@@ -257,6 +257,17 @@ libbitcoin_server_a_SOURCES = \
|
||||
bloom.cpp \
|
||||
cc/eval.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/ponzi.cpp \
|
||||
cc/auction.cpp \
|
||||
cc/betprotocol.cpp \
|
||||
chain.cpp \
|
||||
checkpoints.cpp \
|
||||
@@ -333,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 \
|
||||
|
||||
@@ -1,73 +1,19 @@
|
||||
#!/bin/bash
|
||||
set -eo pipefail
|
||||
|
||||
source pubkey.txt
|
||||
# You can now add delay line to pubkey.txt file
|
||||
|
||||
args=("$@")
|
||||
source pubkey.txt
|
||||
overide_args="$@"
|
||||
seed_ip=`getent hosts zero.kolo.supernet.org | awk '{ print $1 }'`
|
||||
komodo_binary='./komodod'
|
||||
|
||||
if [ -z "$delay" ]; then delay=20; fi
|
||||
|
||||
function komodo_asset ()
|
||||
{
|
||||
if [ $[RANDOM % 10] == 1 ]
|
||||
then
|
||||
gen=" -gen"
|
||||
else
|
||||
gen=""
|
||||
fi
|
||||
./listassetchainparams | while read args; do
|
||||
gen=""
|
||||
if [ $[RANDOM % 10] == 1 ]; then
|
||||
gen=" -gen"
|
||||
fi
|
||||
|
||||
if [ -n "$2" ]
|
||||
then
|
||||
supply=" -ac_supply=$2"
|
||||
else
|
||||
supply=" "
|
||||
fi
|
||||
|
||||
if [ -n "$3" ]
|
||||
then
|
||||
reward=" -ac_reward=$3"
|
||||
else
|
||||
reward=" "
|
||||
fi
|
||||
|
||||
$komodo_binary -ac_name=$1 $gen $supply $reward $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 10000000000
|
||||
komodo_asset EQL 500000000
|
||||
komodo_asset ZILLA 11000000
|
||||
komodo_asset RFOX 1000000000 100000000
|
||||
komodo_asset SEC 1000000000
|
||||
./komodod $gen $args $overide_args -pubkey=$pubkey -addnode=$seed_ip &
|
||||
sleep $delay
|
||||
done
|
||||
|
||||
136
src/assetchains.json
Normal file
136
src/assetchains.json
Normal file
@@ -0,0 +1,136 @@
|
||||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
@@ -1,41 +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
|
||||
komodo_stop SEC
|
||||
./listassetchains | while read chain; do
|
||||
./komodo-cli --ac_name=$chain stop
|
||||
done
|
||||
|
||||
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
|
||||
478
src/cc/CCassetsCore.cpp
Normal file
478
src/cc/CCassetsCore.cpp
Normal file
@@ -0,0 +1,478 @@
|
||||
/******************************************************************************
|
||||
* 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;
|
||||
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,"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*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*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;
|
||||
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);
|
||||
}
|
||||
472
src/cc/CCassetstx.cpp
Normal file
472
src/cc/CCassetstx.cpp
Normal file
@@ -0,0 +1,472 @@
|
||||
/******************************************************************************
|
||||
* 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"
|
||||
|
||||
// need allassets
|
||||
// find asset
|
||||
|
||||
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 )
|
||||
{
|
||||
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("error","cant find assetid"));
|
||||
return(0);
|
||||
}
|
||||
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("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));
|
||||
sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
|
||||
result.push_back(Pair("supply",numstr));
|
||||
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(0);
|
||||
}
|
||||
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(0);
|
||||
}
|
||||
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(0);
|
||||
}
|
||||
|
||||
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(0);
|
||||
}
|
||||
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(0);
|
||||
}
|
||||
|
||||
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(0);
|
||||
}
|
||||
if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
|
||||
{
|
||||
fprintf(stderr,"cant find assetid\n");
|
||||
return(0);
|
||||
}
|
||||
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(0);
|
||||
}
|
||||
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(0);
|
||||
}
|
||||
|
||||
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(0);
|
||||
}
|
||||
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(0);
|
||||
}
|
||||
|
||||
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;
|
||||
if ( askamount < 0 || pricetotal < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
|
||||
return(0);
|
||||
}
|
||||
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(0);
|
||||
}
|
||||
|
||||
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(0);
|
||||
}
|
||||
|
||||
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(0);
|
||||
}
|
||||
|
||||
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(0);
|
||||
}
|
||||
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 )
|
||||
{
|
||||
fprintf(stderr,"negative fillunits %lld\n",(long long)fillunits);
|
||||
return(0);
|
||||
}
|
||||
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));
|
||||
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 fprintf(stderr,"filltx not enough utxos\n");
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
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,uint64_t minbid,char *title,char *description);
|
||||
std::string AuctionBid(uint64_t txfee,uint256 itemhash,uint64_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 "CCponzi.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
|
||||
|
||||
// Ponzi
|
||||
#define FUNCNAME IsPonziInput
|
||||
#define EVALCODE EVAL_PONZI
|
||||
const char *PonziCCaddr = "RUKTbLBeKgHkm3Ss4hKZP3ikuLW1xx7B2x";
|
||||
const char *PonziNormaladdr = "RWSHRbxnJYLvDjpcQ2i8MekgP6h2ctTKaj";
|
||||
char PonziCChexstr[67] = { "039b52d294b413b07f3643c1a28c5467901a76562d8b39a785910ae0a0f3043810" };
|
||||
uint8_t PonziCCpriv[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_PONZI:
|
||||
strcpy(cp->unspendableCCaddr,PonziCCaddr);
|
||||
strcpy(cp->normaladdr,PonziNormaladdr);
|
||||
strcpy(cp->CChexstr,PonziCChexstr);
|
||||
memcpy(cp->CCpriv,PonziCCpriv,32);
|
||||
cp->validate = PonziValidate;
|
||||
cp->ismyvin = IsPonziInput;
|
||||
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;
|
||||
}
|
||||
32
src/cc/CCdice.h
Normal file
32
src/cc/CCdice.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_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 DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks);
|
||||
std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount);
|
||||
UniValue DiceInfo(uint256 diceid);
|
||||
UniValue DiceList();
|
||||
|
||||
#endif
|
||||
30
src/cc/CCfaucet.h
Normal file
30
src/cc/CCfaucet.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_FAUCET_H
|
||||
#define CC_FAUCET_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
#define EVAL_FAUCET 0xe4
|
||||
|
||||
bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
|
||||
// CCcustom
|
||||
std::string FaucetFund(uint64_t txfee,uint64_t funds);
|
||||
std::string FaucetGet(uint64_t txfee);
|
||||
|
||||
#endif
|
||||
82
src/cc/CCinclude.h
Normal file
82
src/cc/CCinclude.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/******************************************************************************
|
||||
* 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>
|
||||
|
||||
|
||||
#define SMALLVAL 0.000000000000001
|
||||
|
||||
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 uint256 zeroid;
|
||||
|
||||
// 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,uint64_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(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);
|
||||
uint64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,uint64_t total,int32_t maxinputs);
|
||||
uint64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout);
|
||||
|
||||
#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,uint64_t numtickets);
|
||||
std::string LottoWinner(uint64_t txfee);
|
||||
|
||||
#endif
|
||||
29
src/cc/CCponzi.h
Normal file
29
src/cc/CCponzi.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_PONZI_H
|
||||
#define CC_PONZI_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
#define EVAL_PONZI 0xe7
|
||||
|
||||
bool PonziValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx);
|
||||
|
||||
std::string PonziBuy(uint64_t txfee,uint64_t amount);
|
||||
std::string PonziClaim(uint64_t txfee);
|
||||
|
||||
#endif
|
||||
33
src/cc/CCrewards.h
Normal file
33
src/cc/CCrewards.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/******************************************************************************
|
||||
* 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
|
||||
|
||||
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
|
||||
235
src/cc/CCtx.cpp
Normal file
235
src/cc/CCtx.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/******************************************************************************
|
||||
* 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,uint64_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,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 ( (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;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_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);
|
||||
}
|
||||
|
||||
uint64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,uint64_t total,int32_t maxinputs)
|
||||
{
|
||||
int32_t vout,j,n = 0; uint64_t nValue,totalinputs = 0; uint256 txid; std::vector<COutput> vecOutputs;
|
||||
#ifdef ENABLE_WALLET
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
assert(pwalletMain != NULL);
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
{
|
||||
if ( out.fSpendable != 0 )
|
||||
{
|
||||
txid = out.tx->GetHash();
|
||||
vout = out.i;
|
||||
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;
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
nValue = out.tx->vout[out.i].nValue;
|
||||
totalinputs += nValue;
|
||||
n++;
|
||||
if ( totalinputs >= total || n >= maxinputs )
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( totalinputs >= total )
|
||||
return(totalinputs);
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
298
src/cc/CCutils.cpp
Normal file
298
src/cc/CCutils.cpp
Normal file
@@ -0,0 +1,298 @@
|
||||
/******************************************************************************
|
||||
* 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,uint64_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 )
|
||||
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 txid,assetid,assetid2,hashBlock; uint8_t funcid; int32_t i,n; uint64_t amount; std::vector<uint8_t> origpubkey;
|
||||
txid = ctx.GetHash();
|
||||
if ( txid == cp->prevtxid )
|
||||
return(true);
|
||||
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 )
|
||||
{
|
||||
cp->prevtxid = txid;
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
int64_t CCduration(uint256 txid)
|
||||
{
|
||||
CTransaction tx; uint256 hashBlock; uint32_t txtime=0; char str[65]; CBlockIndex *pindex; int64_t duration = 0;
|
||||
if ( GetTransaction(txid,tx,hashBlock,false) == 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 )
|
||||
{
|
||||
fprintf(stderr,"CCduration no txtime %u %p for txid %s\n",txtime,pindex,uint256_str(str,txid));
|
||||
return(0);
|
||||
}
|
||||
else if ( (pindex= chainActive.LastTip()) == 0 || pindex->nTime < txtime )
|
||||
{
|
||||
fprintf(stderr,"CCduration backwards timestamps %u %u for txid %s\n",(uint32_t)pindex->nTime,txtime,uint256_str(str,txid));
|
||||
return(0);
|
||||
}
|
||||
duration = (pindex->nTime - txtime);
|
||||
fprintf(stderr,"duration %d (%u - %u)\n",(int32_t)duration,(uint32_t)pindex->nTime,txtime);
|
||||
return(duration);
|
||||
}
|
||||
|
||||
367
src/cc/assets.cpp
Normal file
367
src/cc/assets.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
/******************************************************************************
|
||||
* 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 's': // selloffer
|
||||
case 'e': // exchange
|
||||
//vin.0: normal input
|
||||
//vin.1+: valid CC output for sale
|
||||
//vout.0: vin.1 assetoshis output to CC to unspendable
|
||||
//vout.1: 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]
|
||||
if ( remaining_price == 0 )
|
||||
return eval->Invalid("illegal null remaining_price 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);
|
||||
preventCCvouts = 1;
|
||||
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
|
||||
//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 )
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
203
src/cc/auction.cpp
Normal file
203
src/cc/auction.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
/******************************************************************************
|
||||
* 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
|
||||
|
||||
uint64_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; uint64_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;
|
||||
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
|
||||
|
||||
uint64_t AddAuctionInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
|
||||
{
|
||||
char coinaddr[64]; uint64_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 ( 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,uint64_t amount)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Auctionpk; CScript opret; uint64_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(0);
|
||||
}
|
||||
|
||||
std::string AuctionDeliver(uint64_t txfee,uint256 itemhash,uint256 bidtxid)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Auctionpk; CScript opret; uint64_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(0);
|
||||
}
|
||||
|
||||
std::string AuctionPost(uint64_t txfee,uint256 itemhash,uint64_t minbid,char *title,char *description)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Auctionpk; uint64_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(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <cryptoconditions.h>
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
@@ -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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef BETPROTOCOL_H
|
||||
#define BETPROTOCOL_H
|
||||
|
||||
|
||||
512
src/cc/dice.cpp
Normal file
512
src/cc/dice.cpp
Normal file
@@ -0,0 +1,512 @@
|
||||
/******************************************************************************
|
||||
* 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 "CCdice.h"
|
||||
|
||||
/*
|
||||
in order to implement a dice game, we need a source of entropy, reasonably fast completion time and a way to manage the utxos.
|
||||
|
||||
1. CC vout locks "house" funds with hash(entropy) + half of shared secret
|
||||
2. bettor submits bet, with entropy, odds, houseid and sends combined amount into another CC vout.
|
||||
3. house account sends funds to winner with proof of entropy
|
||||
4. if timeout, bettor wins funds
|
||||
|
||||
2. and 3. can be done in mempool
|
||||
*/
|
||||
|
||||
uint64_t DiceCalc(uint64_t amount,uint256 txid,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks)
|
||||
{
|
||||
/*uint64_t duration,reward = 0;
|
||||
if ( (duration= CCduration(txid)) < minseconds )
|
||||
{
|
||||
return(0);
|
||||
//duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24);
|
||||
} else if ( duration > maxseconds )
|
||||
maxseconds = duration;
|
||||
reward = (((amount * APR) / COIN) * duration) / (365*24*3600LL * 100);
|
||||
fprintf(stderr,"amount %.8f %.8f %llu -> duration.%llu reward %.8f\n",(double)amount/COIN,((double)amount * APR)/COIN,(long long)((amount * APR) / (COIN * 365*24*3600)),(long long)duration,(double)reward/COIN);
|
||||
return(reward);*/
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodeDiceFundingOpRet(uint8_t funcid,uint64_t sbits,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_DICE;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << minbet << maxbet << maxodds << forfeitblocks);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &forfeitblocks)
|
||||
{
|
||||
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 >> minbet; ss >> maxbet; ss >> maxodds; ss >> forfeitblocks) != 0 )
|
||||
{
|
||||
if ( e == EVAL_DICE && f == 'F' )
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_DICE;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid; int64_t minbet,maxbet,maxodds,forfeitblocks;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
if ( vopret.size() > 2 )
|
||||
{
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( script[0] == EVAL_DICE )
|
||||
{
|
||||
if ( script[1] == 'F' )
|
||||
{
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> forfeitblocks) != 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_DICE && (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_DICE\n",script[0]);
|
||||
} else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
|
||||
return(0);
|
||||
}
|
||||
|
||||
uint64_t IsDicevout(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 DiceExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx,uint64_t txfee)
|
||||
{
|
||||
static uint256 zerohash;
|
||||
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_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 dice from mempool");
|
||||
if ( (assetoshis= IsDicevout(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= IsDicevout(cp,tx,i)) != 0 )
|
||||
outputs += assetoshis;
|
||||
}
|
||||
if ( inputs != outputs+txfee )
|
||||
{
|
||||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
|
||||
return eval->Invalid("mismatched inputs != outputs + txfee");
|
||||
}
|
||||
else return(true);
|
||||
}
|
||||
|
||||
bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
|
||||
{
|
||||
uint256 txid,fundingtxid,hashBlock; int64_t minbet,maxbet,maxodds,forfeitblocks; uint64_t sbits,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= DecodeDiceOpRet(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 && DecodeDiceFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) != 'F' )
|
||||
return eval->Invalid("fundingTx not valid");
|
||||
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 DiceValidate 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 DiceValidate 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 DiceValidate 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
|
||||
//vout.1: normal output to unlock address
|
||||
//vout.n-1: opreturn 'U' sbits fundingtxid
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
|
||||
return eval->Invalid("unexpected normal vin for unlock");
|
||||
}
|
||||
if ( DiceExactAmounts(cp,eval,tx,txfee+tx.vout[1].nValue) == 0 )
|
||||
return false;
|
||||
else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("always should find vin.0, but didnt");
|
||||
else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("lock tx vout.0 is normal output");
|
||||
else if ( tx.vout.size() < 3 )
|
||||
return eval->Invalid("unlock tx not enough 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 = DiceCalc(amount,tx.vin[0].prevout.hash,minbet,maxbet,maxodds,forfeitblocks);
|
||||
if ( tx.vout[1].nValue > amount+reward )
|
||||
return eval->Invalid("unlock tx vout.1 isnt amount+reward");
|
||||
preventCCvouts = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// 'L' vs 'F' and 'A'
|
||||
uint64_t AddDiceInputs(CScript &scriptPubKey,int32_t fundsflag,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
|
||||
{
|
||||
char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
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;
|
||||
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 )
|
||||
{
|
||||
if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"fundsflag.%d (%c) %.8f %.8f\n",fundsflag,funcid,(double)tx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN);
|
||||
if ( fundsflag != 0 && funcid != 'F' && funcid != 'A' && funcid != 'U' )
|
||||
continue;
|
||||
else if ( fundsflag == 0 && (funcid != 'L' || tx.vout.size() < 4) )
|
||||
continue;
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
{
|
||||
if ( fundsflag == 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");
|
||||
}
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
uint64_t DicePlanFunds(uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid)
|
||||
{
|
||||
char coinaddr[64]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout; 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 ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
|
||||
{
|
||||
if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
|
||||
{
|
||||
if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 0 )
|
||||
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 DicePlanExists(struct CCcontract_info *cp,uint64_t refsbits,CPubKey dicepk,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &forfeitblocks)
|
||||
{
|
||||
char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
|
||||
GetCCaddress(cp,CCaddr,dicepk);
|
||||
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 )
|
||||
{
|
||||
if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) == 'F' )
|
||||
{
|
||||
if ( sbits == refsbits )
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
UniValue DiceInfo(uint256 diceid)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; int64_t minbet,maxbet,maxodds,forfeitblocks; uint64_t sbits; char str[67],numstr[65];
|
||||
if ( GetTransaction(diceid,vintx,hashBlock,false) == 0 )
|
||||
{
|
||||
fprintf(stderr,"cant find fundingtxid\n");
|
||||
result.push_back(Pair("error","cant find fundingtxid"));
|
||||
return(result);
|
||||
}
|
||||
if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) == 0 )
|
||||
{
|
||||
fprintf(stderr,"fundingtxid isnt dice creation txid\n");
|
||||
result.push_back(Pair("error","fundingtxid isnt dice creation txid"));
|
||||
return(result);
|
||||
}
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("fundingtxid",uint256_str(str,diceid)));
|
||||
unstringbits(str,sbits);
|
||||
result.push_back(Pair("name",str));
|
||||
result.push_back(Pair("sbits",sbits));
|
||||
sprintf(numstr,"%.8f",(double)minbet/COIN);
|
||||
result.push_back(Pair("minbet",numstr));
|
||||
sprintf(numstr,"%.8f",(double)maxbet/COIN);
|
||||
result.push_back(Pair("maxbet",numstr));
|
||||
result.push_back(Pair("maxodds",maxodds));
|
||||
result.push_back(Pair("forfeitblocks",forfeitblocks));
|
||||
sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
|
||||
result.push_back(Pair("funding",numstr));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue DiceList()
|
||||
{
|
||||
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits; int64_t minbet,maxbet,maxodds,forfeitblocks; char str[65];
|
||||
cp = CCinit(&C,EVAL_DICE);
|
||||
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 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) != 0 )
|
||||
{
|
||||
result.push_back(uint256_str(str,txid));
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t a,b,c,d; struct CCcontract_info *cp,C;
|
||||
if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || forfeitblocks < 0 || forfeitblocks > 1440 )
|
||||
{
|
||||
fprintf(stderr,"negative parameter error\n");
|
||||
return(0);
|
||||
}
|
||||
cp = CCinit(&C,EVAL_DICE);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
dicepk = GetUnspendable(cp,0);
|
||||
sbits = stringbits(planstr);
|
||||
if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) != 0 )
|
||||
{
|
||||
fprintf(stderr,"Dice plan (%s) already exists\n",planstr);
|
||||
return(0);
|
||||
}
|
||||
if ( AddNormalinputs(mtx,mypk,funds+2*txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,dicepk));
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(dicepk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,minbet,maxbet,maxodds,forfeitblocks)));
|
||||
}
|
||||
fprintf(stderr,"cant find enough inputs\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t a,b,c,d; struct CCcontract_info *cp,C;
|
||||
if ( amount < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative parameter error\n");
|
||||
return(0);
|
||||
}
|
||||
cp = CCinit(&C,EVAL_DICE);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
dicepk = GetUnspendable(cp,0);
|
||||
sbits = stringbits(planstr);
|
||||
if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) == 0 )
|
||||
{
|
||||
fprintf(stderr,"Dice plan %s doesnt exist\n",planstr);
|
||||
return(0);
|
||||
}
|
||||
sbits = stringbits(planstr);
|
||||
if ( AddNormalinputs(mtx,mypk,amount+txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('A',sbits,fundingtxid)));
|
||||
} else fprintf(stderr,"cant find enough inputs\n");
|
||||
fprintf(stderr,"cant find fundingtxid\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t funding,minbet,maxbet,maxodds,forfeitblocks; struct CCcontract_info *cp,C;
|
||||
if ( bet < 0 || odds < 1 )
|
||||
{
|
||||
fprintf(stderr,"negative parameter error\n");
|
||||
return(0);
|
||||
}
|
||||
cp = CCinit(&C,EVAL_DICE);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
dicepk = GetUnspendable(cp,0);
|
||||
sbits = stringbits(planstr);
|
||||
if ( DicePlanExists(cp,sbits,dicepk,minbet,maxbet,maxodds,forfeitblocks) == 0 )
|
||||
{
|
||||
fprintf(stderr,"Dice plan %s doesnt exist\n",planstr);
|
||||
return(0);
|
||||
}
|
||||
if ( bet < minbet )
|
||||
{
|
||||
fprintf(stderr,"Dice plan %s bet %.8f < minbet %.8f\n",planstr,(double)bet/COIN,(double)minbet/COIN);
|
||||
return(0);
|
||||
}
|
||||
if ( (funding= DicePlanFunds(sbits,cp,dicepk,fundingtxid)) >= bet*odds+txfee )
|
||||
{
|
||||
if ( AddNormalinputs(mtx,mypk,bet+2*txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,dicepk));
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('L',sbits,fundingtxid)));
|
||||
} else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)bet/COIN);
|
||||
}
|
||||
fprintf(stderr,"cant find dice inputs\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
std::string DiceUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid)
|
||||
{
|
||||
CMutableTransaction mtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,dicepk; CScript opret,scriptPubKey,ignore; uint256 hashBlock; uint64_t funding,sbits,reward=0,amount=0,inputs,CCchange=0; int64_t minbet,maxbet,maxodds,forfeitblocks; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_DICE);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
dicepk = GetUnspendable(cp,0);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
sbits = stringbits(planstr);
|
||||
if ( DicePlanExists(cp,sbits,dicepk,minbet,maxbet,maxodds,forfeitblocks) == 0 )
|
||||
{
|
||||
fprintf(stderr,"Dice plan %s doesnt exist\n",planstr);
|
||||
return(0);
|
||||
}
|
||||
// need to deal with finding the right utxos
|
||||
if ( locktxid == zeroid )
|
||||
amount = AddDiceInputs(scriptPubKey,0,cp,mtx,dicepk,(1LL << 30),1);
|
||||
else
|
||||
{
|
||||
GetCCaddress(cp,coinaddr,dicepk);
|
||||
if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 )
|
||||
{
|
||||
fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr);
|
||||
return(0);
|
||||
}
|
||||
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);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if ( amount > 0 && (reward= DiceCalc(amount,mtx.vin[0].prevout.hash,minbet,maxbet,maxodds,forfeitblocks)) > txfee && scriptPubKey.size() > 0 )
|
||||
{
|
||||
if ( (inputs= AddDiceInputs(ignore,1,cp,mtx,dicepk,reward+txfee,30)) > 0 )
|
||||
{
|
||||
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,dicepk));
|
||||
mtx.vout.push_back(CTxOut(amount+reward,scriptPubKey));
|
||||
return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,EncodeDiceOpRet('U',sbits,fundingtxid)));
|
||||
}
|
||||
fprintf(stderr,"cant find enough dice inputs\n");
|
||||
}
|
||||
fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -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 <assert.h>
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
@@ -6,6 +21,7 @@
|
||||
#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"
|
||||
@@ -13,13 +29,13 @@
|
||||
|
||||
|
||||
Eval* EVAL_TEST = 0;
|
||||
|
||||
struct CCcontract_info CCinfos[0x100];
|
||||
|
||||
bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
|
||||
{
|
||||
EvalRef eval;
|
||||
|
||||
bool out = eval->Dispatch(cond, tx, nIn);
|
||||
//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;
|
||||
@@ -40,21 +56,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];
|
||||
cp = &CCinfos[(int32_t)ecode];
|
||||
if ( cp->didinit == 0 )
|
||||
{
|
||||
CCinit(cp,ecode);
|
||||
cp->didinit = 1;
|
||||
}
|
||||
std::vector<uint8_t> vparams(cond->code+1, cond->code+cond->codeLength);
|
||||
|
||||
if (ecode == EVAL_IMPORTPAYOUT) {
|
||||
return ImportPayout(vparams, txTo, nIn);
|
||||
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;
|
||||
}
|
||||
|
||||
if (ecode == EVAL_IMPORTCOIN) {
|
||||
return ImportCoin(vparams, txTo, nIn);
|
||||
}
|
||||
|
||||
return Invalid("invalid-code");
|
||||
return Invalid("invalid-code, dont forget to add EVAL_NEWCC to Eval::Dispatch");
|
||||
}
|
||||
|
||||
|
||||
@@ -67,8 +95,11 @@ 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);
|
||||
bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock);
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +119,6 @@ unsigned int Eval::GetCurrentHeight() const
|
||||
return chainActive.Height();
|
||||
}
|
||||
|
||||
|
||||
bool Eval::GetBlock(uint256 hash, CBlockIndex& blockIdx) const
|
||||
{
|
||||
auto r = mapBlockIndex.find(hash);
|
||||
@@ -100,7 +130,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);
|
||||
|
||||
|
||||
|
||||
@@ -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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef CC_EVAL_H
|
||||
#define CC_EVAL_H
|
||||
|
||||
@@ -10,6 +25,7 @@
|
||||
#include "consensus/validation.h"
|
||||
#include "primitives/transaction.h"
|
||||
|
||||
#define KOMODO_FIRSTFUNGIBLEID 100
|
||||
|
||||
/*
|
||||
* Eval codes
|
||||
@@ -23,7 +39,14 @@
|
||||
*/
|
||||
#define FOREACH_EVAL(EVAL) \
|
||||
EVAL(EVAL_IMPORTPAYOUT, 0xe1) \
|
||||
EVAL(EVAL_IMPORTCOIN, 0xe2)
|
||||
EVAL(EVAL_IMPORTCOIN, 0xe2) \
|
||||
EVAL(EVAL_ASSETS, 0xe3) \
|
||||
EVAL(EVAL_FAUCET, 0xe4) \
|
||||
EVAL(EVAL_REWARDS, 0xe5) \
|
||||
EVAL(EVAL_DICE, 0xe6) \
|
||||
EVAL(EVAL_PONZI, 0xe7) \
|
||||
EVAL(EVAL_AUCTION, 0xe8) \
|
||||
EVAL(EVAL_LOTTO, 0xe9)
|
||||
|
||||
|
||||
typedef uint8_t EvalCode;
|
||||
@@ -250,6 +273,8 @@ 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 */
|
||||
|
||||
190
src/cc/faucet.cpp
Normal file
190
src/cc/faucet.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
/******************************************************************************
|
||||
* 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
|
||||
|
||||
uint64_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; uint64_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+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 FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
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,"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;
|
||||
if ( tx.vout[i].nValue != COIN )
|
||||
return eval->Invalid("invalid faucet output");
|
||||
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
|
||||
|
||||
uint64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
|
||||
{
|
||||
char coinaddr[64]; uint64_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 ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( (nValue= IsFaucetvout(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 FaucetGet(uint64_t txfee)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,faucetpk; CScript opret; uint64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C;
|
||||
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));
|
||||
return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret));
|
||||
} else fprintf(stderr,"cant find faucet inputs\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
std::string FaucetFund(uint64_t txfee,uint64_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(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 "cc/eval.h"
|
||||
#include "cc/utils.h"
|
||||
#include "importcoin.h"
|
||||
@@ -39,6 +54,9 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params, const CTransaction &imp
|
||||
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[0].nValue;
|
||||
|
||||
183
src/cc/lotto.cpp
Normal file
183
src/cc/lotto.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/******************************************************************************
|
||||
* 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
|
||||
|
||||
uint64_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; uint64_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;
|
||||
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
|
||||
|
||||
uint64_t AddLottoInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
|
||||
{
|
||||
char coinaddr[64]; uint64_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 ( 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,uint64_t numtickets)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Lottopk; CScript opret; uint64_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(0);
|
||||
}
|
||||
|
||||
std::string LottoWinner(uint64_t txfee)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,Lottopk; uint64_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(0);
|
||||
}
|
||||
|
||||
|
||||
183
src/cc/ponzi.cpp
Normal file
183
src/cc/ponzi.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/******************************************************************************
|
||||
* 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 "CCponzi.h"
|
||||
#include "../txmempool.h"
|
||||
|
||||
/*
|
||||
*/
|
||||
|
||||
// start of consensus code
|
||||
|
||||
uint64_t IsPonzivout(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 PonziExactAmounts(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; uint64_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 ponzi from mempool");
|
||||
if ( (assetoshis= IsPonzivout(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= IsPonzivout(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 PonziValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
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,"ponziget invalid vini\n");
|
||||
return eval->Invalid("illegal normal vini");
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"check amounts\n");
|
||||
if ( PonziExactAmounts(cp,eval,tx,1,10000) == false )
|
||||
{
|
||||
fprintf(stderr,"ponziget invalid amount\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
preventCCvouts = 1;
|
||||
if ( IsPonzivout(cp,tx,0) != 0 )
|
||||
{
|
||||
preventCCvouts++;
|
||||
i = 1;
|
||||
} else i = 0;
|
||||
if ( tx.vout[i].nValue != COIN )
|
||||
return eval->Invalid("invalid ponzi output");
|
||||
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
|
||||
if ( retval != 0 )
|
||||
fprintf(stderr,"ponziget validated\n");
|
||||
else fprintf(stderr,"ponziget invalid\n");
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of consensus code
|
||||
|
||||
// helper functions for rpc calls in rpcwallet.cpp
|
||||
|
||||
uint64_t AddPonziInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
|
||||
{
|
||||
char coinaddr[64]; uint64_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 ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( (nValue= IsPonzivout(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 PonziBuy(uint64_t txfee,uint64_t amount)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,ponzipk; CScript opret; uint64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_PONZI);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
ponzipk = GetUnspendable(cp,0);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( (inputs= AddPonziInputs(cp,mtx,ponzipk,nValue+txfee,60)) > 0 )
|
||||
{
|
||||
if ( inputs > nValue )
|
||||
CCchange = (inputs - nValue - txfee);
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_PONZI,CCchange,ponzipk));
|
||||
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 ponzi inputs\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
std::string PonziClaim(uint64_t txfee)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,ponzipk; uint64_t funds = 0; CScript opret; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_PONZI);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
ponzipk = GetUnspendable(cp,0);
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,64) > 0 )
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_PONZI,funds,ponzipk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
553
src/cc/rewards.cpp
Normal file
553
src/cc/rewards.cpp
Normal file
@@ -0,0 +1,553 @@
|
||||
/******************************************************************************
|
||||
* 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"
|
||||
|
||||
/*
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
uint64_t RewardsCalc(uint64_t amount,uint256 txid,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit)
|
||||
{
|
||||
uint64_t duration,reward = 0;
|
||||
fprintf(stderr,"minseconds %llu maxseconds %llu\n",(long long)minseconds,(long long)maxseconds);
|
||||
if ( (duration= CCduration(txid)) < minseconds )
|
||||
{
|
||||
return(0);
|
||||
//duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24);
|
||||
} else if ( duration > maxseconds )
|
||||
duration = maxseconds;
|
||||
reward = (((amount * APR) / COIN) * duration) / (365*24*3600LL * 100);
|
||||
fprintf(stderr,"amount %.8f %.8f %llu -> duration.%llu reward %.8f\n",(double)amount/COIN,((double)amount * APR)/COIN,(long long)((amount * APR) / (COIN * 365*24*3600)),(long long)duration,(double)reward/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);
|
||||
}
|
||||
|
||||
uint64_t IsRewardsvout(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 RewardsExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx,uint64_t txfee)
|
||||
{
|
||||
static uint256 zerohash;
|
||||
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_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)) != 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)) != 0 )
|
||||
outputs += assetoshis;
|
||||
}
|
||||
if ( inputs != outputs+txfee )
|
||||
{
|
||||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
|
||||
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; uint64_t 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");
|
||||
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
|
||||
//vout.1: normal output to unlock address
|
||||
//vout.n-1: opreturn 'U' sbits fundingtxid
|
||||
for (i=0; i<numvins; i++)
|
||||
{
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
|
||||
return eval->Invalid("unexpected normal vin for unlock");
|
||||
}
|
||||
if ( RewardsExactAmounts(cp,eval,tx,txfee+tx.vout[1].nValue) == 0 )
|
||||
return false;
|
||||
else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("always should find vin.0, but didnt");
|
||||
else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("lock tx vout.0 is normal output");
|
||||
else if ( tx.vout.size() < 3 )
|
||||
return eval->Invalid("unlock tx not enough 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 ( tx.vout[1].nValue > amount+reward )
|
||||
return eval->Invalid("unlock tx vout.1 isnt amount+reward");
|
||||
preventCCvouts = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// 'L' vs 'F' and 'A'
|
||||
uint64_t AddRewardsInputs(CScript &scriptPubKey,int32_t fundsflag,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
|
||||
{
|
||||
char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
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;
|
||||
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 )
|
||||
{
|
||||
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"fundsflag.%d (%c) %.8f %.8f\n",fundsflag,funcid,(double)tx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN);
|
||||
if ( fundsflag != 0 && funcid != 'F' && funcid != 'A' && funcid != 'U' )
|
||||
continue;
|
||||
else if ( fundsflag == 0 && (funcid != 'L' || tx.vout.size() < 4) )
|
||||
continue;
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
{
|
||||
if ( fundsflag == 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");
|
||||
}
|
||||
}
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
uint64_t RewardsPlanFunds(uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid)
|
||||
{
|
||||
char coinaddr[64]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout; 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 ( 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)) != 0 )
|
||||
{
|
||||
if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
|
||||
{
|
||||
if ( refsbits == sbits && (nValue= IsRewardsvout(cp,tx,vout)) > 0 )
|
||||
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 APR,minseconds,maxseconds,mindeposit,sbits; char str[67],numstr[65];
|
||||
if ( GetTransaction(rewardsid,vintx,hashBlock,false) == 0 )
|
||||
{
|
||||
fprintf(stderr,"cant find fundingtxid\n");
|
||||
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("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));
|
||||
sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
|
||||
result.push_back(Pair("funding",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 < 0 || mindeposit < 0 || minseconds < 0 || maxseconds < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative parameter error\n");
|
||||
return(0);
|
||||
}
|
||||
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(0);
|
||||
}
|
||||
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(0);
|
||||
}
|
||||
|
||||
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(0);
|
||||
}
|
||||
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 doesnt exist\n",planstr);
|
||||
return(0);
|
||||
}
|
||||
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 fprintf(stderr,"cant find enough inputs\n");
|
||||
fprintf(stderr,"cant find fundingtxid\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
std::string RewardsLock(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t deposit)
|
||||
{
|
||||
CMutableTransaction mtx; CPubKey mypk,rewardspk; CScript opret; uint64_t sbits,funding,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C;
|
||||
if ( deposit < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative parameter error\n");
|
||||
return(0);
|
||||
}
|
||||
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 )
|
||||
{
|
||||
fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
|
||||
return(0);
|
||||
}
|
||||
if ( deposit < mindeposit )
|
||||
{
|
||||
fprintf(stderr,"Rewards plan %s deposit %.8f < mindeposit %.8f\n",planstr,(double)deposit/COIN,(double)mindeposit/COIN);
|
||||
return(0);
|
||||
}
|
||||
if ( (funding= RewardsPlanFunds(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 fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)deposit/COIN);
|
||||
}
|
||||
fprintf(stderr,"cant find rewards inputs\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid)
|
||||
{
|
||||
CMutableTransaction mtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,rewardspk; CScript opret,scriptPubKey,ignore; uint256 hashBlock; uint64_t funding,sbits,reward=0,amount=0,inputs,CCchange=0,APR,minseconds,maxseconds,mindeposit; 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 ( RewardsPlanExists(cp,sbits,rewardspk,APR,minseconds,maxseconds,mindeposit) == 0 )
|
||||
{
|
||||
fprintf(stderr,"Rewards plan %s doesnt exist\n",planstr);
|
||||
return(0);
|
||||
}
|
||||
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,0,cp,mtx,rewardspk,(1LL << 30),1);
|
||||
else
|
||||
{
|
||||
GetCCaddress(cp,coinaddr,rewardspk);
|
||||
if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 )
|
||||
{
|
||||
fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr);
|
||||
return(0);
|
||||
}
|
||||
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);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if ( amount > 0 && (reward= RewardsCalc(amount,mtx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit)) > txfee && scriptPubKey.size() > 0 )
|
||||
{
|
||||
if ( (inputs= AddRewardsInputs(ignore,1,cp,mtx,rewardspk,reward+txfee,30)) > 0 )
|
||||
{
|
||||
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)));
|
||||
}
|
||||
fprintf(stderr,"cant find enough rewards inputs\n");
|
||||
}
|
||||
fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -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. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef CC_UTILS_H
|
||||
#define CC_UTILS_H
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ uint256 CalculateProofRoot(const char* symbol, uint32_t targetCCid, int kmdHeigh
|
||||
* > scan backwards >
|
||||
*/
|
||||
|
||||
if (targetCCid <= 1)
|
||||
if (targetCCid < 2)
|
||||
return uint256();
|
||||
|
||||
if (kmdHeight < 0 || kmdHeight > chainActive.Height())
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 "cryptoconditions.h"
|
||||
#include "internal.h"
|
||||
#include <cJSON.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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
42
src/fiat-cli
42
src/fiat-cli
@@ -1,36 +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
|
||||
echo zilla; fiat/zilla $1 $2 $3 $4
|
||||
echo vrsc; fiat/vrsc $1 $2 $3 $4
|
||||
echo rfox; fiat/rfox $1 $2 $3 $4
|
||||
echo sec; fiat/sec $1 $2 $3 $4
|
||||
|
||||
args="$@"
|
||||
|
||||
./listassetchains | while read chain; do
|
||||
echo $chain
|
||||
./komodo-cli --ac_name=$chain $args
|
||||
done
|
||||
|
||||
@@ -1076,11 +1076,11 @@ int32_t komodo_isrealtime(int32_t *kmdheightp)
|
||||
|
||||
int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t cmptime,int32_t dispflag)
|
||||
{
|
||||
if ( KOMODO_REWIND == 0 && (ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED != 0) && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
|
||||
if ( KOMODO_REWIND == 0 && ASSETCHAINS_SYMBOL[0] == 0 && (int64_t)tx.nLockTime >= LOCKTIME_THRESHOLD ) //1473793441 )
|
||||
{
|
||||
if ( txheight > 246748 || ASSETCHAINS_STAKED != 0 )
|
||||
if ( txheight > 246748 )
|
||||
{
|
||||
if ( txheight < 247205 && ASSETCHAINS_STAKED == 0 )
|
||||
if ( txheight < 247205 )
|
||||
cmptime -= 16000;
|
||||
if ( (int64_t)tx.nLockTime < cmptime-KOMODO_MAXMEMPOOLTIME )
|
||||
{
|
||||
@@ -1198,7 +1198,7 @@ uint32_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256
|
||||
|
||||
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,winner = 0 ; uint64_t value,coinage;
|
||||
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 )
|
||||
{
|
||||
@@ -1221,14 +1221,17 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh
|
||||
ratio = (mindiff / bnTarget);
|
||||
if ( (minage= nHeight*3) > 6000 ) // about 100 blocks
|
||||
minage = 6000;
|
||||
vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
|
||||
komodo_segids(hashbuf,nHeight-101,100);
|
||||
segid32 = komodo_stakehash(&hash,address,hashbuf,txid,vout);
|
||||
segid = ((nHeight + segid32) & 0x3f);
|
||||
/*vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address));
|
||||
segid = ((nHeight + addrhash.uints[0]) & 0x3f);
|
||||
komodo_segids(hashbuf,nHeight-101,100);
|
||||
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 *)&hash,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));
|
||||
for (iter=0; iter<180; iter++)
|
||||
vcalc_sha256(0,(uint8_t *)&hash,hashbuf,100 + (int32_t)sizeof(uint256)*2 + sizeof(vout));*/
|
||||
for (iter=0; iter<600; iter++)
|
||||
{
|
||||
if ( blocktime+iter+segid*2 < txtime+minage )
|
||||
continue;
|
||||
@@ -1243,12 +1246,14 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh
|
||||
if ( iter > 0 )
|
||||
diff += segid*2;
|
||||
coinage = (value * diff);
|
||||
if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 )
|
||||
coinage *= ((blocktime+iter+segid*2) - (prevtime+60));
|
||||
if ( blocktime+iter+segid*2 > prevtime+480 )
|
||||
coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
|
||||
//if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 )
|
||||
// coinage *= ((blocktime+iter+segid*2) - (prevtime+60));
|
||||
coinage256 = arith_uint256(coinage+1);
|
||||
hashval = ratio * (UintToArith256(hash) / coinage256);
|
||||
if ( nHeight >= 900 && nHeight < 916 )
|
||||
hashval = (hashval / coinage256);
|
||||
//if ( nHeight >= 900 && nHeight < 916 )
|
||||
// hashval = (hashval / coinage256);
|
||||
if ( hashval <= bnTarget )
|
||||
{
|
||||
winner = 1;
|
||||
@@ -1288,6 +1293,7 @@ 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)
|
||||
{
|
||||
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 || (ASSETCHAINS_STAKED == 100 && height <= 100) )
|
||||
@@ -1352,9 +1358,13 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he
|
||||
if ( ave > target )
|
||||
ave = target;
|
||||
} else ave = 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 ( oldflag != 0 )
|
||||
bnTarget = (ave * arith_uint256(percPoS * percPoS)) / arith_uint256(goalperc * goalperc * goalperc);
|
||||
else bnTarget = (ave / arith_uint256(goalperc * goalperc * goalperc)) * arith_uint256(percPoS * percPoS);
|
||||
if ( ASSETCHAINS_STAKED < 100 )
|
||||
{
|
||||
for (i=31; i>=24; i--)
|
||||
@@ -1370,7 +1380,12 @@ 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(percPoS * percPoS * percPoS)) / arith_uint256(goalperc * 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
|
||||
@@ -1476,11 +1491,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 )
|
||||
@@ -1530,10 +1547,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 )
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@ struct komodo_state KOMODO_STATES[34];
|
||||
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;
|
||||
int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,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;
|
||||
|
||||
|
||||
@@ -1605,8 +1605,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);
|
||||
|
||||
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'])
|
||||
142
src/main.cpp
142
src/main.cpp
@@ -56,7 +56,7 @@ using namespace std;
|
||||
|
||||
CCriticalSection cs_main;
|
||||
extern uint8_t NOTARY_PUBKEY33[33];
|
||||
extern int32_t KOMODO_LOADINGBLOCKS,KOMODO_LONGESTCHAIN;
|
||||
extern int32_t KOMODO_LOADINGBLOCKS,KOMODO_LONGESTCHAIN,KOMODO_INSYNC;
|
||||
int32_t KOMODO_NEWBLOCKS;
|
||||
int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block);
|
||||
void komodo_broadcast(CBlock *pblock,int32_t limit);
|
||||
@@ -588,13 +588,22 @@ CBlockTreeDB *pblocktree = NULL;
|
||||
#define KOMODO_ZCASH
|
||||
#include "komodo.h"
|
||||
|
||||
int64_t komodo_snapshot()
|
||||
UniValue komodo_snapshot(int top)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
int64_t total = -1;
|
||||
if ( pblocktree != 0 )
|
||||
total = pblocktree->Snapshot();
|
||||
else fprintf(stderr,"null pblocktree start with -addressindex=true\n");
|
||||
return(total);
|
||||
UniValue result(UniValue::VOBJ);
|
||||
|
||||
if (fAddressIndex) {
|
||||
if ( pblocktree != 0 ) {
|
||||
result = pblocktree->Snapshot(top);
|
||||
} else {
|
||||
fprintf(stderr,"null pblocktree start with -addressindex=true\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"getsnapshot requires -addressindex=true\n");
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -739,7 +748,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason, const int nHeight)
|
||||
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
|
||||
reason = "bare-multisig";
|
||||
return false;
|
||||
} else if (txout.IsDust(::minRelayTxFee)) {
|
||||
} else if (txout.scriptPubKey.IsPayToCryptoCondition() == 0 && txout.IsDust(::minRelayTxFee)) {
|
||||
reason = "dust";
|
||||
return false;
|
||||
}
|
||||
@@ -1356,7 +1365,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
// do we already have it?
|
||||
if (view.HaveCoins(hash))
|
||||
{
|
||||
fprintf(stderr,"view.HaveCoins(hash) error\n");
|
||||
//fprintf(stderr,"view.HaveCoins(hash) error\n");
|
||||
return state.Invalid(false, REJECT_DUPLICATE, "already have coins");
|
||||
}
|
||||
|
||||
@@ -1594,6 +1603,47 @@ bool GetAddressUnspent(uint160 addressHash, int type,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock)
|
||||
{
|
||||
// need a GetTransaction without lock so the validation code for assets can run without deadlock
|
||||
{
|
||||
//fprintf(stderr,"check mempool\n");
|
||||
if (mempool.lookup(hash, txOut))
|
||||
{
|
||||
//fprintf(stderr,"found in mempool\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"check disk\n");
|
||||
|
||||
if (fTxIndex) {
|
||||
CDiskTxPos postx;
|
||||
//fprintf(stderr,"ReadTxIndex\n");
|
||||
if (pblocktree->ReadTxIndex(hash, postx)) {
|
||||
//fprintf(stderr,"OpenBlockFile\n");
|
||||
CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
|
||||
if (file.IsNull())
|
||||
return error("%s: OpenBlockFile failed", __func__);
|
||||
CBlockHeader header;
|
||||
//fprintf(stderr,"seek and read\n");
|
||||
try {
|
||||
file >> header;
|
||||
fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
|
||||
file >> txOut;
|
||||
} catch (const std::exception& e) {
|
||||
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
|
||||
}
|
||||
hashBlock = header.GetHash();
|
||||
if (txOut.GetHash() != hash)
|
||||
return error("%s: txid mismatch", __func__);
|
||||
//fprintf(stderr,"found on disk\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//fprintf(stderr,"not found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */
|
||||
bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow)
|
||||
{
|
||||
@@ -2466,6 +2516,16 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
// undo unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, Hash160(hashBytes), hash, k), CAddressUnspentValue()));
|
||||
|
||||
}
|
||||
else if (out.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin(), out.scriptPubKey.end());
|
||||
|
||||
// undo receiving activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(1, Hash160(hashBytes), pindex->nHeight, i, hash, k, false), out.nValue));
|
||||
|
||||
// undo unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, Hash160(hashBytes), hash, k), CAddressUnspentValue()));
|
||||
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
@@ -2551,6 +2611,16 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
||||
// restore unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, Hash160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight)));
|
||||
|
||||
}
|
||||
else if (prevout.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin(), prevout.scriptPubKey.end());
|
||||
|
||||
// undo spending activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(1, Hash160(hashBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1));
|
||||
|
||||
// restore unspent index
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, Hash160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight)));
|
||||
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
@@ -2755,6 +2825,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
|
||||
CBlockUndo blockundo;
|
||||
|
||||
if ( ASSETCHAINS_CC != 0 )
|
||||
{
|
||||
if ( scriptcheckqueue.IsIdle() == 0 )
|
||||
{
|
||||
fprintf(stderr,"scriptcheckqueue isnt idle\n");
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
CCheckQueueControl<CScriptCheck> control(fExpensiveChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
|
||||
|
||||
int64_t nTimeStart = GetTimeMicros();
|
||||
@@ -2834,6 +2912,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
hashBytes = Hash160(vector <unsigned char>(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34));
|
||||
addressType = 1;
|
||||
}
|
||||
else if (prevout.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
hashBytes = Hash160(vector <unsigned char>(prevout.scriptPubKey.begin(), prevout.scriptPubKey.end()));
|
||||
addressType = 1;
|
||||
}
|
||||
else {
|
||||
hashBytes.SetNull();
|
||||
addressType = 0;
|
||||
@@ -2910,6 +2992,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
// record unspent output
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, Hash160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
|
||||
|
||||
}
|
||||
else if (out.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin(), out.scriptPubKey.end());
|
||||
|
||||
// record receiving activity
|
||||
addressIndex.push_back(make_pair(CAddressIndexKey(1, Hash160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
|
||||
|
||||
// record unspent output
|
||||
addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, Hash160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight)));
|
||||
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
@@ -3387,7 +3479,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
|
||||
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
|
||||
LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
|
||||
LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001);
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
if ( KOMODO_LONGESTCHAIN != 0 && pindexNew->nHeight >= KOMODO_LONGESTCHAIN )
|
||||
KOMODO_INSYNC = 1;
|
||||
else KOMODO_INSYNC = 0;
|
||||
//fprintf(stderr,"connect.%d insync.%d\n",(int32_t)pindexNew->nHeight,KOMODO_INSYNC);
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && KOMODO_INSYNC != 0 )
|
||||
komodo_broadcast(pblock,8);
|
||||
return true;
|
||||
}
|
||||
@@ -4036,6 +4132,21 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
|
||||
REJECT_INVALID, "bad-cb-multiple");
|
||||
|
||||
// Check transactions
|
||||
if ( ASSETCHAINS_CC != 0 ) // CC contracts might refer to transactions in the current block, from a CC spend within the same block and out of order
|
||||
{
|
||||
CValidationState stateDummy;
|
||||
//fprintf(stderr,"put block's tx into mempool\n");
|
||||
for (int i = 0; i < block.vtx.size(); i++)
|
||||
{
|
||||
const CTransaction &tx = block.vtx[i];
|
||||
if (tx.IsCoinBase() != 0 )
|
||||
continue;
|
||||
else if ( ASSETCHAINS_STAKED != 0 && (i == (block.vtx.size() - 1)) && komodo_isPoS((CBlock *)&block) != 0 )
|
||||
continue;
|
||||
AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL);
|
||||
}
|
||||
//fprintf(stderr,"done putting block's tx into mempool\n");
|
||||
}
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
{
|
||||
if ( komodo_validate_interest(tx,height == 0 ? komodo_block2height((CBlock *)&block) : height,block.nTime,0) < 0 )
|
||||
@@ -4439,15 +4550,15 @@ bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNo
|
||||
bool checked; uint256 hash; int32_t futureblock=0;
|
||||
auto verifier = libzcash::ProofVerifier::Disabled();
|
||||
hash = pblock->GetHash();
|
||||
|
||||
if ( chainActive.LastTip() != 0 )
|
||||
komodo_currentheight_set(chainActive.LastTip()->nHeight);
|
||||
checked = CheckBlock(&futureblock,height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier,0);
|
||||
//fprintf(stderr,"ProcessBlock %d\n",(int32_t)chainActive.LastTip()->nHeight);
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if ( chainActive.LastTip() != 0 )
|
||||
komodo_currentheight_set(chainActive.LastTip()->nHeight);
|
||||
checked = CheckBlock(&futureblock,height!=0?height:komodo_block2height(pblock),0,*pblock, state, verifier,0);
|
||||
bool fRequested = MarkBlockAsReceived(hash);
|
||||
fRequested |= fForceProcessing;
|
||||
if ( checked != 0 && komodo_checkPOW(from_miner && ASSETCHAINS_STAKED == 0,pblock,height) < 0 )
|
||||
if ( checked != 0 && komodo_checkPOW(0,pblock,height) < 0 ) //from_miner && ASSETCHAINS_STAKED == 0
|
||||
{
|
||||
checked = 0;
|
||||
//fprintf(stderr,"passed checkblock but failed checkPOW.%d\n",from_miner && ASSETCHAINS_STAKED == 0);
|
||||
@@ -4479,7 +4590,8 @@ bool ProcessNewBlock(bool from_miner,int32_t height,CValidationState &state, CNo
|
||||
|
||||
if (futureblock == 0 && !ActivateBestChain(state, pblock))
|
||||
return error("%s: ActivateBestChain failed", __func__);
|
||||
|
||||
//fprintf(stderr,"finished ProcessBlock %d\n",(int32_t)chainActive.LastTip()->nHeight);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,8 @@ static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
|
||||
/** Maximum length of reject messages. */
|
||||
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
|
||||
|
||||
static const bool DEFAULT_ADDRESSINDEX = false;
|
||||
//static const bool DEFAULT_ADDRESSINDEX = false;
|
||||
#define DEFAULT_ADDRESSINDEX (GetArg("-ac_cc",0) != 0)
|
||||
static const bool DEFAULT_TIMESTAMPINDEX = false;
|
||||
static const bool DEFAULT_SPENTINDEX = false;
|
||||
static const unsigned int DEFAULT_DB_MAX_OPEN_FILES = 1000;
|
||||
|
||||
@@ -106,7 +106,7 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
|
||||
|
||||
#include "komodo_defs.h"
|
||||
|
||||
extern int32_t ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE;
|
||||
extern int32_t KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE;
|
||||
extern uint64_t ASSETCHAINS_REWARD,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED;
|
||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY;
|
||||
@@ -126,7 +126,8 @@ int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33);
|
||||
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount)
|
||||
{
|
||||
uint64_t deposits; int32_t isrealtime,kmdheight; uint32_t blocktime; const CChainParams& chainparams = Params();
|
||||
// Create new block
|
||||
//fprintf(stderr,"create new block\n");
|
||||
// Create new block
|
||||
if ( gpucount < 0 )
|
||||
gpucount = KOMODO_MAXGPUCOUNT;
|
||||
std::unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
|
||||
@@ -163,10 +164,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount)
|
||||
|
||||
// Collect memory pool transactions into the block
|
||||
CAmount nFees = 0;
|
||||
|
||||
CBlockIndex* pindexPrev = 0;
|
||||
{
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
CBlockIndex* pindexPrev = chainActive.LastTip();
|
||||
pindexPrev = chainActive.LastTip();
|
||||
const int nHeight = pindexPrev->nHeight + 1;
|
||||
uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus());
|
||||
pblock->nTime = GetAdjustedTime();
|
||||
@@ -492,19 +493,38 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount)
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
else if ( ASSETCHAINS_STAKED == 0 )
|
||||
else if ( ASSETCHAINS_CC == 0 && pindexPrev != 0 && ASSETCHAINS_STAKED == 0 && (ASSETCHAINS_SYMBOL[0] != 0 || IS_KOMODO_NOTARY == 0 || My_notaryid < 0) )
|
||||
{
|
||||
CValidationState state;
|
||||
if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false))
|
||||
//fprintf(stderr,"check validity\n");
|
||||
if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) // invokes CC checks
|
||||
{
|
||||
//static uint32_t counter;
|
||||
//if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
||||
// fprintf(stderr,"warning: miner testblockvalidity failed\n");
|
||||
fprintf(stderr,"invalid\n");
|
||||
return(0);
|
||||
}
|
||||
//fprintf(stderr,"valid\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* skip checking validity outside of lock. if inside lock and CC contract is being validated, can deadlock.
|
||||
if ( ASSETCHAINS_CC != 0 && pindexPrev != 0 && ASSETCHAINS_STAKED == 0 && (ASSETCHAINS_SYMBOL[0] != 0 || IS_KOMODO_NOTARY == 0 || My_notaryid < 0) )
|
||||
{
|
||||
CValidationState state;
|
||||
//fprintf(stderr,"check validity\n");
|
||||
if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) // invokes CC checks
|
||||
{
|
||||
//static uint32_t counter;
|
||||
//if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
||||
// fprintf(stderr,"warning: miner testblockvalidity failed\n");
|
||||
fprintf(stderr,"invalid\n");
|
||||
return(0);
|
||||
}
|
||||
//fprintf(stderr,"valid\n");
|
||||
}*/
|
||||
//fprintf(stderr,"done new block\n");
|
||||
|
||||
return pblocktemplate.release();
|
||||
}
|
||||
|
||||
@@ -644,7 +664,7 @@ static bool ProcessBlockFound(CBlock* pblock)
|
||||
|
||||
// Found a solution
|
||||
{
|
||||
LOCK(cs_main);
|
||||
//LOCK(cs_main);
|
||||
if (pblock->hashPrevBlock != chainActive.LastTip()->GetBlockHash())
|
||||
{
|
||||
uint256 hash; int32_t i;
|
||||
@@ -673,11 +693,13 @@ static bool ProcessBlockFound(CBlock* pblock)
|
||||
// Track how many getdata requests this block gets
|
||||
//if ( 0 )
|
||||
{
|
||||
//fprintf(stderr,"lock cs_wallet\n");
|
||||
LOCK(wallet.cs_wallet);
|
||||
wallet.mapRequestCount[pblock->GetHash()] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//fprintf(stderr,"process new block\n");
|
||||
|
||||
// Process this block the same as if we had received it from another node
|
||||
CValidationState state;
|
||||
if (!ProcessNewBlock(1,chainActive.LastTip()->nHeight+1,state, NULL, pblock, true, NULL))
|
||||
@@ -692,7 +714,7 @@ int32_t komodo_baseid(char *origbase);
|
||||
int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t *blocktimes,int32_t *nonzpkeysp,int32_t height);
|
||||
arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc);
|
||||
int32_t FOUND_BLOCK,KOMODO_MAYBEMINED;
|
||||
extern int32_t KOMODO_LASTMINED;
|
||||
extern int32_t KOMODO_LASTMINED,KOMODO_INSYNC;
|
||||
int32_t roundrobin_delay;
|
||||
arith_uint256 HASHTarget,HASHTarget_POW;
|
||||
|
||||
@@ -718,13 +740,14 @@ void static BitcoinMiner()
|
||||
unsigned int n = chainparams.EquihashN();
|
||||
unsigned int k = chainparams.EquihashK();
|
||||
uint8_t *script; uint64_t total,checktoshis; int32_t i,j,gpucount=KOMODO_MAXGPUCOUNT,notaryid = -1;
|
||||
while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) //chainActive.LastTip()->nHeight != 235300 &&
|
||||
while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) )
|
||||
{
|
||||
sleep(1);
|
||||
if ( komodo_baseid(ASSETCHAINS_SYMBOL) < 0 )
|
||||
break;
|
||||
}
|
||||
komodo_chosennotary(¬aryid,chainActive.LastTip()->nHeight,NOTARY_PUBKEY33,(uint32_t)chainActive.LastTip()->GetBlockTime());
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 )
|
||||
komodo_chosennotary(¬aryid,chainActive.LastTip()->nHeight,NOTARY_PUBKEY33,(uint32_t)chainActive.LastTip()->GetBlockTime());
|
||||
if ( notaryid != My_notaryid )
|
||||
My_notaryid = notaryid;
|
||||
std::string solver;
|
||||
@@ -800,6 +823,7 @@ void static BitcoinMiner()
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
//fprintf(stderr,"get template\n");
|
||||
unique_ptr<CBlockTemplate> pblocktemplate(ptr);
|
||||
if (!pblocktemplate.get())
|
||||
{
|
||||
@@ -827,6 +851,7 @@ void static BitcoinMiner()
|
||||
}
|
||||
}
|
||||
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
|
||||
//fprintf(stderr,"Running KomodoMiner.%s with %u transactions in block\n",solver.c_str(),(int32_t)pblock->vtx.size());
|
||||
LogPrintf("Running KomodoMiner.%s with %u transactions in block (%u bytes)\n",solver.c_str(),pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
|
||||
//
|
||||
// Search
|
||||
@@ -901,12 +926,13 @@ void static BitcoinMiner()
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
/*if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && pblock->vtx[0].vout.size() == 1 && Mining_height > ASSETCHAINS_MINHEIGHT ) // skips when it shouldnt
|
||||
{
|
||||
fprintf(stderr,"skip generating %s on-demand block, no tx avail\n",ASSETCHAINS_SYMBOL);
|
||||
sleep(10);
|
||||
break;
|
||||
}*/
|
||||
if ( KOMODO_INSYNC == 0 )
|
||||
{
|
||||
fprintf(stderr,"Mining when blockchain might not be in sync longest.%d vs %d\n",KOMODO_LONGESTCHAIN,Mining_height);
|
||||
if ( KOMODO_LONGESTCHAIN != 0 && Mining_height >= KOMODO_LONGESTCHAIN )
|
||||
KOMODO_INSYNC = 1;
|
||||
sleep(3);
|
||||
}
|
||||
// Hash state
|
||||
KOMODO_CHOSEN_ONE = 0;
|
||||
crypto_generichash_blake2b_state state;
|
||||
|
||||
@@ -210,7 +210,7 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
|
||||
delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString()));
|
||||
}
|
||||
else if (out.scriptPubKey.IsPayToPublicKey()) {
|
||||
else if (out.scriptPubKey.IsPayToPublicKey() || out.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
CTxDestination address;
|
||||
if (ExtractDestination(out.scriptPubKey, address))
|
||||
{
|
||||
|
||||
@@ -153,8 +153,8 @@ UniValue migrate_converttoexport(const UniValue& params, bool fHelp)
|
||||
"import transaction.\n"
|
||||
);
|
||||
|
||||
if (ASSETCHAINS_CC < 2)
|
||||
throw runtime_error("-ac_cc < 2");
|
||||
if (ASSETCHAINS_CC < KOMODO_FIRSTFUNGIBLEID)
|
||||
throw runtime_error("-ac_cc < KOMODO_FIRSTFUNGIBLEID");
|
||||
|
||||
if (ASSETCHAINS_SYMBOL[0] == 0)
|
||||
throw runtime_error("Must be called on assetchain");
|
||||
@@ -208,8 +208,8 @@ UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp)
|
||||
throw runtime_error("migrate_createimporttransaction burnTx payouts\n\n"
|
||||
"Create an importTx given a burnTx and the corresponding payouts, hex encoded");
|
||||
|
||||
if (ASSETCHAINS_CC < 2)
|
||||
throw runtime_error("-ac_cc < 2");
|
||||
if (ASSETCHAINS_CC < KOMODO_FIRSTFUNGIBLEID)
|
||||
throw runtime_error("-ac_cc < KOMODO_FIRSTFUNGIBLEID");
|
||||
|
||||
if (ASSETCHAINS_SYMBOL[0] == 0)
|
||||
throw runtime_error("Must be called on assetchain");
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern uint64_t ASSETCHAINS_STAKED;
|
||||
arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc);
|
||||
|
||||
/**
|
||||
* Return average network hashes per second based on the last 'lookup' blocks,
|
||||
@@ -727,7 +729,15 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
|
||||
result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
|
||||
}
|
||||
result.push_back(Pair("longpollid", chainActive.LastTip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
|
||||
result.push_back(Pair("target", hashTarget.GetHex()));
|
||||
if ( ASSETCHAINS_STAKED != 0 )
|
||||
{
|
||||
arith_uint256 POWtarget; int32_t PoSperc;
|
||||
POWtarget = komodo_PoWtarget(&PoSperc,hashTarget,(int32_t)(pindexPrev->nHeight+1),ASSETCHAINS_STAKED);
|
||||
result.push_back(Pair("target", POWtarget.GetHex()));
|
||||
result.push_back(Pair("PoSperc", (int64_t)PoSperc));
|
||||
result.push_back(Pair("ac_staked", (int64_t)ASSETCHAINS_STAKED));
|
||||
result.push_back(Pair("origtarget", hashTarget.GetHex()));
|
||||
} else result.push_back(Pair("target", hashTarget.GetHex()));
|
||||
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
|
||||
result.push_back(Pair("mutable", aMutable));
|
||||
result.push_back(Pair("noncerange", "00000000ffffffff"));
|
||||
|
||||
@@ -229,21 +229,43 @@ public:
|
||||
|
||||
UniValue coinsupply(const UniValue& params, bool fHelp)
|
||||
{
|
||||
int32_t height = 0; int64_t zfunds,supply = 0; UniValue result(UniValue::VOBJ);
|
||||
int32_t height = 0; int32_t currentHeight; int64_t zfunds,supply = 0; UniValue result(UniValue::VOBJ);
|
||||
if (fHelp || params.size() > 1)
|
||||
throw runtime_error("coinsupply <height>\n");
|
||||
throw runtime_error("coinsupply <height>\n"
|
||||
"\nReturn coin supply information at a given block height. If no height is given, the current height is used.\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"height\" (integer, optional) Block height\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"result\" : \"success\", (string) If the request was successful.\n"
|
||||
" \"coin\" : \"KMD\", (string) The currency symbol of the coin for asset chains, otherwise KMD.\n"
|
||||
" \"height\" : 420, (integer) The height of this coin supply data\n"
|
||||
" \"supply\" : \"777.0\", (float) The transparent coin supply\n"
|
||||
" \"zfunds\" : \"0.777\", (float) The shielded coin supply (in zaddrs)\n"
|
||||
" \"total\" : \"777.777\", (float) The total coin supply, i.e. sum of supply + zfunds\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("coinsupply", "420")
|
||||
+ HelpExampleRpc("coinsupply", "420")
|
||||
);
|
||||
if ( params.size() == 0 )
|
||||
height = chainActive.Height();
|
||||
else height = atoi(params[0].get_str());
|
||||
if ( (supply= komodo_coinsupply(&zfunds,height)) > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("coin", ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL));
|
||||
result.push_back(Pair("height", (int)height));
|
||||
result.push_back(Pair("supply", ValueFromAmount(supply)));
|
||||
result.push_back(Pair("zfunds", ValueFromAmount(zfunds)));
|
||||
result.push_back(Pair("total", ValueFromAmount(zfunds + supply)));
|
||||
} else result.push_back(Pair("error", "couldnt calculate supply"));
|
||||
currentHeight = chainActive.Height();
|
||||
|
||||
if (height >= 0 && height <= currentHeight) {
|
||||
if ( (supply= komodo_coinsupply(&zfunds,height)) > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("coin", ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL));
|
||||
result.push_back(Pair("height", (int)height));
|
||||
result.push_back(Pair("supply", ValueFromAmount(supply)));
|
||||
result.push_back(Pair("zfunds", ValueFromAmount(zfunds)));
|
||||
result.push_back(Pair("total", ValueFromAmount(zfunds + supply)));
|
||||
} else result.push_back(Pair("error", "couldnt calculate supply"));
|
||||
} else {
|
||||
result.push_back(Pair("error", "invalid height"));
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
@@ -1015,20 +1037,57 @@ UniValue getaddressbalance(const UniValue& params, bool fHelp)
|
||||
|
||||
}
|
||||
|
||||
int32_t komodo_snapshot();
|
||||
UniValue komodo_snapshot(int top);
|
||||
|
||||
UniValue getsnapshot(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); int64_t total;
|
||||
if ( fHelp || params.size() > 0 )
|
||||
UniValue result(UniValue::VOBJ); int64_t total; int32_t top = 0;
|
||||
|
||||
if (params.size() > 0 && !params[0].isNull()) {
|
||||
top = atoi(params[0].get_str().c_str());
|
||||
if (top <= 0)
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, top must be a positive integer");
|
||||
}
|
||||
|
||||
if ( fHelp || params.size() > 1)
|
||||
{
|
||||
throw runtime_error(
|
||||
"getsnapshot\n"
|
||||
"\nReturns a snapshot of (address,amount) pairs at current height (requires addressindex to be enabled).\n"
|
||||
"\nArguments:\n"
|
||||
" \"top\" (number, optional) Only return this many addresses, i.e. top N richlist\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"addresses\": [\n"
|
||||
" {\n"
|
||||
" \"addr\": \"RMEBhzvATA8mrfVK82E5TgPzzjtaggRGN3\",\n"
|
||||
" \"amount\": \"100.0\"\n"
|
||||
" },\n"
|
||||
" {\n"
|
||||
" \"addr\": \"RqEBhzvATAJmrfVL82E57gPzzjtaggR777\",\n"
|
||||
" \"amount\": \"23.45\"\n"
|
||||
" }\n"
|
||||
" ],\n"
|
||||
" \"total\": 123.45 (numeric) Total amount in snapshot\n"
|
||||
" \"average\": 61.7, (numeric) Average amount in each address \n"
|
||||
" \"utxos\": 14, (number) Total number of UTXOs in snapshot\n"
|
||||
" \"total_addresses\": 2, (number) Total number of addresses in snapshot,\n"
|
||||
" \"start_height\": 91, (number) Block height snapshot began\n"
|
||||
" \"ending_height\": 91 (number) Block height snapsho finished,\n"
|
||||
" \"start_time\": 1531982752, (number) Unix epoch time snapshot started\n"
|
||||
" \"end_time\": 1531982752 (number) Unix epoch time snapshot finished\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("getsnapshot","")
|
||||
+ HelpExampleRpc("getsnapshot", "1000")
|
||||
);
|
||||
}
|
||||
if ( (total= komodo_snapshot()) >= 0 )
|
||||
result.push_back(Pair("total", (double)total/COIN));
|
||||
else result.push_back(Pair("error", "no addressindex"));
|
||||
result = komodo_snapshot(top);
|
||||
if ( result.size() > 0 ) {
|
||||
result.push_back(Pair("end_time", (int) time(NULL)));
|
||||
} else {
|
||||
result.push_back(Pair("error", "no addressindex"));
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -196,6 +196,9 @@ int32_t komodo_longestchain()
|
||||
}
|
||||
if ( num > (n >> 1) )
|
||||
{
|
||||
extern char ASSETCHAINS_SYMBOL[];
|
||||
if ( 0 && height != KOMODO_LONGESTCHAIN )
|
||||
fprintf(stderr,"set %s KOMODO_LONGESTCHAIN <- %d\n",ASSETCHAINS_SYMBOL,height);
|
||||
KOMODO_LONGESTCHAIN = height;
|
||||
return(height);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern char ASSETCHAINS_SYMBOL[];
|
||||
|
||||
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
|
||||
{
|
||||
txnouttype type;
|
||||
@@ -43,7 +45,8 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud
|
||||
if (fIncludeHex)
|
||||
out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
|
||||
|
||||
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) {
|
||||
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
|
||||
{
|
||||
out.push_back(Pair("type", GetTxnOutputType(type)));
|
||||
return;
|
||||
}
|
||||
@@ -175,11 +178,12 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
|
||||
CBlockIndex *tipindex,*pindex = it->second;
|
||||
uint64_t interest;
|
||||
UniValue vout(UniValue::VARR);
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++) {
|
||||
for (unsigned int i = 0; i < tx.vout.size(); i++)
|
||||
{
|
||||
const CTxOut& txout = tx.vout[i];
|
||||
UniValue out(UniValue::VOBJ);
|
||||
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
|
||||
if ( pindex != 0 && tx.nLockTime >= 500000000 && (tipindex= chainActive.LastTip()) != 0 )
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && pindex != 0 && tx.nLockTime >= 500000000 && (tipindex= chainActive.LastTip()) != 0 )
|
||||
{
|
||||
int64_t interest; int32_t txheight; uint32_t locktime;
|
||||
interest = komodo_accrued_interest(&txheight,&locktime,tx.GetHash(),i,0,txout.nValue,(int32_t)tipindex->nHeight);
|
||||
|
||||
@@ -344,6 +344,53 @@ static const CRPCCommand vRPCCommands[] =
|
||||
#ifdef ENABLE_WALLET
|
||||
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
|
||||
#endif
|
||||
/* auction */
|
||||
{ "auction", "auctionaddress", &auctionaddress, true },
|
||||
|
||||
/* lotto */
|
||||
{ "lotto", "lottoaddress", &lottoaddress, true },
|
||||
|
||||
/* ponzi */
|
||||
{ "ponzi", "ponziaddress", &ponziaddress, true },
|
||||
|
||||
/* rewards */
|
||||
{ "rewards", "rewardslist", &rewardslist, true },
|
||||
{ "rewards", "rewardsinfo", &rewardsinfo, true },
|
||||
{ "rewards", "rewardscreatefunding", &rewardscreatefunding, true },
|
||||
{ "rewards", "rewardsaddfunding", &rewardsaddfunding, true },
|
||||
{ "rewards", "rewardslock", &rewardslock, true },
|
||||
{ "rewards", "rewardsunlock", &rewardsunlock, true },
|
||||
{ "rewards", "rewardsaddress", &rewardsaddress, true },
|
||||
|
||||
/* faucet */
|
||||
{ "faucet", "faucetfund", &faucetfund, true },
|
||||
{ "faucet", "faucetget", &faucetget, true },
|
||||
{ "faucet", "faucetaddress", &faucetaddress, true },
|
||||
|
||||
/* dice */
|
||||
{ "dice", "dicelist", &dicelist, true },
|
||||
{ "dice", "diceinfo", &diceinfo, true },
|
||||
{ "dice", "dicefund", &dicefund, true },
|
||||
{ "dice", "diceaddfunds", &diceaddfunds, true },
|
||||
{ "dice", "dicebet", &dicebet, true },
|
||||
{ "dice", "diceaddress", &diceaddress, true },
|
||||
|
||||
/* tokens */
|
||||
{ "tokens", "tokeninfo", &tokeninfo, true },
|
||||
{ "tokens", "tokenlist", &tokenlist, true },
|
||||
{ "tokens", "tokenorders", &tokenorders, true },
|
||||
{ "tokens", "tokenaddress", &tokenaddress, true },
|
||||
{ "tokens", "tokenbalance", &tokenbalance, true },
|
||||
{ "tokens", "tokencreate", &tokencreate, true },
|
||||
{ "tokens", "tokentransfer", &tokentransfer, true },
|
||||
{ "tokens", "tokenbid", &tokenbid, true },
|
||||
{ "tokens", "tokencancelbid", &tokencancelbid, true },
|
||||
{ "tokens", "tokenfillbid", &tokenfillbid, true },
|
||||
{ "tokens", "tokenask", &tokenask, true },
|
||||
{ "tokens", "tokenswapask", &tokenswapask, true },
|
||||
{ "tokens", "tokencancelask", &tokencancelask, true },
|
||||
{ "tokens", "tokenfillask", &tokenfillask, true },
|
||||
{ "tokens", "tokenfillswap", &tokenfillswap, true },
|
||||
|
||||
/* Address index */
|
||||
{ "addressindex", "getaddressmempool", &getaddressmempool, true },
|
||||
|
||||
@@ -208,6 +208,40 @@ extern UniValue submitblock(const UniValue& params, bool fHelp);
|
||||
extern UniValue estimatefee(const UniValue& params, bool fHelp);
|
||||
extern UniValue estimatepriority(const UniValue& params, bool fHelp);
|
||||
extern UniValue coinsupply(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokeninfo(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenlist(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenorders(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenbalance(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokencreate(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokentransfer(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenbid(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokencancelbid(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenfillbid(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenask(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokencancelask(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenfillask(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenswapask(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenfillswap(const UniValue& params, bool fHelp);
|
||||
extern UniValue faucetfund(const UniValue& params, bool fHelp);
|
||||
extern UniValue faucetget(const UniValue& params, bool fHelp);
|
||||
extern UniValue faucetaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue rewardsinfo(const UniValue& params, bool fHelp);
|
||||
extern UniValue rewardslist(const UniValue& params, bool fHelp);
|
||||
extern UniValue rewardsaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue rewardscreatefunding(const UniValue& params, bool fHelp);
|
||||
extern UniValue rewardsaddfunding(const UniValue& params, bool fHelp);
|
||||
extern UniValue rewardslock(const UniValue& params, bool fHelp);
|
||||
extern UniValue rewardsunlock(const UniValue& params, bool fHelp);
|
||||
extern UniValue diceaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue dicefund(const UniValue& params, bool fHelp);
|
||||
extern UniValue dicelist(const UniValue& params, bool fHelp);
|
||||
extern UniValue diceinfo(const UniValue& params, bool fHelp);
|
||||
extern UniValue diceaddfunds(const UniValue& params, bool fHelp);
|
||||
extern UniValue dicebet(const UniValue& params, bool fHelp);
|
||||
extern UniValue lottoaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue ponziaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue auctionaddress(const UniValue& params, bool fHelp);
|
||||
|
||||
extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||
//extern UniValue getnewaddress64(const UniValue& params, bool fHelp); // in rpcwallet.cpp
|
||||
|
||||
@@ -1313,6 +1313,14 @@ int TransactionSignatureChecker::CheckCryptoCondition(
|
||||
} catch (logic_error ex) {
|
||||
return 0;
|
||||
}
|
||||
//int32_t z; uint8_t *ptr;
|
||||
//ptr = (uint8_t *)scriptCode.data();
|
||||
//for (z=0; z<scriptCode.size(); z++)
|
||||
// fprintf(stderr,"%02x",ptr[z]);
|
||||
//fprintf(stderr," <- CScript\n");
|
||||
//for (z=0; z<32; z++)
|
||||
// fprintf(stderr,"%02x",((uint8_t *)&sighash)[z]);
|
||||
//fprintf(stderr," sighash nIn.%d nHashType.%d %.8f id.%d\n",(int32_t)nIn,(int32_t)nHashType,(double)amount/COIN,(int32_t)consensusBranchId);
|
||||
|
||||
VerifyEval eval = [] (CC *cond, void *checker) {
|
||||
return ((TransactionSignatureChecker*)checker)->CheckEvalCondition(cond);
|
||||
@@ -1320,6 +1328,7 @@ int TransactionSignatureChecker::CheckCryptoCondition(
|
||||
|
||||
int out = cc_verify(cond, (const unsigned char*)&sighash, 32, 0,
|
||||
condBin.data(), condBin.size(), eval, (void*)this);
|
||||
//fprintf(stderr,"out.%d from cc_verify\n",(int32_t)out);
|
||||
cc_free(cond);
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ const char* GetTxnOutputType(txnouttype t)
|
||||
case TX_SCRIPTHASH: return "scripthash";
|
||||
case TX_MULTISIG: return "multisig";
|
||||
case TX_NULL_DATA: return "nulldata";
|
||||
case TX_CRYPTOCONDITION: return "cryptocondition";
|
||||
default: return "invalid";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -74,6 +76,14 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||
if (scriptPubKey.IsPayToCryptoCondition()) {
|
||||
if (scriptPubKey.MayAcceptCryptoCondition()) {
|
||||
typeRet = TX_CRYPTOCONDITION;
|
||||
vector<unsigned char> hashBytes; uint160 x; int32_t i; uint8_t hash20[20],*ptr;;
|
||||
x = Hash160(scriptPubKey);
|
||||
memcpy(hash20,&x,20);
|
||||
hashBytes.resize(20);
|
||||
ptr = hashBytes.data();
|
||||
for (i=0; i<20; i++)
|
||||
ptr[i] = hash20[i];
|
||||
vSolutionsRet.push_back(hashBytes);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -251,6 +261,12 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||
addressRet = CScriptID(uint160(vSolutions[0]));
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (IsCryptoConditionsEnabled() != 0 && whichType == TX_CRYPTOCONDITION)
|
||||
{
|
||||
addressRet = CKeyID(uint160(vSolutions[0]));
|
||||
return true;
|
||||
}
|
||||
// Multisig txns have more than one address...
|
||||
return false;
|
||||
}
|
||||
@@ -288,7 +304,9 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto
|
||||
nRequiredRet = 1;
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(scriptPubKey, address))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
addressRet.push_back(address);
|
||||
}
|
||||
|
||||
|
||||
141
src/txdb.cpp
141
src/txdb.cpp
@@ -10,6 +10,7 @@
|
||||
#include "main.h"
|
||||
#include "pow.h"
|
||||
#include "uint256.h"
|
||||
#include "core_io.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -398,46 +399,140 @@ bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type,
|
||||
|
||||
bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address);
|
||||
|
||||
int64_t CBlockTreeDB::Snapshot()
|
||||
extern UniValue CBlockTreeDB::Snapshot(int top)
|
||||
{
|
||||
char chType; int64_t total = 0; std::string address;
|
||||
boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
|
||||
pcursor->SeekToLast();
|
||||
fprintf(stderr,"pcursor iterate\n");
|
||||
while (pcursor->Valid())
|
||||
char chType; int64_t total = 0; int64_t totalAddresses = 0; std::string address;
|
||||
int64_t utxos = 0; int64_t ignoredAddresses;
|
||||
boost::scoped_ptr<leveldb::Iterator> iter(NewIterator());
|
||||
std::map <std::string, CAmount> addressAmounts;
|
||||
std::vector <std::pair<CAmount, std::string>> vaddr;
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("start_time", (int) time(NULL)));
|
||||
|
||||
std::map <std::string,int> ignoredMap = {
|
||||
{"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1},
|
||||
{"RMUF3UDmzWFLSKV82iFbMaqzJpUnrWjcT4", 1},
|
||||
{"RA5imhVyJa7yHhggmBytWuDr923j2P1bxx", 1},
|
||||
{"RBM5LofZFodMeewUzoMWcxedm3L3hYRaWg", 1},
|
||||
{"RAdcko2d94TQUcJhtFHZZjMyWBKEVfgn4J", 1},
|
||||
{"RLzUaZ934k2EFCsAiVjrJqM8uU1vmMRFzk", 1},
|
||||
{"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1},
|
||||
{"RUDrX1v5toCsJMUgtvBmScKjwCB5NaR8py", 1},
|
||||
{"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1},
|
||||
{"RRvwmbkxR5YRzPGL5kMFHMe1AH33MeD8rN", 1},
|
||||
{"RQLQvSgpPAJNPgnpc8MrYsbBhep95nCS8L", 1},
|
||||
{"RK8JtBV78HdvEPvtV5ckeMPSTojZPzHUTe", 1},
|
||||
{"RHVs2KaCTGUMNv3cyWiG1jkEvZjigbCnD2", 1},
|
||||
{"RE3SVaDgdjkRPYA6TRobbthsfCmxQedVgF", 1},
|
||||
{"RW6S5Lw5ZCCvDyq4QV9vVy7jDHfnynr5mn", 1},
|
||||
{"RTkJwAYtdXXhVsS3JXBAJPnKaBfMDEswF8", 1},
|
||||
{"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} //Burnaddress for null privkey
|
||||
};
|
||||
|
||||
int64_t startingHeight = chainActive.Height();
|
||||
fprintf(stderr, "Starting snapshot at height %li\n", startingHeight);
|
||||
for (iter->SeekToLast(); iter->Valid(); iter->Prev())
|
||||
{
|
||||
boost::this_thread::interruption_point();
|
||||
try
|
||||
{
|
||||
leveldb::Slice slKey = pcursor->key();
|
||||
leveldb::Slice slKey = iter->key();
|
||||
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
|
||||
CAddressIndexKey indexKey;
|
||||
ssKey >> chType;
|
||||
ssKey >> indexKey;
|
||||
fprintf(stderr,"chType.%d\n",chType);
|
||||
if ( chType == DB_ADDRESSINDEX )
|
||||
CAddressIndexIteratorKey indexKey;
|
||||
|
||||
ssKey >> chType;
|
||||
ssKey >> indexKey;
|
||||
|
||||
//fprintf(stderr, "chType=%d\n", chType);
|
||||
if (chType == DB_ADDRESSUNSPENTINDEX)
|
||||
{
|
||||
try {
|
||||
leveldb::Slice slValue = pcursor->value();
|
||||
leveldb::Slice slValue = iter->value();
|
||||
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
|
||||
CAmount nValue;
|
||||
ssValue >> nValue;
|
||||
getAddressFromIndex(indexKey.type, indexKey.hashBytes, address);
|
||||
fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN);
|
||||
if ( total < 0 )
|
||||
total = (int64_t)nValue;
|
||||
else total += (int64_t)nValue;
|
||||
//addressIndex.push_back(make_pair(indexKey, nValue));
|
||||
|
||||
getAddressFromIndex(indexKey.type, indexKey.hashBytes, address);
|
||||
|
||||
std::map <std::string, int>::iterator ignored = ignoredMap.find(address);
|
||||
if (ignored != ignoredMap.end()) {
|
||||
fprintf(stderr,"ignoring %s\n", address.c_str());
|
||||
ignoredAddresses++;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map <std::string, CAmount>::iterator pos = addressAmounts.find(address);
|
||||
if (pos == addressAmounts.end()) {
|
||||
// insert new address + utxo amount
|
||||
//fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue);
|
||||
addressAmounts[address] = nValue;
|
||||
totalAddresses++;
|
||||
} else {
|
||||
// update unspent tally for this address
|
||||
//fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue);
|
||||
addressAmounts[address] += nValue;
|
||||
}
|
||||
//fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN);
|
||||
// total += nValue;
|
||||
utxos++;
|
||||
} catch (const std::exception& e) {
|
||||
return error("failed to get address index value");
|
||||
fprintf(stderr, "DONE %s: LevelDB addressindex exception! - %s\n", __func__, e.what());
|
||||
break;
|
||||
}
|
||||
} else { break; }
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
fprintf(stderr, "DONE reading index entries\n");
|
||||
break;
|
||||
}
|
||||
pcursor->Prev();
|
||||
}
|
||||
return(total);
|
||||
|
||||
UniValue addresses(UniValue::VARR);
|
||||
fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses);
|
||||
|
||||
for (std::pair<std::string, CAmount> element : addressAmounts) {
|
||||
vaddr.push_back( make_pair(element.second, element.first) );
|
||||
}
|
||||
std::sort(vaddr.rbegin(), vaddr.rend());
|
||||
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
UniValue addressesSorted(UniValue::VARR);
|
||||
int topN = 0;
|
||||
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) {
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back( make_pair("addr", it->second.c_str() ) );
|
||||
char amount[32];
|
||||
sprintf(amount, "%.8f", (double) it->first / COIN);
|
||||
obj.push_back( make_pair("amount", amount) );
|
||||
total += it->first;
|
||||
addressesSorted.push_back(obj);
|
||||
topN++;
|
||||
// If requested, only show top N addresses in output JSON
|
||||
if (top == topN)
|
||||
break;
|
||||
}
|
||||
|
||||
if (top)
|
||||
totalAddresses = top;
|
||||
|
||||
if (totalAddresses > 0) {
|
||||
// Array of all addreses with balances
|
||||
result.push_back(make_pair("addresses", addressesSorted));
|
||||
// Total amount in this snapshot, which is less than circulating supply if top parameter is used
|
||||
result.push_back(make_pair("total", (double) total / COIN ));
|
||||
// Average amount in each address of this snapshot
|
||||
result.push_back(make_pair("average",(double) (total/COIN) / totalAddresses ));
|
||||
}
|
||||
// Total number of utxos processed in this snaphot
|
||||
result.push_back(make_pair("utxos", utxos));
|
||||
// Total number of addresses in this snaphot
|
||||
result.push_back(make_pair("total_addresses", totalAddresses));
|
||||
// Total number of ignored addresses in this snaphot
|
||||
result.push_back(make_pair("ignored_addresses", ignoredAddresses));
|
||||
// The snapshot began at this block height
|
||||
result.push_back(make_pair("start_height", startingHeight));
|
||||
// The snapshot finished at this block height
|
||||
result.push_back(make_pair("ending_height", chainActive.Height()));
|
||||
return(result);
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::WriteTimestampIndex(const CTimestampIndexKey ×tampIndex) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <univalue.h>
|
||||
|
||||
class CBlockFileInfo;
|
||||
class CBlockIndex;
|
||||
@@ -94,7 +95,7 @@ public:
|
||||
bool ReadFlag(const std::string &name, bool &fValue);
|
||||
bool LoadBlockIndexGuts();
|
||||
bool blockOnchainActive(const uint256 &hash);
|
||||
int64_t Snapshot();
|
||||
UniValue Snapshot(int top);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_TXDB_H
|
||||
|
||||
@@ -152,7 +152,13 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC
|
||||
mapAddress.insert(make_pair(key, delta));
|
||||
inserted.push_back(key);
|
||||
}
|
||||
}
|
||||
else if (prevout.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
vector<unsigned char> hashBytes(prevout.scriptPubKey.begin(), prevout.scriptPubKey.end());
|
||||
CMempoolAddressDeltaKey key(1, Hash160(hashBytes), txhash, j, 1);
|
||||
CMempoolAddressDelta delta(entry.GetTime(), prevout.nValue * -1, input.prevout.hash, input.prevout.n);
|
||||
mapAddress.insert(make_pair(key, delta));
|
||||
inserted.push_back(key);
|
||||
} }
|
||||
|
||||
for (unsigned int k = 0; k < tx.vout.size(); k++) {
|
||||
const CTxOut &out = tx.vout[k];
|
||||
@@ -176,6 +182,13 @@ void CTxMemPool::addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewC
|
||||
mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
|
||||
inserted.push_back(key);
|
||||
}
|
||||
else if (out.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin(), out.scriptPubKey.end());
|
||||
std::pair<addressDeltaMap::iterator,bool> ret;
|
||||
CMempoolAddressDeltaKey key(1, Hash160(hashBytes), txhash, k, 0);
|
||||
mapAddress.insert(make_pair(key, CMempoolAddressDelta(entry.GetTime(), out.nValue)));
|
||||
inserted.push_back(key);
|
||||
}
|
||||
}
|
||||
|
||||
mapAddressInserted.insert(make_pair(txhash, inserted));
|
||||
@@ -237,6 +250,10 @@ void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCac
|
||||
addressHash = Hash160(vector<unsigned char> (prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34));
|
||||
addressType = 1;
|
||||
}
|
||||
else if (prevout.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
addressHash = Hash160(vector<unsigned char> (prevout.scriptPubKey.begin(), prevout.scriptPubKey.end()));
|
||||
addressType = 1;
|
||||
}
|
||||
else {
|
||||
addressHash.SetNull();
|
||||
addressType = 0;
|
||||
|
||||
@@ -4636,18 +4636,20 @@ arith_uint256 _komodo_eligible(struct komodo_staking *kp,arith_uint256 ratio,uin
|
||||
if ( iter > 0 )
|
||||
diff += segid*2;
|
||||
coinage = ((uint64_t)kp->nValue/COIN * diff);
|
||||
if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 )
|
||||
coinage *= ((blocktime+iter+segid*2) - (prevtime+60));
|
||||
if ( blocktime+iter+segid*2 > prevtime+480 )
|
||||
coinage *= ((blocktime+iter+segid*2) - (prevtime+400));
|
||||
//if ( nHeight >= 2500 && blocktime+iter+segid*2 > prevtime+180 )
|
||||
// coinage *= ((blocktime+iter+segid*2) - (prevtime+60));
|
||||
coinage256 = arith_uint256(coinage+1);
|
||||
hashval = ratio * (kp->hashval / coinage256);
|
||||
if ( nHeight >= 900 && nHeight < 916 )
|
||||
hashval = (hashval / coinage256);
|
||||
//if ( nHeight >= 900 && nHeight < 916 )
|
||||
// hashval = (hashval / coinage256);
|
||||
return(hashval);
|
||||
}
|
||||
|
||||
uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komodo_staking *kp,int32_t nHeight,uint32_t blocktime,uint32_t prevtime,int32_t minage,uint8_t *hashbuf)
|
||||
{
|
||||
int32_t maxiters = 180; uint256 hash;
|
||||
int32_t maxiters = 600; uint256 hash;
|
||||
int32_t segid,iter,diff; uint64_t coinage; arith_uint256 hashval,coinage256;
|
||||
komodo_stakehash(&hash,kp->address,hashbuf,kp->txid,kp->vout);
|
||||
kp->hashval = UintToArith256(hash);
|
||||
@@ -4678,7 +4680,7 @@ uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komod
|
||||
int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig)
|
||||
{
|
||||
static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime;
|
||||
set<CBitcoinAddress> setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock;
|
||||
set<CBitcoinAddress> setAddress; struct komodo_staking *kp; int32_t winners,segid,minage,nHeight,counter=0,i,m,siglen=0,nMinDepth = 1,nMaxDepth = 99999999; vector<COutput> vecOutputs; uint32_t block_from_future_rejecttime,besttime,eligible,eligible2,earliest = 0; CScript best_scriptPubKey; arith_uint256 mindiff,ratio,bnTarget; CBlockIndex *tipindex,*pindex; CTxDestination address; bool fNegative,fOverflow; uint8_t hashbuf[256]; CTransaction tx; uint256 hashBlock;
|
||||
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
|
||||
mindiff.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
|
||||
ratio = (mindiff / bnTarget);
|
||||
@@ -4737,6 +4739,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
lasttime = (uint32_t)time(NULL);
|
||||
//fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp);
|
||||
}
|
||||
block_from_future_rejecttime = (uint32_t)GetAdjustedTime() + 57;
|
||||
for (i=winners=0; i<numkp; i++)
|
||||
{
|
||||
if ( (tipindex= chainActive.Tip()) == 0 || tipindex->nHeight+1 > nHeight )
|
||||
@@ -4758,7 +4761,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
{
|
||||
besttime = eligible;
|
||||
eligible--;
|
||||
if ( eligible < (uint32_t)tipindex->nTime-63 )
|
||||
if ( eligible < block_from_future_rejecttime ) // nothing gained by going earlier
|
||||
break;
|
||||
m++;
|
||||
//fprintf(stderr,"m.%d ht.%d validated winning blocktime %u -> %.8f eligible.%u test prior\n",m,nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
|
||||
@@ -4827,6 +4830,618 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
return(siglen);
|
||||
}
|
||||
|
||||
int32_t ensure_CCrequirements()
|
||||
{
|
||||
extern uint8_t NOTARY_PUBKEY33[];
|
||||
if ( NOTARY_PUBKEY33[0] == 0 )
|
||||
return(-1);
|
||||
else if ( GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX) == 0 )
|
||||
return(-1);
|
||||
else return(0);
|
||||
}
|
||||
|
||||
#include "../cc/CCfaucet.h"
|
||||
#include "../cc/CCassets.h"
|
||||
#include "../cc/CCrewards.h"
|
||||
#include "../cc/CCdice.h"
|
||||
#include "../cc/CCponzi.h"
|
||||
#include "../cc/CCauction.h"
|
||||
#include "../cc/CClotto.h"
|
||||
|
||||
UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector<unsigned char> &pubkey)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); ; char destaddr[64],str[64],marker[64];
|
||||
result.push_back(Pair("result", "success"));
|
||||
sprintf(str,"%sCCaddress",name);
|
||||
sprintf(marker,"%smarker",name);
|
||||
if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
|
||||
result.push_back(Pair(str,destaddr));
|
||||
if ( pubkey.size() == 33 )
|
||||
{
|
||||
if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
|
||||
result.push_back(Pair("CCaddress",destaddr));
|
||||
}
|
||||
if ( GetCCaddress(cp,destaddr,pubkey2pk(Mypubkey())) != 0 )
|
||||
result.push_back(Pair("myCCaddress",destaddr));
|
||||
if ( Getscriptaddress(destaddr,(CScript() << Mypubkey() << OP_CHECKSIG)) != 0 )
|
||||
result.push_back(Pair("myaddress",destaddr));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue lottoaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
cp = CCinit(&C,EVAL_LOTTO);
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("lottoaddress [pubkey]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
if ( params.size() == 1 )
|
||||
pubkey = ParseHex(params[0].get_str().c_str());
|
||||
return(CCaddress(cp,(char *)"Lotto",pubkey));
|
||||
}
|
||||
|
||||
UniValue ponziaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
cp = CCinit(&C,EVAL_PONZI);
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("ponziaddress [pubkey]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
if ( params.size() == 1 )
|
||||
pubkey = ParseHex(params[0].get_str().c_str());
|
||||
return(CCaddress(cp,(char *)"Ponzi",pubkey));
|
||||
}
|
||||
|
||||
UniValue auctionaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
cp = CCinit(&C,EVAL_AUCTION);
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("auctionaddress [pubkey]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
if ( params.size() == 1 )
|
||||
pubkey = ParseHex(params[0].get_str().c_str());
|
||||
return(CCaddress(cp,(char *)"Auction",pubkey));
|
||||
}
|
||||
|
||||
UniValue diceaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
cp = CCinit(&C,EVAL_DICE);
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("diceaddress [pubkey]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
if ( params.size() == 1 )
|
||||
pubkey = ParseHex(params[0].get_str().c_str());
|
||||
return(CCaddress(cp,(char *)"Dice",pubkey));
|
||||
}
|
||||
|
||||
UniValue faucetaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
cp = CCinit(&C,EVAL_FAUCET);
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("faucetaddress [pubkey]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
if ( params.size() == 1 )
|
||||
pubkey = ParseHex(params[0].get_str().c_str());
|
||||
return(CCaddress(cp,(char *)"Faucet",pubkey));
|
||||
}
|
||||
|
||||
UniValue rewardsaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
cp = CCinit(&C,EVAL_REWARDS);
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("rewardsaddress [pubkey]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
if ( params.size() == 1 )
|
||||
pubkey = ParseHex(params[0].get_str().c_str());
|
||||
return(CCaddress(cp,(char *)"Rewards",pubkey));
|
||||
}
|
||||
|
||||
UniValue tokenaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("tokenaddress [pubkey]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
if ( params.size() == 1 )
|
||||
pubkey = ParseHex(params[0].get_str().c_str());
|
||||
return(CCaddress(cp,(char *)"Assets",pubkey));
|
||||
}
|
||||
|
||||
UniValue rewardscreatefunding(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); char *name; uint64_t funds,APR,minseconds,maxseconds,mindeposit; std::string hex;
|
||||
if ( fHelp || params.size() > 6 || params.size() < 2 )
|
||||
throw runtime_error("rewardscreatefunding name amount APR mindays maxdays mindeposit\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
// default to OOT params
|
||||
APR = 5 * COIN;
|
||||
minseconds = maxseconds = 60 * 3600 * 24;
|
||||
mindeposit = 100 * COIN;
|
||||
name = (char *)params[0].get_str().c_str();
|
||||
funds = atof(params[1].get_str().c_str()) * COIN;
|
||||
if ( params.size() > 2 )
|
||||
{
|
||||
APR = atof(params[2].get_str().c_str()) * COIN;
|
||||
if ( params.size() > 3 )
|
||||
{
|
||||
minseconds = atol(params[3].get_str().c_str()) * 3600 * 24;
|
||||
if ( params.size() > 4 )
|
||||
{
|
||||
maxseconds = atol(params[4].get_str().c_str()) * 3600 * 24;
|
||||
if ( params.size() > 5 )
|
||||
mindeposit = atof(params[5].get_str().c_str()) * COIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
hex = RewardsCreateFunding(0,name,funds,APR,minseconds,maxseconds,mindeposit);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create rewards funding transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue rewardslock(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; uint64_t amount; std::string hex;
|
||||
if ( fHelp || params.size() != 3 )
|
||||
throw runtime_error("rewardslock name fundingtxid amount\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
name = (char *)params[0].get_str().c_str();
|
||||
fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
amount = atof(params[2].get_str().c_str()) * COIN;
|
||||
hex = RewardsLock(0,name,fundingtxid,amount);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create rewards lock transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue rewardsaddfunding(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; uint64_t amount; std::string hex;
|
||||
if ( fHelp || params.size() != 3 )
|
||||
throw runtime_error("rewardsaddfunding name fundingtxid amount\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
name = (char *)params[0].get_str().c_str();
|
||||
fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
amount = atof(params[2].get_str().c_str()) * COIN;
|
||||
hex = RewardsAddfunding(0,name,fundingtxid,amount);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create rewards addfunding transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue rewardsunlock(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); std::string hex; char *name; uint256 fundingtxid,txid;
|
||||
if ( fHelp || params.size() > 3 )
|
||||
throw runtime_error("rewardsunlock name fundingtxid [txid]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
name = (char *)params[0].get_str().c_str();
|
||||
fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
if ( params.size() > 2 )
|
||||
txid = Parseuint256((char *)params[2].get_str().c_str());
|
||||
else memset(&txid,0,sizeof(txid));
|
||||
hex = RewardsUnlock(0,name,fundingtxid,txid);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create rewards unlock transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue rewardslist(const UniValue& params, bool fHelp)
|
||||
{
|
||||
uint256 tokenid;
|
||||
if ( fHelp || params.size() > 0 )
|
||||
throw runtime_error("rewardslist\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
return(RewardsList());
|
||||
}
|
||||
|
||||
UniValue rewardsinfo(const UniValue& params, bool fHelp)
|
||||
{
|
||||
uint256 fundingtxid;
|
||||
if ( fHelp || params.size() != 1 )
|
||||
throw runtime_error("rewardsinfo fundingtxid\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
return(RewardsInfo(fundingtxid));
|
||||
}
|
||||
|
||||
UniValue faucetfund(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint64_t funds; std::string hex;
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("faucetfund amount\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
funds = atof(params[0].get_str().c_str()) * COIN;
|
||||
hex = FaucetFund(0,funds);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create faucet funding transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue faucetget(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); std::string hex;
|
||||
if ( fHelp || params.size() > 0 )
|
||||
throw runtime_error("faucetget\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
hex = FaucetGet(0);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create faucet get transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue dicefund(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); int64_t funds,minbet,maxbet,maxodds,forfeitblocks; std::string hex; char *name;
|
||||
if ( fHelp || params.size() != 6 )
|
||||
throw runtime_error("dicefund name funds minbet maxbet maxodds forfeitblocks\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
name = (char *)params[0].get_str().c_str();
|
||||
funds = atof(params[1].get_str().c_str()) * COIN;
|
||||
minbet = atof(params[2].get_str().c_str()) * COIN;
|
||||
maxbet = atof(params[3].get_str().c_str()) * COIN;
|
||||
maxodds = atol(params[4].get_str().c_str());
|
||||
forfeitblocks = atol(params[5].get_str().c_str());
|
||||
hex = DiceCreateFunding(0,name,funds,minbet,maxbet,maxodds,forfeitblocks);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create dice funding transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue diceaddfunds(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid; uint64_t amount; std::string hex;
|
||||
if ( fHelp || params.size() != 3 )
|
||||
throw runtime_error("diceaddfunds name fundingtxid amount\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
name = (char *)params[0].get_str().c_str();
|
||||
fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
amount = atof(params[2].get_str().c_str()) * COIN;
|
||||
hex = DiceAddfunding(0,name,fundingtxid,amount);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create dice addfunding transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue dicebet(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid; uint64_t amount,odds; char *name;
|
||||
if ( fHelp || params.size() != 4 )
|
||||
throw runtime_error("dicebet name fundingtxid amount odds\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
name = (char *)params[0].get_str().c_str();
|
||||
fundingtxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
amount = atof(params[2].get_str().c_str()) * COIN;
|
||||
odds = atol(params[3].get_str().c_str());
|
||||
hex = DiceBet(0,name,fundingtxid,amount,odds);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create faucet get transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue dicelist(const UniValue& params, bool fHelp)
|
||||
{
|
||||
uint256 tokenid;
|
||||
if ( fHelp || params.size() > 0 )
|
||||
throw runtime_error("dicelist\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
return(DiceList());
|
||||
}
|
||||
|
||||
UniValue diceinfo(const UniValue& params, bool fHelp)
|
||||
{
|
||||
uint256 fundingtxid;
|
||||
if ( fHelp || params.size() != 1 )
|
||||
throw runtime_error("diceinfo fundingtxid\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
return(DiceInfo(fundingtxid));
|
||||
}
|
||||
|
||||
UniValue tokenlist(const UniValue& params, bool fHelp)
|
||||
{
|
||||
uint256 tokenid;
|
||||
if ( fHelp || params.size() > 0 )
|
||||
throw runtime_error("tokenlist\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
return(AssetList());
|
||||
}
|
||||
|
||||
UniValue tokeninfo(const UniValue& params, bool fHelp)
|
||||
{
|
||||
uint256 tokenid;
|
||||
if ( fHelp || params.size() != 1 )
|
||||
throw runtime_error("tokeninfo tokenid\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
return(AssetInfo(tokenid));
|
||||
}
|
||||
|
||||
UniValue tokenorders(const UniValue& params, bool fHelp)
|
||||
{
|
||||
uint256 tokenid;
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("tokenorders [tokenid]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
if ( params.size() == 1 )
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
else memset(&tokenid,0,sizeof(tokenid));
|
||||
return(AssetOrders(tokenid));
|
||||
}
|
||||
|
||||
UniValue tokenbalance(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); char destaddr[64]; uint256 tokenid; uint64_t balance; std::vector<unsigned char> pubkey; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( fHelp || params.size() > 2 )
|
||||
throw runtime_error("tokenbalance tokenid [pubkey]\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
if ( params.size() == 2 )
|
||||
pubkey = ParseHex(params[1].get_str().c_str());
|
||||
else pubkey = Mypubkey();
|
||||
result.push_back(Pair("result", "success"));
|
||||
if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 )
|
||||
result.push_back(Pair("CCaddress",destaddr));
|
||||
balance = GetAssetBalance(pubkey2pk(pubkey),tokenid);
|
||||
result.push_back(Pair("tokenid", params[0].get_str()));
|
||||
result.push_back(Pair("balance", (int64_t)balance));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokencreate(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); std::string name,description,hex; uint64_t supply;
|
||||
if ( fHelp || params.size() > 3 || params.size() < 2 )
|
||||
throw runtime_error("tokencreate name supply description\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
name = params[0].get_str();
|
||||
supply = atof(params[1].get_str().c_str()) * COIN;
|
||||
if ( params.size() == 3 )
|
||||
description = params[2].get_str();
|
||||
hex = CreateAsset(0,supply,name,description);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create transaction"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokentransfer(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); std::string hex; uint64_t amount; uint256 tokenid;
|
||||
if ( fHelp || params.size() != 3 )
|
||||
throw runtime_error("tokentransfer tokenid destpubkey amount\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
std::vector<unsigned char> pubkey(ParseHex(params[1].get_str().c_str()));
|
||||
amount = atol(params[2].get_str().c_str());
|
||||
hex = AssetTransfer(0,tokenid,pubkey,amount);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt transfer assets"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokenbid(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint64_t bidamount,numtokens; std::string hex; double price; uint256 tokenid;
|
||||
if ( fHelp || params.size() != 3 )
|
||||
throw runtime_error("tokenbid numtokens tokenid price\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
numtokens = atoi(params[0].get_str().c_str());
|
||||
tokenid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
price = atof(params[2].get_str().c_str());
|
||||
bidamount = (price * numtokens) * COIN + 0.0000000049999;
|
||||
hex = CreateBuyOffer(0,bidamount,tokenid,numtokens);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create bid"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokencancelbid(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,bidtxid;
|
||||
if ( fHelp || params.size() != 2 )
|
||||
throw runtime_error("tokencancelbid tokenid bidtxid\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
bidtxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
hex = CancelBuyOffer(0,tokenid,bidtxid);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt cancel bid"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokenfillbid(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint64_t fillamount; std::string hex; uint256 tokenid,bidtxid;
|
||||
if ( fHelp || params.size() != 3 )
|
||||
throw runtime_error("tokenfillbid tokenid bidtxid fillamount\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
bidtxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
fillamount = atol(params[2].get_str().c_str());
|
||||
hex = FillBuyOffer(0,tokenid,bidtxid,fillamount);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt fill bid"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokenask(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint64_t askamount,numtokens; std::string hex; double price; uint256 tokenid;
|
||||
if ( fHelp || params.size() != 3 )
|
||||
throw runtime_error("tokenask numtokens tokenid price\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
numtokens = atoi(params[0].get_str().c_str());
|
||||
tokenid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
price = atof(params[2].get_str().c_str());
|
||||
askamount = (price * numtokens) * COIN + 0.0000000049999;
|
||||
hex = CreateSell(0,numtokens,tokenid,askamount);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create ask"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokenswapask(const UniValue& params, bool fHelp)
|
||||
{
|
||||
static uint256 zeroid;
|
||||
UniValue result(UniValue::VOBJ); uint64_t askamount,numtokens; std::string hex; double price; uint256 tokenid,otherid;
|
||||
if ( fHelp || params.size() != 4 )
|
||||
throw runtime_error("tokenswapask numtokens tokenid otherid price\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
numtokens = atoi(params[0].get_str().c_str());
|
||||
tokenid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
otherid = Parseuint256((char *)params[2].get_str().c_str());
|
||||
price = atof(params[3].get_str().c_str());
|
||||
askamount = (price * numtokens);
|
||||
hex = CreateSwap(0,numtokens,tokenid,otherid,askamount);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt create swap"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokencancelask(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); std::string hex; int32_t i; uint256 tokenid,asktxid;
|
||||
if ( fHelp || params.size() != 2 )
|
||||
throw runtime_error("tokencancelask tokenid asktxid\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
asktxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
hex = CancelSell(0,tokenid,asktxid);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt cancel bid"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokenfillask(const UniValue& params, bool fHelp)
|
||||
{
|
||||
static uint256 zeroid;
|
||||
UniValue result(UniValue::VOBJ); uint64_t fillunits; std::string hex; uint256 tokenid,asktxid;
|
||||
if ( fHelp || params.size() != 3 )
|
||||
throw runtime_error("tokenfillask tokenid asktxid fillunits\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
asktxid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
fillunits = atol(params[2].get_str().c_str());
|
||||
hex = FillSell(0,tokenid,zeroid,asktxid,fillunits);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt fill bid"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue tokenfillswap(const UniValue& params, bool fHelp)
|
||||
{
|
||||
static uint256 zeroid;
|
||||
UniValue result(UniValue::VOBJ); uint64_t fillunits; std::string hex; uint256 tokenid,otherid,asktxid;
|
||||
if ( fHelp || params.size() != 4 )
|
||||
throw runtime_error("tokenfillswap tokenid otherid asktxid fillunits\n");
|
||||
if ( ensure_CCrequirements() < 0 )
|
||||
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
otherid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
asktxid = Parseuint256((char *)params[2].get_str().c_str());
|
||||
fillunits = atol(params[3].get_str().c_str());
|
||||
hex = FillSell(0,tokenid,otherid,asktxid,fillunits);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else result.push_back(Pair("error", "couldnt fill bid"));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue getbalance64(const UniValue& params, bool fHelp)
|
||||
{
|
||||
set<CBitcoinAddress> setAddress; vector<COutput> vecOutputs;
|
||||
@@ -4864,3 +5479,5 @@ UniValue getbalance64(const UniValue& params, bool fHelp)
|
||||
ret.push_back(Pair("notstaking", b));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1885,6 +1885,11 @@ void CWallet::ReacceptWalletTransactions()
|
||||
|
||||
bool CWalletTx::RelayWalletTransaction()
|
||||
{
|
||||
if ( pwallet == 0 )
|
||||
{
|
||||
fprintf(stderr,"unexpected null pwallet in RelayWalletTransaction\n");
|
||||
return(false);
|
||||
}
|
||||
assert(pwallet->GetBroadcastTransactions());
|
||||
if (!IsCoinBase())
|
||||
{
|
||||
@@ -2124,9 +2129,12 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
|
||||
}
|
||||
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
|
||||
{
|
||||
CWalletTx& wtx = *item.second;
|
||||
if (wtx.RelayWalletTransaction())
|
||||
result.push_back(wtx.GetHash());
|
||||
if ( item.second != 0 )
|
||||
{
|
||||
CWalletTx &wtx = *item.second;
|
||||
if (wtx.RelayWalletTransaction())
|
||||
result.push_back(wtx.GetHash());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user