@@ -112,17 +112,15 @@ class CryptoconditionsOraclesTest(CryptoconditionsTestFramework):
|
||||
# baton
|
||||
oraclesdata_d = self.send_and_mine(result["hex"], rpc)
|
||||
result = rpc.oraclessamples(globals()["oracle_{}".format("d")], oraclesdata_d, "1")
|
||||
# TODO: working not correct now!
|
||||
#assert_equal("[u'01']", str(result["samples"][0]), "Data match")
|
||||
assert_equal("[u'01']", str(result["samples"][0]), "Data match")
|
||||
|
||||
# D type
|
||||
result = rpc.oraclesdata(globals()["oracle_{}".format("D")], "0101")
|
||||
result = rpc.oraclesdata(globals()["oracle_{}".format("D")], "010001")
|
||||
assert_success(result)
|
||||
# baton
|
||||
oraclesdata_D = self.send_and_mine(result["hex"], rpc)
|
||||
result = rpc.oraclessamples(globals()["oracle_{}".format("D")], oraclesdata_D, "1")
|
||||
# TODO: working not correct now!
|
||||
#assert_equal("[u'01']", str(result["samples"][0]), "Data match")
|
||||
assert_equal("[u'01']", str(result["samples"][0]), "Data match")
|
||||
|
||||
# c type
|
||||
result = rpc.oraclesdata(globals()["oracle_{}".format("c")], "ff")
|
||||
@@ -198,12 +196,12 @@ class CryptoconditionsOraclesTest(CryptoconditionsTestFramework):
|
||||
assert_equal("[u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000']", str(result["samples"][0]), "Data match")
|
||||
|
||||
# Ihh type
|
||||
result = rpc.oraclesdata(globals()["oracle_{}".format("Ihh")], "00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff")
|
||||
result = rpc.oraclesdata(globals()["oracle_{}".format("Ihh")], "ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff")
|
||||
assert_success(result)
|
||||
# baton
|
||||
oraclesdata_Ihh = self.send_and_mine(result["hex"], rpc)
|
||||
result = rpc.oraclessamples(globals()["oracle_{}".format("Ihh")], oraclesdata_Ihh, "1")
|
||||
assert_equal("[u'0']", str(result["samples"][0]), "Data match")
|
||||
assert_equal("[u'4294967295', u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000', u'ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000']", str(result["samples"][0]), "Data match")
|
||||
|
||||
|
||||
def run_test(self):
|
||||
|
||||
@@ -290,6 +290,7 @@ libbitcoin_server_a_SOURCES = \
|
||||
cc/CCcustom.cpp \
|
||||
cc/CCtx.cpp \
|
||||
cc/CCutils.cpp \
|
||||
cc/CCtokens.cpp \
|
||||
cc/assets.cpp \
|
||||
cc/faucet.cpp \
|
||||
cc/rewards.cpp \
|
||||
@@ -383,6 +384,8 @@ libbitcoin_wallet_a_SOURCES = \
|
||||
transaction_builder.cpp \
|
||||
wallet/rpcdisclosure.cpp \
|
||||
wallet/rpcdump.cpp \
|
||||
cc/CCtokens.cpp \
|
||||
cc/CCassetsCore.cpp \
|
||||
cc/CCassetstx.cpp \
|
||||
cc/CCtx.cpp \
|
||||
wallet/rpcwallet.cpp \
|
||||
@@ -568,7 +571,8 @@ komodod_LDADD += \
|
||||
$(LIBBITCOIN_CRYPTO) \
|
||||
$(LIBVERUS_CRYPTO) \
|
||||
$(LIBVERUS_PORTABLE_CRYPTO) \
|
||||
$(LIBZCASH_LIBS)
|
||||
$(LIBZCASH_LIBS) \
|
||||
cclib.so
|
||||
|
||||
if ENABLE_PROTON
|
||||
komodod_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS)
|
||||
|
||||
@@ -18,12 +18,24 @@
|
||||
#define CC_HEIR_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "CCtokens.h"
|
||||
|
||||
#define EVAL_HEIR 0xea
|
||||
//#define EVAL_HEIR 0xea
|
||||
|
||||
bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
|
||||
// CCcustom
|
||||
UniValue HeirInfo();
|
||||
class CoinHelper;
|
||||
class TokenHelper;
|
||||
|
||||
UniValue HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
|
||||
UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
|
||||
UniValue HeirClaimCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount);
|
||||
UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount);
|
||||
|
||||
UniValue HeirInfo(uint256 fundingtxid);
|
||||
UniValue HeirList();
|
||||
//std::string Heir_MakeBadTx(uint256 fundingtxid, uint8_t funcId, int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTime, uint32_t errMask);
|
||||
|
||||
//bool HeirExactTokenAmounts(bool compareTotals, struct CCcontract_info *cpHeir, Eval* eval, uint256 assetid, const CTransaction &tx);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,25 @@
|
||||
#define CC_TRIGGERS_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "../komodo_cJSON.h"
|
||||
|
||||
#define MARMARA_GROUPSIZE 60
|
||||
#define MARMARA_MINLOCK (1440 * 3 * 30)
|
||||
#define MARMARA_MAXLOCK (1440 * 24 * 30)
|
||||
#define MARMARA_VINS 16
|
||||
|
||||
extern uint8_t ASSETCHAINS_MARMARA;
|
||||
uint64_t komodo_block_prg(uint32_t nHeight);
|
||||
int32_t MarmaraGetcreatetxid(uint256 &createtxid,uint256 txid);
|
||||
int32_t MarmaraGetbatontxid(std::vector<uint256> &creditloop,uint256 &batontxid,uint256 txid);
|
||||
UniValue MarmaraCreditloop(uint256 txid);
|
||||
UniValue MarmaraSettlement(uint64_t txfee,uint256 batontxid);
|
||||
UniValue MarmaraLock(uint64_t txfee,int64_t amount,int32_t height);
|
||||
|
||||
UniValue MarmaraPoolPayout(uint64_t txfee,int32_t firstheight,double perc,char *jsonstr); // [[pk0, shares0], [pk1, shares1], ...]
|
||||
UniValue MarmaraReceive(uint64_t txfee,CPubKey senderpk,int64_t amount,std::string currency,int32_t matures,uint256 batontxid,bool automaticflag);
|
||||
UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey receiverpk,int64_t amount,std::string currency,int32_t matures,uint256 approvaltxid,uint256 batontxid);
|
||||
UniValue MarmaraInfo(CPubKey refpk,int32_t firstheight,int32_t lastheight,int64_t minamount,int64_t maxamount,std::string currency);
|
||||
|
||||
bool MarmaraValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@ 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);
|
||||
//CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,std::string name,std::string description);
|
||||
//CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
|
||||
//bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
|
||||
//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
|
||||
bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx);
|
||||
int64_t IsAssetvout(int32_t maxAssetExactAmountDepth, struct CCcontract_info *cp, Eval* eval, int64_t &price,std::vector<uint8_t> &origpubkey,const CTransaction& tx,int32_t v,uint256 refassetid);
|
||||
int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid);
|
||||
bool ValidateBidRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice);
|
||||
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);
|
||||
@@ -44,18 +44,18 @@ bool SetAskFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValu
|
||||
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(int32_t maxDepth, struct CCcontract_info *cp,int64_t &inputs,int32_t starti,int64_t &outputs,Eval* eval,const CTransaction &tx,uint256 assetid);
|
||||
//bool AssetExactAmounts(bool doValidateTx, struct CCcontract_info *cp, int64_t &inputs, int32_t starti, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid, std::vector<CTransaction> &ccVinsTxs);
|
||||
bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, 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);
|
||||
//int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); // --> GetTokenBalance()
|
||||
int64_t AddAssetInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 assetid, int64_t total, int32_t maxinputs);
|
||||
|
||||
UniValue AssetOrders(uint256 tokenid);
|
||||
UniValue 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 AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode);
|
||||
//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 AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode);
|
||||
|
||||
std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal);
|
||||
std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* 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 *
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
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.
|
||||
In ValidateAssetRemainder 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.
|
||||
*/
|
||||
@@ -230,38 +230,43 @@ bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int6
|
||||
return(true);
|
||||
}
|
||||
|
||||
/* use EncodeTokenCreateOpRet instead:
|
||||
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 EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_ASSETS;
|
||||
assetid = revuint256(assetid);
|
||||
switch ( funcid )
|
||||
CScript opret;
|
||||
uint8_t evalcode = EVAL_ASSETS;
|
||||
|
||||
switch ( assetFuncId )
|
||||
{
|
||||
case 't': case 'x': case 'o':
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid);
|
||||
//case 't': this cannot be here
|
||||
case 'x': case 'o':
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << assetFuncId);
|
||||
break;
|
||||
case 's': case 'b': case 'S': case 'B':
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << price << origpubkey);
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << assetFuncId << price << origpubkey);
|
||||
break;
|
||||
case 'E': case 'e':
|
||||
assetid2 = revuint256(assetid2);
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << assetid2 << price << origpubkey);
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << assetFuncId << assetid2 << price << origpubkey);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"EncodeOpRet: illegal funcid.%02x\n",funcid);
|
||||
fprintf(stderr,"EncodeAssetOpRet: illegal funcid.%02x\n", assetFuncId);
|
||||
opret << OP_RETURN;
|
||||
break;
|
||||
}
|
||||
return(opret);
|
||||
}
|
||||
|
||||
bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description)
|
||||
/* it is for compatibility, do not use this for new contracts (use DecodeTokenCreateOpRet)
|
||||
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);
|
||||
@@ -272,173 +277,187 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &or
|
||||
return(true);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
} */
|
||||
|
||||
uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector<uint8_t> &origpubkey)
|
||||
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, 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);
|
||||
std::vector<uint8_t> vopretExtra, vopretStripped;
|
||||
uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyAssetFuncId;
|
||||
uint256 dummyTokenid;
|
||||
std::vector<CPubKey> voutPubkeysDummy;
|
||||
|
||||
tokenid = zeroid;
|
||||
assetid2 = zeroid;
|
||||
price = 0;
|
||||
|
||||
// First - decode token opret:
|
||||
funcId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra);
|
||||
|
||||
/*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 )
|
||||
if (script == 0) {
|
||||
std::cerr << "DecodeAssetOpRet() script is empty" << std::endl;
|
||||
return (uint8_t)0;
|
||||
}*/
|
||||
//bool isEof = true; // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set!
|
||||
//bool result = E_UNMARSHAL(vopret, ss >> evalCodeInOpret; ss >> funcId; ss >> tokenid; ss >> assetFuncId; isEof = ss.eof());
|
||||
|
||||
if (funcId == 0 || vopretExtra.size() < 2) {
|
||||
std::cerr << "DecodeAssetOpRet() incorrect opret or no asset's payload" << " funcId=" << (int)funcId << " vopretExtra.size()=" << vopretExtra.size() << std::endl;
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size
|
||||
std::cerr << "DecodeAssetTokenOpRet() could not unmarshal vopretStripped" << std::endl;
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
////tokenid = revuint256(tokenid); already done in DecodeToken!
|
||||
evalCodeInOpret = vopretStripped.begin()[0];
|
||||
assetFuncId = vopretStripped.begin()[1];
|
||||
|
||||
//std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl;
|
||||
|
||||
if(evalCodeInOpret == EVAL_ASSETS)
|
||||
{
|
||||
//fprintf(stderr,"decode.[%c] assetFuncId.[%c]\n", funcId, assetFuncId);
|
||||
switch( assetFuncId )
|
||||
{
|
||||
case 'c': return(funcid);
|
||||
break;
|
||||
case 't': case 'x': case 'o':
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid) != 0 )
|
||||
case 'x': case 'o':
|
||||
if (vopretStripped.size() == 2) // no data after 'evalcode assetFuncId' allowed
|
||||
{
|
||||
assetid = revuint256(assetid);
|
||||
return(funcid);
|
||||
return(assetFuncId);
|
||||
}
|
||||
break;
|
||||
case 's': case 'b': case 'S': case 'B':
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> price; ss >> origpubkey) != 0 )
|
||||
if (E_UNMARSHAL(vopretStripped, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0)
|
||||
{
|
||||
assetid = revuint256(assetid);
|
||||
//fprintf(stderr,"got price %llu\n",(long long)price);
|
||||
return(funcid);
|
||||
//fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price);
|
||||
return(assetFuncId);
|
||||
}
|
||||
break;
|
||||
case 'E': case 'e':
|
||||
if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 )
|
||||
if ( E_UNMARSHAL(vopretStripped, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 )
|
||||
{
|
||||
//fprintf(stderr,"got price %llu\n",(long long)price);
|
||||
assetid = revuint256(assetid);
|
||||
//fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price);
|
||||
assetid2 = revuint256(assetid2);
|
||||
return(funcid);
|
||||
return(assetFuncId);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"DecodeAssetOpRet: illegal funcid.%02x\n",funcid);
|
||||
funcid = 0;
|
||||
fprintf(stderr,"DecodeAssetTokenOpRet: illegal assetFuncId.%02x\n", assetFuncId);
|
||||
//funcId = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(funcid);
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// extract sell/buy owner's pubkey from the opret
|
||||
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 )
|
||||
uint8_t evalCode;
|
||||
if ( tx.vout.size() > 0 && DecodeAssetTokenOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey) != 0 )
|
||||
return(true);
|
||||
else return(false);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,const CTransaction& tx)
|
||||
|
||||
// Calculate sell/buy owner's source token/asset address from ask/bid tx
|
||||
bool GetAssetorigaddrs(struct CCcontract_info *cp, char *userCCaddr, char *destaddr, const CTransaction& tx)
|
||||
{
|
||||
uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector<uint8_t> origpubkey; CScript script;
|
||||
uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
CScript script;
|
||||
uint8_t evalCode;
|
||||
|
||||
n = tx.vout.size();
|
||||
if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
|
||||
if( n == 0 || (funcid = DecodeAssetTokenOpRet(tx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 )
|
||||
return(false);
|
||||
if ( GetCCaddress(cp,CCaddr,pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr,CScript() << origpubkey << OP_CHECKSIG) != 0 )
|
||||
|
||||
bool bGetCCaddr = false;
|
||||
if (funcid == 's' || funcid == 'S') {
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
bGetCCaddr = GetCCaddress(cpTokens, userCCaddr, pubkey2pk(origpubkey));
|
||||
//bGetCCaddr = GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey));
|
||||
}
|
||||
else if (funcid == 'b' || funcid == 'B') {
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
bGetCCaddr = GetCCaddress(cpTokens, userCCaddr, pubkey2pk(origpubkey));
|
||||
}
|
||||
else {
|
||||
std::cerr << "GetAssetorigaddrs incorrect funcid=" << (char)(funcid?funcid:' ') << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( bGetCCaddr && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG))
|
||||
return(true);
|
||||
else return(false);
|
||||
else
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
// Checks if the vout is a really Asset CC vout
|
||||
// if maxAssetExactAmountDepth > 0, it also validates the vin transaction itself:
|
||||
// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx
|
||||
int64_t IsAssetvout(int32_t maxAssetExactAmountDepth, struct CCcontract_info *cp, Eval* eval, 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?
|
||||
{
|
||||
|
||||
if (maxAssetExactAmountDepth > 0) {
|
||||
//validate all tx
|
||||
int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0;
|
||||
std::vector<CTransaction> ccVinsTxs;
|
||||
|
||||
//std::cerr << "IsAssetvout() validate=yes" << std::endl;
|
||||
const bool validateVinTxs = false;
|
||||
bool isEqualAmounts = AssetExactAmounts(maxAssetExactAmountDepth, cp, myCCVinsAmount, 0, myCCVoutsAmount, eval, tx, refassetid);
|
||||
|
||||
// if ccInputs != ccOutputs and it is not the tokenbase tx means it is possibly fake tx (dimxy):
|
||||
if (!isEqualAmounts && refassetid != tx.GetHash()) { // checking that this is the true tokenbase tx, by verifying that funcid=c, is done further in this function (dimxy)
|
||||
std::cerr << "IsAssetvout() detected bad tx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs and not the 'tokenbase' tx" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
n = tx.vout.size();
|
||||
if (v >= n - 1) { // just moved this up (dimxy)
|
||||
std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl;
|
||||
return(0);
|
||||
}
|
||||
nValue = tx.vout[v].nValue;
|
||||
|
||||
// fprintf(stderr,"IsAssetvout() CC vout v.%d of n=%d amount=%.8f\n",v,n,(double)nValue/COIN);
|
||||
|
||||
if ( (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 )
|
||||
{
|
||||
fprintf(stderr,"IsAssetvout() null decodeopret v.%d\n",v);
|
||||
return(0);
|
||||
}
|
||||
else if ( funcid == 'c' )
|
||||
{
|
||||
if (refassetid == tx.GetHash() && v == 0) {
|
||||
std::cerr << "isAssetVout() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " returning nValue=" << nValue << std::endl;
|
||||
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 )
|
||||
{
|
||||
fprintf(stderr,"IsAssetvout() returning %.8f\n",(double)nValue/COIN);
|
||||
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];
|
||||
uint256 hashBlock;
|
||||
uint256 assetid, assetid2;
|
||||
int64_t tmpprice;
|
||||
std::vector<uint8_t> tmporigpubkey;
|
||||
uint8_t evalCode;
|
||||
|
||||
char destaddr[64], unspendableAddr[64];
|
||||
|
||||
origaddr[0] = destaddr[0] = CCaddr[0] = 0;
|
||||
if ( tx.vin.size() < 2 )
|
||||
|
||||
uint8_t funcid = 0;
|
||||
if (tx.vout.size() > 0) {
|
||||
uint256 assetid, assetid2;
|
||||
int64_t tmpprice;
|
||||
std::vector<uint8_t> tmporigpubkey;
|
||||
uint8_t evalCode;
|
||||
funcid = DecodeAssetTokenOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey);
|
||||
}
|
||||
|
||||
if( tx.vin.size() < 2 )
|
||||
return eval->Invalid("not enough for CC vins");
|
||||
else if ( tx.vin[vini].prevout.n != 0 )
|
||||
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 )
|
||||
else if( eval->GetTxUnconfirmed(tx.vin[vini].prevout.hash, vinTx,hashBlock) == 0 )
|
||||
{
|
||||
int32_t z;
|
||||
/* 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);
|
||||
fprintf(stderr," vini.%d\n",vini); */
|
||||
std::cerr << "AssetValidateCCvin cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl;
|
||||
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 )
|
||||
// if fillSell or cancelSell --> to spend tokens from dual-eval token-assets unspendable addr
|
||||
else if( (funcid == 'S' || funcid == 'x') &&
|
||||
(Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ||
|
||||
!GetTokensCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) ||
|
||||
strcmp(destaddr, unspendableAddr) != 0))
|
||||
{
|
||||
fprintf(stderr,"%s vs %s\n",destaddr,(char *)cp->unspendableCCaddr);
|
||||
fprintf(stderr,"AssetValidateCCvin cc addr %s is not dual token-evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
|
||||
return eval->Invalid("invalid vin AssetsCCaddr");
|
||||
}
|
||||
// if fillBuy or cancelBuy --> to spend coins from asset unspendable addr
|
||||
else if ((funcid == 'B' || funcid == 'o') &&
|
||||
(Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ||
|
||||
!GetCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) ||
|
||||
strcmp(destaddr, unspendableAddr) != 0))
|
||||
{
|
||||
fprintf(stderr, "AssetValidateCCvin cc addr %s is not evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
|
||||
return eval->Invalid("invalid vin AssetsCCaddr");
|
||||
}
|
||||
|
||||
//else if ( vinTx.vout[0].nValue < 10000 )
|
||||
// return eval->Invalid("invalid dust for buyvin");
|
||||
else if ( GetAssetorigaddrs(cp,CCaddr,origaddr,vinTx) == 0 )
|
||||
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);
|
||||
fprintf(stderr,"AssetValidateCCvin got %.8f to origaddr.(%s)\n",(double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr);
|
||||
if ( vinTx.vout[0].nValue == 0 )
|
||||
return eval->Invalid("null value CCvin");
|
||||
return(vinTx.vout[0].nValue);
|
||||
@@ -446,16 +465,21 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch
|
||||
|
||||
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;
|
||||
CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid, evalCode;
|
||||
CCaddr[0] = origaddr[0] = 0;
|
||||
if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 )
|
||||
return(0);
|
||||
|
||||
// validate locked coins on Assets vin[1]
|
||||
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 if ((funcid = DecodeAssetTokenOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' &&
|
||||
vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) // marker is only in 'b'?
|
||||
return eval->Invalid("invalid normal vout1 for buyvin");
|
||||
else
|
||||
{
|
||||
//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' )
|
||||
if ( vinTx.vout.size() > 0 && funcid != 'b' && funcid != 'B' )
|
||||
return eval->Invalid("invalid opreturn for buyvin");
|
||||
else if ( refassetid != assetid )
|
||||
return eval->Invalid("invalid assetid for buyvin");
|
||||
@@ -469,88 +493,162 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr
|
||||
int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid)
|
||||
{
|
||||
CTransaction vinTx; int64_t nValue,assetoshis;
|
||||
fprintf(stderr,"AssetValidateSellvin\n");
|
||||
if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 )
|
||||
//fprintf(stderr,"AssetValidateSellvin\n");
|
||||
if ( (nValue = AssetValidateCCvin(cp, eval, CCaddr, origaddr, tx, 1, vinTx)) == 0 )
|
||||
return(0);
|
||||
if ( (assetoshis= IsAssetvout(1, cp, NULL, tmpprice,tmporigpubkey,vinTx,0,assetid)) == 0 )
|
||||
if ( (assetoshis= IsAssetvout(cp, tmpprice, tmporigpubkey, vinTx, 0, assetid)) == 0 )
|
||||
return eval->Invalid("invalid missing CC vout0 for sellvin");
|
||||
else return(assetoshis);
|
||||
else
|
||||
return(assetoshis);
|
||||
}
|
||||
|
||||
|
||||
// overload with additional params for deep tx validation (dimxy)
|
||||
bool AssetExactAmounts(int maxDepth, struct CCcontract_info *cp, int64_t &inputs, int32_t starti, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid)
|
||||
// validates opret for asset tx:
|
||||
bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &price, std::vector<uint8_t> &origpubkey) {
|
||||
|
||||
uint256 assetidOpret, assetidOpret2;
|
||||
uint8_t funcid, evalCode;
|
||||
|
||||
// this is just for log messages indentation fur debugging recursive calls:
|
||||
int32_t n = tx.vout.size();
|
||||
|
||||
if ((funcid = DecodeAssetTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, assetidOpret, assetidOpret2, price, origpubkey)) == 0)
|
||||
{
|
||||
std::cerr << "ValidateAssetOpret() DecodeAssetTokenOpRet returned null for the opret for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
return(false);
|
||||
}
|
||||
/* it is now on token level:
|
||||
else if (funcid == 'c')
|
||||
{
|
||||
if (assetid != zeroid && assetid == tx.GetHash() && v == 0) {
|
||||
//std::cerr << "ValidateAssetOpret() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
else if (funcid == 't') // TODO: check if this new block does not influence IsAssetVout
|
||||
{
|
||||
//std::cerr << "ValidateAssetOpret() assetid=" << assetid.GetHex() << " assetIdOpret=" << assetidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
if (assetid != zeroid && assetid == assetidOpret) {
|
||||
//std::cerr << "ValidateAssetOpret() this is a transfer 't' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl;
|
||||
return(true);
|
||||
}
|
||||
} */
|
||||
//else if ((funcid == 'b' || funcid == 'B') && v == 0) // critical! 'b'/'B' vout0 is NOT asset
|
||||
// return(false);
|
||||
else if (funcid != 'E')
|
||||
{
|
||||
if (assetid != zeroid && assetidOpret == assetid)
|
||||
{
|
||||
//std::cerr << "ValidateAssetOpret() returns true for not 'E', funcid=" << (char)funcid << std::endl;
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
else if (funcid == 'E') // NOTE: not implemented yet!
|
||||
{
|
||||
if (v < 2 && assetid != zeroid && assetidOpret == assetid)
|
||||
return(true);
|
||||
else if (v == 2 && assetid != zeroid && assetidOpret2 == assetid)
|
||||
return(true);
|
||||
}
|
||||
|
||||
//std::cerr << "ValidateAssetOpret() return false funcid=" << (char)funcid << " assetid=" << assetid.GetHex() << " assetIdOpret=" << assetidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks if the vout is a really Asset CC vout
|
||||
// compareTotals == true, the func also validates the passed transaction itself:
|
||||
// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx
|
||||
int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid)
|
||||
{
|
||||
CTransaction vinTx; uint256 hashBlock,id,id2; int32_t i,flag,numvins,numvouts; int64_t assetoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
inputs = outputs = 0;
|
||||
|
||||
maxDepth--;
|
||||
//std::cerr << "IsAssetvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for assetid=" << refassetid.GetHex() << std::endl;
|
||||
|
||||
for (i=starti; i<numvins; i++)
|
||||
{
|
||||
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
|
||||
{
|
||||
//std::cerr << "AssetExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl;
|
||||
// we are really not inside validation! -- dimxy
|
||||
if ( (eval && eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0) || (!eval && !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock)) )
|
||||
{
|
||||
fprintf(stderr,"AssetExactAmounts() cannot read vintx i.%d starti.%d numvins.%d\n", i,starti,numvins);
|
||||
return (!eval) ? false : eval->Invalid("always should find vin, but didnt");
|
||||
if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here
|
||||
{
|
||||
int32_t n = tx.vout.size();
|
||||
// just check boundaries:
|
||||
if (v >= n - 1) { // just moved this up (dimxy)
|
||||
std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl;
|
||||
return(0);
|
||||
}
|
||||
|
||||
} // false means 'don't go deeper' -- dimxy
|
||||
else if ( (assetoshis= IsAssetvout( maxDepth, cp, eval, tmpprice,tmporigpubkey,vinTx,tx.vin[i].prevout.n,assetid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"AssetExactAmounts() vin%d %llu, ",i,(long long)assetoshis);
|
||||
inputs += assetoshis;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( vinTx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 && DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid )
|
||||
{
|
||||
assetoshis = vinTx.vout[i].nValue;
|
||||
fprintf(stderr,"AssetExactAmounts() vin%d assetoshis=%llu special case, ",i,(long long)assetoshis);
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// moved opret checking to this new reusable func (dimxy):
|
||||
const bool valOpret = ValidateAssetOpret(tx, v, refassetid, price, origpubkey);
|
||||
//std::cerr << "IsAssetvout() ValidateAssetOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for assetid=" << refassetid.GetHex() << std::endl;
|
||||
if (valOpret) {
|
||||
//std::cerr << "IsAssetvout() ValidateAssetOpret returned true, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for assetid=" << refassetid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
|
||||
//fprintf(stderr,"IsAssetvout() CC vout v.%d of n=%d amount=%.8f txid=%s\n",v,n,(double)0/COIN, tx.GetHash().GetHex().c_str());
|
||||
}
|
||||
//fprintf(stderr,"IsAssetvout() normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if ( DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid )
|
||||
flag = 1;
|
||||
else flag = 0;
|
||||
// sets cc inputs vs cc outputs and ensures they are equal:
|
||||
bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid)
|
||||
{
|
||||
CTransaction vinTx; uint256 hashBlock, id, id2; int32_t flag; int64_t assetoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
|
||||
int32_t numvins = tx.vin.size();
|
||||
int32_t numvouts = tx.vout.size();
|
||||
inputs = outputs = 0;
|
||||
|
||||
for (i=0; i<numvouts; i++)
|
||||
{ // 'false' means 'dont go deep' -- dimxy
|
||||
if ( (assetoshis= IsAssetvout(maxDepth, cp, eval, tmpprice,tmporigpubkey,tx,i,assetid)) != 0 )
|
||||
{
|
||||
fprintf(stderr,"AssetExactAmounts() vout%d assetoshis=%llu, ",i,(long long)assetoshis);
|
||||
outputs += assetoshis;
|
||||
}
|
||||
// Note: account it only if this is 'transfer' tx -- dimxy
|
||||
else if ( flag != 0 && tx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
assetoshis = tx.vout[i].nValue;
|
||||
fprintf(stderr,"AssetExactAmounts() vout%d assetoshis=%llu special case, ",i,(long long)assetoshis);
|
||||
outputs += assetoshis;
|
||||
}
|
||||
}
|
||||
struct CCcontract_info *cpTokens, C;
|
||||
|
||||
//std::cerr << "AssetExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
cpTokens = CCinit(&C, EVAL_TOKENS);
|
||||
|
||||
if ( inputs != outputs )
|
||||
{
|
||||
std::cerr << "AssetExactAmounts() incorrect inputs=" << (double)inputs / COIN << " vs outputs=" << (double)outputs/COIN << " for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
return(false);
|
||||
}
|
||||
else return(true);
|
||||
for (int32_t i = 0; i<numvins; i++)
|
||||
{ // only tokens are relevant!!
|
||||
if (/*(*cpAssets->ismyvin)(tx.vin[i].scriptSig)*/ (*cpTokens->ismyvin)(tx.vin[i].scriptSig) ) // || IsVinAllowed(tx.vin[i].scriptSig) != 0)
|
||||
{
|
||||
//std::cerr << indentStr << "AssetExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl;
|
||||
// we are not inside the validation code -- dimxy
|
||||
if ((eval && eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock) == 0) || (!eval && !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock)))
|
||||
{
|
||||
std::cerr << "AssetCalcAmounts() cannot read vintx for i." << i << " numvins." << numvins << std::endl;
|
||||
return (!eval) ? false : eval->Invalid("always should find vin tx, but didnt");
|
||||
}
|
||||
else {
|
||||
// validate vouts of vintx
|
||||
//std::cerr << indentStr << "AssetExactAmounts() check vin i=" << i << " nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl;
|
||||
//assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, vinTx, tx.vin[i].prevout.n, assetid);
|
||||
std::vector<uint8_t> vopretExtra;
|
||||
std::vector<CPubKey> vinPubkeysEmpty;
|
||||
|
||||
// TODO: maybe we do not need call to IsTokensVout here, cause we've already selected token vins
|
||||
assetoshis = IsTokensvout(false, false, cpTokens, NULL, vinTx, tx.vin[i].prevout.n, assetid);
|
||||
if (assetoshis != 0)
|
||||
{
|
||||
std::cerr << "AssetCalcAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl;
|
||||
inputs += assetoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < numvouts; i++)
|
||||
{
|
||||
// Note: we pass in here 'false' because we don't need to call AssetExactAmounts() recursively from IsAssetvout
|
||||
// indeed, in this case we'll be checking this tx again
|
||||
assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, tx, i, assetid);
|
||||
|
||||
if (assetoshis != 0)
|
||||
{
|
||||
std::cerr << "AssetCalcAmounts() vout i=" << i << " assetoshis=" << assetoshis << std::endl;
|
||||
outputs += assetoshis;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << "AssetCalcAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
|
||||
/* we do not verify inputs == outputs here,
|
||||
it's done in Tokens:
|
||||
if (inputs != outputs) {
|
||||
if (tx.GetHash() != assetid) {
|
||||
std::cerr << "AssetCalcAmounts() unequal inputs=" << inputs << " vs outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
return (!eval) ? false : eval->Invalid("assets cc inputs != cc outputs");
|
||||
}
|
||||
} */
|
||||
return(true);
|
||||
}
|
||||
|
||||
// overload for existing calls of this function (dimxy)
|
||||
/*bool AssetExactAmounts(struct CCcontract_info *cp, int64_t &inputs, int32_t starti, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid) {
|
||||
std::vector<CTransaction> ccVinsTxs;
|
||||
|
||||
return AssetExactAmounts(true, cp, inputs, starti, outputs, eval, tx, assetid);
|
||||
}*/
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "CCassets.h"
|
||||
//#include "CCtokens.h"
|
||||
|
||||
|
||||
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs)
|
||||
{
|
||||
@@ -21,25 +23,31 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
threshold = total/(maxinputs!=0?maxinputs:64);
|
||||
|
||||
threshold = total/(maxinputs!=0?maxinputs:64); // TODO: is maxinputs really not over 64, what if i want to calc total balance?
|
||||
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
vout = (int32_t)it->first.index;
|
||||
if ( it->second.satoshis < threshold )
|
||||
|
||||
if (it->second.satoshis < threshold)
|
||||
continue;
|
||||
|
||||
for (j=0; j<mtx.vin.size(); j++)
|
||||
if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
|
||||
if (txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n)
|
||||
break;
|
||||
if ( j != mtx.vin.size() )
|
||||
|
||||
if( j != mtx.vin.size() )
|
||||
continue;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
|
||||
if( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
Getscriptaddress(destaddr,vintx.vout[vout].scriptPubKey);
|
||||
if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
|
||||
if( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
|
||||
continue;
|
||||
fprintf(stderr,"AddAssetInputs() check destaddress=%s vout amount=%.8f\n",destaddr,(double)vintx.vout[vout].nValue/COIN);
|
||||
if ( (nValue= IsAssetvout(1, cp, NULL, price,origpubkey,vintx,vout,assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
if( (nValue = IsAssetvout(cp, price, origpubkey, vintx, vout, assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
{
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
|
||||
@@ -57,72 +65,37 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
int64_t GetAssetBalance(CPubKey pk,uint256 tokenid)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
return(AddAssetInputs(cp,mtx,pk,tokenid,0,0));
|
||||
}
|
||||
|
||||
UniValue AssetInfo(uint256 assetid)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description; char str[67],numstr[65];
|
||||
if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
|
||||
{
|
||||
fprintf(stderr,"cant find assetid\n");
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","cant find assetid"));
|
||||
return(result);
|
||||
}
|
||||
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 )
|
||||
{
|
||||
fprintf(stderr,"assetid isnt assetcreation txid\n");
|
||||
result.push_back(Pair("result","error"));
|
||||
result.push_back(Pair("error","assetid isnt assetcreation txid"));
|
||||
}
|
||||
result.push_back(Pair("result","success"));
|
||||
result.push_back(Pair("tokenid",uint256_str(str,assetid)));
|
||||
result.push_back(Pair("owner",pubkey33_str(str,origpubkey.data())));
|
||||
result.push_back(Pair("name",name));
|
||||
result.push_back(Pair("supply",vintx.vout[0].nValue));
|
||||
result.push_back(Pair("description",description));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue AssetList()
|
||||
{
|
||||
UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name,description; char str[65];
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
SetCCtxids(addressIndex,cp->normaladdr);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
{
|
||||
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) != 0 )
|
||||
{
|
||||
result.push_back(uint256_str(str,txid));
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue AssetOrders(uint256 refassetid)
|
||||
{
|
||||
static uint256 zero;
|
||||
int64_t price; uint256 txid,hashBlock,assetid,assetid2; std::vector<uint8_t> origpubkey; CTransaction vintx; UniValue result(UniValue::VARR); std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; uint8_t funcid; char numstr[32],funcidstr[16],origaddr[64],assetidstr[65]; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
SetCCunspents(unspentOutputs,(char *)cp->unspendableCCaddr);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
UniValue result(UniValue::VARR);
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputsTokens, unspentOutputsAssets;
|
||||
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
struct CCcontract_info *cpAssets, assetsC;
|
||||
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
|
||||
auto addOrders = [&](struct CCcontract_info *cp, std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it)
|
||||
{
|
||||
uint256 txid, hashBlock, assetid, assetid2;
|
||||
int64_t price;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
CTransaction vintx;
|
||||
uint8_t funcid, evalCode;
|
||||
char numstr[32], funcidstr[16], origaddr[64], assetidstr[65];
|
||||
|
||||
txid = it->first.txhash;
|
||||
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
|
||||
//std::cerr << "addOrders() txid=" << txid.GetHex() << std::endl;
|
||||
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 )
|
||||
// for logging: funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey);
|
||||
//std::cerr << "addOrders() vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl;
|
||||
if (vintx.vout.size() > 0 && (funcid = DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0)
|
||||
{
|
||||
if ( refassetid != zero && assetid != refassetid )
|
||||
if (refassetid != zero && assetid != refassetid)
|
||||
{
|
||||
//int32_t z;
|
||||
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&txid)[z]);
|
||||
@@ -131,11 +104,15 @@ UniValue AssetOrders(uint256 refassetid)
|
||||
//fprintf(stderr," assetid\n");
|
||||
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&refassetid)[z]);
|
||||
//fprintf(stderr," refassetid\n");
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
if ( vintx.vout[it->first.index].nValue == 0 )
|
||||
continue;
|
||||
|
||||
//std::cerr << "addOrders() it->first.index=" << it->first.index << " vintx.vout[it->first.index].nValue=" << vintx.vout[it->first.index].nValue << std::endl;
|
||||
if (vintx.vout[it->first.index].nValue == 0)
|
||||
return;
|
||||
|
||||
UniValue item(UniValue::VOBJ);
|
||||
|
||||
funcidstr[0] = funcid;
|
||||
funcidstr[1] = 0;
|
||||
item.push_back(Pair("funcid", funcidstr));
|
||||
@@ -157,8 +134,8 @@ UniValue AssetOrders(uint256 refassetid)
|
||||
}
|
||||
if ( origpubkey.size() == 33 )
|
||||
{
|
||||
GetCCaddress(cp,origaddr,pubkey2pk(origpubkey));
|
||||
item.push_back(Pair("origaddress",origaddr));
|
||||
GetCCaddress(cp, origaddr, pubkey2pk(origpubkey)); // TODO: what is this? is it asset or token??
|
||||
item.push_back(Pair("origaddress", origaddr));
|
||||
}
|
||||
if ( assetid != zeroid )
|
||||
item.push_back(Pair("tokenid",uint256_str(assetidstr,assetid)));
|
||||
@@ -181,14 +158,35 @@ UniValue AssetOrders(uint256 refassetid)
|
||||
}
|
||||
}
|
||||
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);
|
||||
//fprintf(stderr,"addOrders() func.(%c) %s/v%d %.8f\n",funcid,uint256_str(assetidstr,txid),(int32_t)it->first.index,(double)vintx.vout[it->first.index].nValue/COIN);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
char assetsUnspendableAddr[64];
|
||||
GetCCaddress(cpAssets, assetsUnspendableAddr, GetUnspendable(cpAssets, NULL));
|
||||
SetCCunspents(unspentOutputsAssets, assetsUnspendableAddr /*(char *)cpTokens->unspendableCCaddr*/);
|
||||
|
||||
char tokensUnspendableAddr[64];
|
||||
GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
|
||||
SetCCunspents(unspentOutputsAssets, tokensUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/);
|
||||
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itTokens = unspentOutputsTokens.begin();
|
||||
itTokens != unspentOutputsTokens.end();
|
||||
itTokens++)
|
||||
addOrders(cpTokens, itTokens);
|
||||
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itAssets = unspentOutputsAssets.begin();
|
||||
itAssets != unspentOutputsAssets.end();
|
||||
itAssets++)
|
||||
addOrders(cpAssets, itAssets);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description)
|
||||
// not used (use TokenCreate instead)
|
||||
/* std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; struct CCcontract_info *cp,C;
|
||||
@@ -213,9 +211,10 @@ std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetCreateOpRet('c',Mypubkey(),name,description)));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total)
|
||||
} */
|
||||
|
||||
// not used (use TokenTransfer instead)
|
||||
/* std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; uint64_t mask; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
|
||||
@@ -230,11 +229,11 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> des
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
{
|
||||
/*n = outputs.size();
|
||||
if ( n == amounts.size() )
|
||||
{
|
||||
for (i=0; i<n; i++)
|
||||
total += amounts[i];*/
|
||||
//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 )
|
||||
{
|
||||
@@ -254,9 +253,10 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector<uint8_t> des
|
||||
//} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
|
||||
}
|
||||
return("");
|
||||
}
|
||||
} */
|
||||
|
||||
std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode)
|
||||
// deprecated
|
||||
/* std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> destpubkey,int64_t total,int32_t evalcode)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C;
|
||||
@@ -281,76 +281,121 @@ std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector<uint8_t> dest
|
||||
} else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN);
|
||||
}
|
||||
return("");
|
||||
}
|
||||
} */
|
||||
|
||||
std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal)
|
||||
// rpc tokenbid implementation, locks 'bidamount' coins for the 'pricetotal' of tokens
|
||||
std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, int64_t pricetotal)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
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 )
|
||||
CPubKey mypk;
|
||||
struct CCcontract_info *cpAssets, C;
|
||||
uint256 hashBlock;
|
||||
CTransaction vintx;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
std::string name,description;
|
||||
int64_t inputs;
|
||||
|
||||
std::cerr << "CreateBuyOffer() bidamount=" << bidamount << " numtokens(pricetotal)=" << pricetotal << std::endl;
|
||||
|
||||
if (bidamount < 0 || pricetotal < 0)
|
||||
{
|
||||
fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n",(long long)bidamount,(long long)pricetotal);
|
||||
fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n", (long long)bidamount, (long long)pricetotal);
|
||||
return("");
|
||||
}
|
||||
if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 )
|
||||
if (GetTransaction(assetid, vintx, hashBlock, false) == 0)
|
||||
{
|
||||
fprintf(stderr,"cant find assetid\n");
|
||||
return("");
|
||||
}
|
||||
if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 )
|
||||
if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, origpubkey, name, description) == 0)
|
||||
{
|
||||
fprintf(stderr,"assetid isnt assetcreation txid\n");
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
|
||||
cpAssets = CCinit(&C,EVAL_ASSETS); // NOTE: assets here!
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,bidamount+txfee,64) > 0 )
|
||||
|
||||
if ((inputs = AddNormalinputs(mtx, mypk, bidamount+(2*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())));
|
||||
std::cerr << "CreateBuyOffer() inputs=" << inputs << std::endl;
|
||||
if (inputs < bidamount+txfee) {
|
||||
std::cerr << "CreateBuyOffer(): insufficient coins to make buy offer" << std::endl;
|
||||
CCerror = strprintf("insufficient coins to make buy offer");
|
||||
return ("");
|
||||
}
|
||||
|
||||
CPubKey unspendablePubkey = GetUnspendable(cpAssets, 0);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, unspendablePubkey));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk));
|
||||
std::vector<CPubKey> voutTokenPubkeys; // should be empty - no token vouts
|
||||
|
||||
return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet('b', zeroid, pricetotal, Mypubkey()))));
|
||||
}
|
||||
CCerror = strprintf("no coins found to make buy offer");
|
||||
return("");
|
||||
}
|
||||
|
||||
// rpc tokenask implementation, locks 'askamount' tokens for the 'pricetotal'
|
||||
std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
|
||||
CPubKey mypk;
|
||||
uint64_t mask;
|
||||
int64_t inputs, CCchange;
|
||||
CScript opret;
|
||||
struct CCcontract_info *cpAssets, assetsC;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
|
||||
//std::cerr << "CreateSell() askamount=" << askamount << " pricetotal=" << pricetotal << std::endl;
|
||||
|
||||
if ( askamount < 0 || pricetotal < 0 )
|
||||
{
|
||||
if (askamount < 0 || pricetotal < 0) {
|
||||
fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS); // NOTE: this is for signing
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
|
||||
// add single-eval tokens:
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS); // NOTE: tokens is here
|
||||
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, askamount, 60)) > 0)
|
||||
{
|
||||
if (inputs < askamount) {
|
||||
//askamount = inputs;
|
||||
//was: askamount = inputs;
|
||||
std::cerr << "CreateSell(): insufficient tokens for ask" << std::endl;
|
||||
CCerror = strprintf("insufficient tokens for ask");
|
||||
return ("");
|
||||
}
|
||||
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
|
||||
if ( inputs > askamount )
|
||||
CPubKey unspendablePubkey = GetUnspendable(cpAssets, NULL);
|
||||
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, askamount, unspendablePubkey));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); //marker
|
||||
if (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));
|
||||
if (CCchange != 0)
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // change to single-eval token vout
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(unspendablePubkey);
|
||||
|
||||
opret = EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey()));
|
||||
return(FinalizeCCTx(mask,cpAssets, mtx, mypk, txfee, opret));
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "need some assets to place ask\n");
|
||||
fprintf(stderr, "need some tokens to place ask\n");
|
||||
}
|
||||
}
|
||||
else { // dimxy added 'else', because it was misleading message before
|
||||
@@ -359,39 +404,62 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
|
||||
return("");
|
||||
}
|
||||
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C;
|
||||
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
fprintf(stderr,"asset swaps disabled\n");
|
||||
return("");
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
|
||||
if ( askamount < 0 || pricetotal < 0 )
|
||||
{
|
||||
fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
cp = CCinit(&C, EVAL_ASSETS);
|
||||
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 )
|
||||
if ((inputs = AddAssetInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0)
|
||||
{
|
||||
if ( inputs < askamount )
|
||||
askamount = inputs;
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0)));
|
||||
if ( inputs > askamount )
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
if (inputs < askamount) {
|
||||
//was: askamount = inputs;
|
||||
std::cerr << "CreateSwap(): insufficient tokens for ask" << std::endl;
|
||||
CCerror = strprintf("insufficient tokens for ask");
|
||||
return ("");
|
||||
}
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
CPubKey unspendablePubkey = GetUnspendable(cp, 0);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, askamount, unspendablePubkey));
|
||||
|
||||
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());
|
||||
if (CCchange != 0)
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk));
|
||||
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
std::vector<CPubKey> voutTokenPubkeys; // should be empty - no token vouts
|
||||
|
||||
if (assetid2 == zeroid) {
|
||||
opret = EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey()));
|
||||
}
|
||||
else {
|
||||
opret = EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet('e', assetid2, pricetotal, Mypubkey()));
|
||||
}
|
||||
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
|
||||
}
|
||||
else {
|
||||
@@ -403,148 +471,306 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
|
||||
}
|
||||
|
||||
return("");
|
||||
}
|
||||
} ////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
|
||||
|
||||
// unlocks coins
|
||||
std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
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 )
|
||||
CTransaction vintx;
|
||||
uint64_t mask;
|
||||
uint256 hashBlock;
|
||||
int64_t bidamount;
|
||||
CPubKey mypk;
|
||||
struct CCcontract_info *cpAssets, C;
|
||||
|
||||
uint8_t dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector<uint8_t> dummyOrigpubkey;
|
||||
|
||||
cpAssets = CCinit(&C, EVAL_ASSETS);
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
|
||||
if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0)
|
||||
{
|
||||
bidamount = vintx.vout[0].nValue;
|
||||
mtx.vin.push_back(CTxIn(bidtxid,0,CScript()));
|
||||
mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets
|
||||
|
||||
if( DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 'b')
|
||||
mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); // spend marker if funcid='b' (not 'B')
|
||||
// TODO: spend it also in FillBuyOffer?
|
||||
|
||||
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())));
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys; // should be empty, no token vouts
|
||||
|
||||
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet('o', zeroid, 0, Mypubkey()))));
|
||||
}
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
//unlocks tokens
|
||||
std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cp,C;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
CTransaction vintx; uint64_t mask;
|
||||
uint256 hashBlock;
|
||||
int64_t askamount;
|
||||
CPubKey mypk;
|
||||
struct CCcontract_info *cpTokens, *cpAssets, tokensC, assetsC;
|
||||
|
||||
uint8_t dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector<uint8_t> dummyOrigpubkey;
|
||||
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
|
||||
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())));
|
||||
mtx.vin.push_back(CTxIn(asktxid, 0, CScript()));
|
||||
|
||||
if (DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 's')
|
||||
mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s' (not 'S')
|
||||
// TODO: spend it also in FillSell?
|
||||
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); // one-eval token vout
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(mypk);
|
||||
|
||||
/* char myCCaddr[65];
|
||||
uint8_t myPrivkey[32];
|
||||
Myprivkey(myPrivkey);
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
GetCCaddress(cpAssets, myCCaddr, mypk); */
|
||||
|
||||
// this is only for unspendable addresses:
|
||||
//CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); //do we need this? Seems FinalizeCCTx can attach to any evalcode cc addr by calling Getscriptaddress
|
||||
|
||||
uint8_t unspendableAssetsPrivkey[32];
|
||||
char unspendableAssetsAddr[64];
|
||||
// init assets 'unspendable' privkey and pubkey
|
||||
CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey);
|
||||
GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk);
|
||||
|
||||
// add additional eval-tokens unspendable assets privkey:
|
||||
CCaddr2set(cpAssets, EVAL_TOKENS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
|
||||
|
||||
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet('x', zeroid, 0, Mypubkey()))));
|
||||
}
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
//send tokens, receive coins:
|
||||
std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction vintx; uint256 hashBlock; 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 )
|
||||
CTransaction vintx;
|
||||
uint256 hashBlock;
|
||||
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 *cpTokens, tokensC;
|
||||
struct CCcontract_info *cpAssets, assetsC;
|
||||
|
||||
if (fillamount < 0)
|
||||
{
|
||||
fprintf(stderr,"negative fillamount %lld\n",(long long)fillamount);
|
||||
fprintf(stderr,"negative fillamount %lld\n", (long long)fillamount);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 )
|
||||
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 )
|
||||
SetAssetOrigpubkey(origpubkey, origprice, vintx);
|
||||
|
||||
mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript())); // Coins on Assets unspendable
|
||||
|
||||
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, fillamount, 60)) > 0)
|
||||
{
|
||||
if ( inputs < fillamount )
|
||||
fillamount = inputs;
|
||||
SetBidFillamounts(paid_amount,remaining_required,bidamount,fillamount,origprice);
|
||||
if ( inputs > fillamount )
|
||||
if (inputs < fillamount) {
|
||||
std::cerr << "FillBuyOffer(): insufficient tokens to fill buy offer" << std::endl;
|
||||
CCerror = strprintf("insufficient tokens to fill buy offer");
|
||||
return ("");
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
uint8_t unspendableAssetsPrivkey[32];
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey);
|
||||
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // vout0 coins remainder
|
||||
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // vout1 coins to normal
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens sent to the buyer
|
||||
|
||||
if (CCchange != 0)
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // vout3 change in single-eval tokens
|
||||
|
||||
fprintf(stderr,"FillBuyOffer remaining %llu -> origpubkey\n", (long long)remaining_required);
|
||||
|
||||
char unspendableAssetsAddr[64];
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk);
|
||||
|
||||
// add additional unspendable addr from Assets:
|
||||
CCaddr2set(cpTokens, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
|
||||
|
||||
// token vout verification pubkeys:
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(pubkey2pk(origpubkey));
|
||||
|
||||
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet('B', zeroid, remaining_required, origpubkey))));
|
||||
} else return("dont have any assets to fill bid");
|
||||
}
|
||||
}
|
||||
return("no normal coins left");
|
||||
}
|
||||
|
||||
std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillunits)
|
||||
|
||||
// send coins, receive tokens
|
||||
std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 asktxid, int64_t fillunits)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction vintx,filltx; uint256 hashBlock; 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 )
|
||||
CTransaction vintx,filltx;
|
||||
uint256 hashBlock;
|
||||
CPubKey mypk;
|
||||
std::vector<uint8_t> origpubkey;
|
||||
double dprice;
|
||||
uint64_t mask = 0;
|
||||
int32_t askvout = 0;
|
||||
int64_t received_assetoshis, total_nValue, orig_assetoshis, paid_nValue, remaining_nValue, inputs, CCchange=0;
|
||||
//struct CCcontract_info *cpTokens, tokensC;
|
||||
struct CCcontract_info *cpAssets, assetsC;
|
||||
|
||||
if (fillunits < 0)
|
||||
{
|
||||
CCerror = strprintf("negative fillunits %lld\n",(long long)fillunits);
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
if ( assetid2 != zeroid )
|
||||
if (assetid2 != zeroid)
|
||||
{
|
||||
CCerror = "asset swaps disabled";
|
||||
fprintf(stderr,"%s\n",CCerror.c_str());
|
||||
return("");
|
||||
}
|
||||
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
if ( txfee == 0 )
|
||||
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
|
||||
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
|
||||
{
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 )
|
||||
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
|
||||
{
|
||||
orig_assetoshis = vintx.vout[askvout].nValue;
|
||||
SetAssetOrigpubkey(origpubkey,total_nValue,vintx);
|
||||
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);
|
||||
|
||||
mtx.vin.push_back(CTxIn(asktxid, askvout, CScript())); // NOTE: this is the reference to tokens -> send cpTokens for signing into FinalizeCCTx!
|
||||
|
||||
if (assetid2 != zeroid)
|
||||
inputs = AddAssetInputs(cpAssets, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet
|
||||
else
|
||||
{
|
||||
inputs = AddNormalinputs(mtx,mypk,paid_nValue,60);
|
||||
inputs = AddNormalinputs(mtx, mypk, paid_nValue, 60);
|
||||
mask = ~((1LL << mtx.vin.size()) - 1);
|
||||
}
|
||||
if ( inputs > 0 )
|
||||
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 )
|
||||
if (inputs < paid_nValue) {
|
||||
std::cerr << "FillSell(): insufficient coins to fill sell" << std::endl;
|
||||
CCerror = strprintf("insufficient coins to fill sell");
|
||||
return ("");
|
||||
}
|
||||
|
||||
if (assetid2 != zeroid)
|
||||
SetSwapFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); //not implemented correctly yet
|
||||
else
|
||||
SetAskFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue);
|
||||
|
||||
if (assetid2 != zeroid && inputs > paid_nValue)
|
||||
CCchange = (inputs - paid_nValue);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,orig_assetoshis - received_assetoshis,GetUnspendable(cp,0)));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,received_assetoshis,mypk));
|
||||
if ( assetid2 != zeroid )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,paid_nValue,origpubkey));
|
||||
else mtx.vout.push_back(CTxOut(paid_nValue,CScript() << origpubkey << OP_CHECKSIG));
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk));
|
||||
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet(assetid2!=zeroid?'E':'S',assetid,assetid2,remaining_nValue,origpubkey)));
|
||||
|
||||
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // vout.0 tokens remainder to unspendable cc addr
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //vout.1 purchased tokens to self single-eval addr
|
||||
|
||||
// NOTE: no marker here
|
||||
|
||||
if (assetid2 != zeroid) {
|
||||
std::cerr << "FillSell() WARNING: asset swap not implemented yet! (paid_nValue)" << std::endl;
|
||||
// TODO: change MakeCC1vout appropriately when implementing:
|
||||
//mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //vout.2 tokens... (swap is not implemented yet)
|
||||
}
|
||||
else {
|
||||
//std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl;
|
||||
mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //vout.2 coins to tokens seller's normal addr
|
||||
}
|
||||
|
||||
// not implemented
|
||||
if (CCchange != 0) {
|
||||
std::cerr << "FillSell() WARNING: asset swap not implemented yet! (CCchange)" << std::endl;
|
||||
// TODO: change MakeCC1vout appropriately when implementing:
|
||||
//mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //vout.3 coins in Assets cc addr (swap not implemented)
|
||||
}
|
||||
|
||||
uint8_t unspendableAssetsPrivkey[32];
|
||||
char unspendableAssetsAddr[64];
|
||||
// init assets 'unspendable' privkey and pubkey
|
||||
CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey);
|
||||
GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk);
|
||||
|
||||
// add additional eval-tokens unspendable assets privkey:
|
||||
CCaddr2set(cpAssets, EVAL_TOKENS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
|
||||
|
||||
// vout verification pubkeys:
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(mypk);
|
||||
|
||||
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet(assetid, voutTokenPubkeys,
|
||||
EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid2, remaining_nValue, origpubkey))));
|
||||
} else {
|
||||
CCerror = strprintf("filltx not enough utxos");
|
||||
fprintf(stderr,"%s\n", CCerror.c_str());
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define CHANNELS_MAXPAYMENTS 1000
|
||||
|
||||
bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment);
|
||||
std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 tokenid);
|
||||
std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret);
|
||||
std::string ChannelClose(uint64_t txfee,uint256 opentxid);
|
||||
std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "CCMarmara.h"
|
||||
#include "CCPayments.h"
|
||||
#include "CCGateways.h"
|
||||
#include "CCtokens.h"
|
||||
|
||||
/*
|
||||
CCcustom has most of the functions that need to be extended to create a new CC contract.
|
||||
@@ -222,6 +223,18 @@ uint8_t GatewaysCCpriv[32] = { 0xf7, 0x4b, 0x5b, 0xa2, 0x7a, 0x5e, 0x9c, 0xda, 0
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
// Tokens
|
||||
#define FUNCNAME IsTokensInput
|
||||
#define EVALCODE EVAL_TOKENS
|
||||
const char *TokensCCaddr = "RAMvUfoyURBRxAdVeTMHxn3giJZCFWeha2";
|
||||
const char *TokensNormaladdr = "RCNgAngYAdrfzujYyPgfbjCGNVQZzCgTad";
|
||||
char TokensCChexstr[67] = { "03e6191c70c9c9a28f9fd87089b9488d0e6c02fb629df64979c9cdb6b2b4a68d95" };
|
||||
uint8_t TokensCCpriv[32] = { 0x1d, 0x0d, 0x0d, 0xce, 0x2d, 0xd2, 0xe1, 0x9d, 0xf5, 0xb6, 0x26, 0xd5, 0xad, 0xa0, 0xf0, 0x0a, 0xdd, 0x7a, 0x72, 0x7d, 0x17, 0x35, 0xb5, 0xe3, 0x2c, 0x6c, 0xa9, 0xa2, 0x03, 0x16, 0x4b, 0xcf };
|
||||
#include "CCcustom.inc"
|
||||
#undef FUNCNAME
|
||||
#undef EVALCODE
|
||||
|
||||
|
||||
struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
|
||||
{
|
||||
cp->evalcode = evalcode;
|
||||
@@ -347,6 +360,15 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
|
||||
cp->validate = GatewaysValidate;
|
||||
cp->ismyvin = IsGatewaysInput;
|
||||
break;
|
||||
|
||||
case EVAL_TOKENS:
|
||||
strcpy(cp->unspendableCCaddr, TokensCCaddr);
|
||||
strcpy(cp->normaladdr, TokensNormaladdr);
|
||||
strcpy(cp->CChexstr, TokensCChexstr);
|
||||
memcpy(cp->CCpriv, TokensCCpriv, 32);
|
||||
cp->validate = TokensValidate;
|
||||
cp->ismyvin = IsTokensInput;
|
||||
break;
|
||||
}
|
||||
return(cp);
|
||||
}
|
||||
|
||||
@@ -54,9 +54,15 @@ one other technical note is that komodod has the insight-explorer extensions bui
|
||||
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE,KOMODO_DEALERNODE;
|
||||
extern uint32_t ASSETCHAINS_CC;
|
||||
extern char ASSETCHAINS_SYMBOL[];
|
||||
extern std::string CCerror;
|
||||
extern std::string CCerror,ASSETCHAINS_CCLIB;
|
||||
extern uint8_t ASSETCHAINS_CCDISABLES[256];
|
||||
|
||||
#define CC_MAXVINS 1024
|
||||
|
||||
#define SMALLVAL 0.000000000000001
|
||||
#define SATOSHIDEN ((uint64_t)100000000L)
|
||||
#define dstr(x) ((double)(x) / SATOSHIDEN)
|
||||
|
||||
#ifndef _BITS256
|
||||
#define _BITS256
|
||||
union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; };
|
||||
@@ -84,12 +90,31 @@ struct CC_meta
|
||||
|
||||
struct CCcontract_info
|
||||
{
|
||||
char unspendableCCaddr[64],CChexstr[72],normaladdr[64],unspendableaddr2[64],unspendableaddr3[64];
|
||||
uint8_t CCpriv[32],unspendablepriv2[32],unspendablepriv3[32];
|
||||
CPubKey unspendablepk2,unspendablepk3;
|
||||
bool (*validate)(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn);
|
||||
bool (*ismyvin)(CScript const& scriptSig);
|
||||
uint8_t evalcode,evalcode2,evalcode3,didinit;
|
||||
// this is for spending from 'unspendable' CC address
|
||||
uint8_t evalcode;
|
||||
char unspendableCCaddr[64], CChexstr[72], normaladdr[64];
|
||||
uint8_t CCpriv[32];
|
||||
|
||||
// this for 1of2 keys coins cryptocondition (for this evalcode)
|
||||
// NOTE: only one evalcode is allowed at this time
|
||||
char coins1of2addr[64];
|
||||
CPubKey coins1of2pk[2];
|
||||
|
||||
// the same for tokens 1of2 keys cc
|
||||
char tokens1of2addr[64];
|
||||
CPubKey tokens1of2pk[2];
|
||||
|
||||
// this is for spending from two additional 'unspendable' CC addresses of other eval codes
|
||||
// (that is, for spending from several cc contract 'unspendable' addresses):
|
||||
uint8_t evalcode2, evalcode3;
|
||||
char unspendableaddr2[64], unspendableaddr3[64];
|
||||
uint8_t unspendablepriv2[32], unspendablepriv3[32];
|
||||
CPubKey unspendablepk2, unspendablepk3;
|
||||
|
||||
bool (*validate)(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn); // cc contract tx validation callback
|
||||
bool (*ismyvin)(CScript const& scriptSig); // checks if evalcode is present in the scriptSig param
|
||||
|
||||
uint8_t didinit;
|
||||
};
|
||||
struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode);
|
||||
|
||||
@@ -103,15 +128,18 @@ struct oracleprice_info
|
||||
#ifdef ENABLE_WALLET
|
||||
extern CWallet* pwalletMain;
|
||||
#endif
|
||||
//extern CCoinsViewCache *pcoinsTip;
|
||||
bool GetAddressUnspent(uint160 addressHash, int type,std::vector<std::pair<CAddressUnspentKey,CAddressUnspentValue> > &unspentOutputs);
|
||||
CBlockIndex *komodo_getblockindex(uint256 hash);
|
||||
int32_t komodo_nextheight();
|
||||
|
||||
int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256 txid,int32_t vout);
|
||||
|
||||
static const uint256 zeroid;
|
||||
bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock);
|
||||
int32_t is_hexstr(char *str,int32_t n);
|
||||
bool myAddtomempool(CTransaction &tx, CValidationState *pstate = NULL, bool fSkipExpiry = false);
|
||||
//uint64_t myGettxout(uint256 hash,int32_t n);
|
||||
int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag);
|
||||
bool myIsutxo_spentinmempool(uint256 txid,int32_t vout);
|
||||
bool mytxid_inmempool(uint256 txid);
|
||||
int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout);
|
||||
@@ -128,13 +156,25 @@ int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *
|
||||
uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format);
|
||||
uint256 OracleMerkle(int32_t height,uint256 reforacletxid,char *format,std::vector<struct oracle_merklepair>publishers);
|
||||
uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk);
|
||||
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
|
||||
|
||||
//int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
|
||||
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs);
|
||||
int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, int32_t v, uint256 reftokenid);
|
||||
|
||||
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
|
||||
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);
|
||||
CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
|
||||
//bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description);
|
||||
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
|
||||
|
||||
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload);
|
||||
CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload);
|
||||
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description);
|
||||
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopretExtra);
|
||||
|
||||
uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data);
|
||||
int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen);
|
||||
CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector<uint8_t> origpubkey);
|
||||
|
||||
|
||||
|
||||
// CCcustom
|
||||
CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv);
|
||||
@@ -150,6 +190,17 @@ CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2);
|
||||
CC* GetCryptoCondition(CScript const& scriptSig);
|
||||
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
|
||||
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
|
||||
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr);
|
||||
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2);
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk);
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2);
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk);
|
||||
|
||||
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk);
|
||||
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2);
|
||||
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr);
|
||||
|
||||
bool IsCCInput(CScript const& scriptSig);
|
||||
int32_t unstringbits(char *buf,uint64_t bits);
|
||||
uint64_t stringbits(char *str);
|
||||
@@ -172,9 +223,11 @@ std::vector<uint8_t> Mypubkey();
|
||||
bool Myprivkey(uint8_t myprivkey[]);
|
||||
int64_t CCduration(int32_t &numblocks,uint256 txid);
|
||||
bool komodo_txnotarizedconfirmed(uint256 txid);
|
||||
CPubKey check_signing_pubkey(CScript scriptSig);
|
||||
// CCtx
|
||||
bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey);
|
||||
std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret);
|
||||
extern std::vector<CPubKey> NULL_pubkeys;
|
||||
std::string FinalizeCCTx(uint64_t skipmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret,std::vector<CPubKey> pubkeys = NULL_pubkeys);
|
||||
void SetCCunspents(std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs,char *coinaddr);
|
||||
void SetCCtxids(std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,char *coinaddr);
|
||||
int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs);
|
||||
@@ -187,5 +240,6 @@ bits256 curve25519_basepoint9();
|
||||
bits256 curve25519(bits256 mysecret,bits256 basepoint);
|
||||
void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
|
||||
bits256 bits256_doublesha256(char *deprecated,uint8_t *data,int32_t datalen);
|
||||
UniValue ValueFromAmount(const CAmount& amount);
|
||||
|
||||
#endif
|
||||
|
||||
769
src/cc/CCtokens.cpp
Normal file
769
src/cc/CCtokens.cpp
Normal file
@@ -0,0 +1,769 @@
|
||||
/******************************************************************************
|
||||
* 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 "CCtokens.h"
|
||||
|
||||
/* TODO: correct this:
|
||||
-----------------------------
|
||||
The SetTokenFillamounts() and ValidateTokenRemainder() 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 tokens 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 tokenoshis to original pubkey
|
||||
//vout.3: CC output for tokenoshis change (if any)
|
||||
//vout.4: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['B'] [tokenid] [remaining token required] [origpubkey]
|
||||
ValidateTokenRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,totalunits);
|
||||
|
||||
Yes, this is quite confusing...
|
||||
|
||||
In ValudateTokenRemainder the naming convention is nValue is the coin/token with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or tokens, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits.
|
||||
|
||||
We assume that the effective unit cost in the orderbook is valid and that that amount was paid and also that any remainder will be close enough in effective unit cost to not matter. At the edge cases, this will probably be not true and maybe some orders wont be practically fillable when reduced to fractional state. However, the original pubkey that created the offer can always reclaim it.
|
||||
------------------------------
|
||||
*/
|
||||
|
||||
|
||||
// NOTE: this inital tx won't be used by other contract
|
||||
// for tokens to be used there should be at least one 't' tx with other contract's custom opret
|
||||
CScript EncodeTokenCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,std::string name,std::string description)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_TOKENS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
// this is for other contracts which use tokens and build customized extra payloads to token's opret:
|
||||
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload)
|
||||
{
|
||||
CScript opret;
|
||||
uint8_t tokenFuncId = 't';
|
||||
uint8_t evalCodeInOpret = EVAL_TOKENS;
|
||||
|
||||
tokenid = revuint256(tokenid);
|
||||
|
||||
uint8_t ccType = 0;
|
||||
if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2)
|
||||
ccType = voutPubkeys.size();
|
||||
|
||||
std::vector<uint8_t> vpayload;
|
||||
GetOpReturnData(payload, vpayload);
|
||||
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \
|
||||
if (ccType >= 1) ss << voutPubkeys[0]; \
|
||||
if (ccType == 2) ss << voutPubkeys[1]; \
|
||||
if (vpayload.size() > 0) ss << vpayload;);
|
||||
|
||||
|
||||
// "error 64: scriptpubkey":
|
||||
// if (payload.size() > 0)
|
||||
// opret += payload;
|
||||
|
||||
// error 64: scriptpubkey:
|
||||
// CScript opretPayloadNoOpcode(vpayload);
|
||||
// return opret + opretPayloadNoOpcode;
|
||||
|
||||
// how to attach payload without re-serialization:
|
||||
// sig_aborted:
|
||||
// opret.resize(opret.size() + vpayload.size());
|
||||
// CScript::iterator it = opret.begin() + opret.size();
|
||||
// for (int i = 0; i < vpayload.size(); i++, it++)
|
||||
// *it = vpayload[i];
|
||||
|
||||
return opret;
|
||||
}
|
||||
|
||||
// overload for compatibility
|
||||
CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload)
|
||||
{
|
||||
return EncodeTokenOpRet(tokenid, voutPubkeys, payload);
|
||||
}
|
||||
|
||||
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t dummyEvalcode, funcid, *script;
|
||||
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( script != 0 && vopret.size() > 2 && script[0] == EVAL_TOKENS && script[1] == 'c' )
|
||||
{
|
||||
if ( E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description) != 0 )
|
||||
return(funcid);
|
||||
}
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopretExtra)
|
||||
{
|
||||
std::vector<uint8_t> vopret, extra, dummyPubkey;
|
||||
uint8_t funcId=0, *script, dummyEvalCode, dummyFuncId, ccType;
|
||||
std::string dummyName; std::string dummyDescription;
|
||||
CPubKey voutPubkey1, voutPubkey2;
|
||||
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
tokenid = zeroid;
|
||||
|
||||
if (script != 0 && vopret.size() > 2)
|
||||
{
|
||||
// NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set!
|
||||
bool isEof = true;
|
||||
|
||||
evalCode = script[0];
|
||||
if (evalCode != EVAL_TOKENS)
|
||||
return (uint8_t)0;
|
||||
|
||||
funcId = script[1];
|
||||
//fprintf(stderr,"decode.[%c]\n",funcId);
|
||||
|
||||
switch( funcId )
|
||||
{
|
||||
case 'c':
|
||||
return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription);
|
||||
//break;
|
||||
case 't':
|
||||
//not used yet: case 'l':
|
||||
// NOTE: 'E_UNMARSHAL result==false' means 'parse error' OR 'not eof state'. Consequently, 'result==false' but 'isEof==true' means just 'parse error'
|
||||
if (E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> tokenid; ss >> ccType; if (ccType >= 1) ss >> voutPubkey1; if (ccType == 2) ss >> voutPubkey2; isEof = ss.eof(); vopretExtra = std::vector<uint8_t>(ss.begin(), ss.end()))
|
||||
|| !isEof)
|
||||
{
|
||||
|
||||
if (!(ccType >= 0 && ccType <= 2)) { //incorrect ccType
|
||||
std::cerr << "DecodeTokenOpRet() incorrect ccType=" << (int)ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl;
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// add verification pubkeys:
|
||||
voutPubkeys.clear();
|
||||
if (voutPubkey1.IsValid())
|
||||
voutPubkeys.push_back(voutPubkey1);
|
||||
if (voutPubkey2.IsValid())
|
||||
voutPubkeys.push_back(voutPubkey2);
|
||||
|
||||
tokenid = revuint256(tokenid);
|
||||
return(funcId);
|
||||
}
|
||||
std::cerr << "DecodeTokenOpRet() bad opret format, isEof=" << isEof << " ccType=" << ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl;
|
||||
return (uint8_t)0;
|
||||
|
||||
default:
|
||||
std::cerr << "DecodeTokenOpRet() illegal funcid=" << (int)funcId << std::endl;
|
||||
return (uint8_t)0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cerr << "DecodeTokenOpRet() empty opret, could not parse" << std::endl;
|
||||
}
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// tx validation
|
||||
bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
static uint256 zero;
|
||||
CTxDestination address; CTransaction vinTx, createTx; uint256 hashBlock, tokenid, tokenid2;
|
||||
int32_t i, starti, numvins, numvouts, preventCCvins, preventCCvouts;
|
||||
int64_t remaining_price, nValue, tokenoshis, outputs, inputs, tmpprice, totalunits, ignore;
|
||||
std::vector<uint8_t> vopretExtra, tmporigpubkey, ignorepubkey;
|
||||
uint8_t funcid, evalCodeInOpret;
|
||||
char destaddr[64], origaddr[64], CCaddr[64];
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
|
||||
//return true;
|
||||
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
outputs = inputs = 0;
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
|
||||
if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, vopretExtra)) == 0)
|
||||
return eval->Invalid("TokenValidate: invalid opreturn payload");
|
||||
|
||||
fprintf(stderr, "TokensValidate (%c) evalcode=0x%0x\n", funcid, cp->evalcode);
|
||||
|
||||
if (eval->GetTxUnconfirmed(tokenid, createTx, hashBlock) == 0)
|
||||
return eval->Invalid("cant find token create txid");
|
||||
else if (IsCCInput(tx.vin[0].scriptSig) != 0)
|
||||
return eval->Invalid("illegal token vin0");
|
||||
else if (numvouts < 1)
|
||||
return eval->Invalid("no vouts");
|
||||
else if (funcid != 'c')
|
||||
{
|
||||
if (tokenid == zeroid)
|
||||
return eval->Invalid("illegal tokenid");
|
||||
else if (!TokensExactAmounts(true, cp, inputs, outputs, eval, tx, tokenid)) {
|
||||
if (!eval->Valid())
|
||||
return false; //TokenExactAmounts must call eval->Invalid()!
|
||||
else
|
||||
return eval->Invalid("tokens cc inputs != cc 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 tokenoshis to CC
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.n-1: opreturn EVAL_TOKENS 'c' <tokenname> <description>
|
||||
//if (evalCodeInOpret != EVAL_TOKENS)
|
||||
// return eval->Invalid("unexpected TokenValidate for createtoken");
|
||||
//else
|
||||
return true;
|
||||
|
||||
case 't': // transfer
|
||||
//vin.0: normal input
|
||||
//vin.1 .. vin.n-1: valid CC outputs
|
||||
//vout.0 to n-2: tokenoshis output to CC
|
||||
//vout.n-2: normal output for change (if any)
|
||||
//vout.n-1: opreturn <other evalcode> 't' tokenid <other contract payload>
|
||||
if (inputs == 0)
|
||||
return eval->Invalid("no token inputs for transfer");
|
||||
|
||||
fprintf(stderr, "token transfer preliminarily validated %.8f -> %.8f (%d %d)\n", (double)inputs / COIN, (double)outputs / COIN, preventCCvins, preventCCvouts);
|
||||
break; // breaking to other contract validation...
|
||||
|
||||
default:
|
||||
fprintf(stderr, "illegal tokens funcid.(%c)\n", funcid);
|
||||
return eval->Invalid("unexpected token funcid");
|
||||
}
|
||||
|
||||
// forward validation if evalcode in opret is not EVAL_TOKENS
|
||||
// init for forwarding validation call
|
||||
//if (evalCodeInOpret != EVAL_TOKENS) { // TODO: should we check also only allowed for tokens evalcodes, like EVAL_ASSETS, EVAL_GATEWAYS?
|
||||
// struct CCcontract_info *cpOther = NULL, C;
|
||||
|
||||
// cpOther = CCinit(&C, evalCodeInOpret);
|
||||
// if (cpOther)
|
||||
// return cpOther->validate(cpOther, eval, tx, nIn);
|
||||
// else
|
||||
// return eval->Invalid("unsupported evalcode in opret");
|
||||
//}
|
||||
return true;
|
||||
// what does this do?
|
||||
// return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
|
||||
}
|
||||
|
||||
// helper funcs:
|
||||
|
||||
// extract my vins pubkeys:
|
||||
bool ExtractTokensVinPubkeys(CTransaction tx, std::vector<CPubKey> &vinPubkeys) {
|
||||
|
||||
bool found = false;
|
||||
CPubKey pubkey;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
for (int32_t i = 0; i < tx.vin.size(); i++)
|
||||
{ // check for additional contracts which may send tokens to the Tokens contract
|
||||
if( (*cpTokens->ismyvin)(tx.vin[i].scriptSig) )
|
||||
{
|
||||
|
||||
auto findEval = [](CC *cond, struct CCVisitor _) {
|
||||
bool r = false; //cc_typeId(cond) == CC_Eval && cond->codeLength == 1 && cond->code[0] == EVAL_TOKENS;
|
||||
|
||||
if (cc_typeId(cond) == CC_Secp256k1) {
|
||||
*(CPubKey*)_.context = buf2pk(cond->publicKey);
|
||||
//std::cerr << "findEval found pubkey=" << HexStr(*(CPubKey*)_.context) << std::endl;
|
||||
r = true;
|
||||
}
|
||||
// false for a match, true for continue
|
||||
return r ? 0 : 1;
|
||||
};
|
||||
|
||||
CC *cond = GetCryptoCondition(tx.vin[i].scriptSig);
|
||||
|
||||
if (cond) {
|
||||
CCVisitor visitor = { findEval, (uint8_t*)"", 0, &pubkey };
|
||||
bool out = !cc_visit(cond, visitor);
|
||||
cc_free(cond);
|
||||
|
||||
if (pubkey.IsValid()) {
|
||||
vinPubkeys.push_back(pubkey);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// this is just for log messages indentation fur debugging recursive calls:
|
||||
thread_local uint32_t tokenValIndentSize = 0;
|
||||
|
||||
// validates opret for token tx:
|
||||
uint8_t ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopretExtra) {
|
||||
|
||||
uint256 tokenidOpret, tokenidOpret2;
|
||||
uint8_t funcid;
|
||||
uint8_t dummyEvalCode;
|
||||
|
||||
// this is just for log messages indentation fur debugging recursive calls:
|
||||
std::string indentStr = std::string().append(tokenValIndentSize, '.');
|
||||
|
||||
int32_t n = tx.vout.size();
|
||||
|
||||
if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, dummyEvalCode, tokenidOpret, voutPubkeys, vopretExtra)) == 0)
|
||||
{
|
||||
std::cerr << indentStr << "ValidateTokenOpret() DecodeTokenOpret could not parse opret for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
return(false);
|
||||
}
|
||||
else if (funcid == 'c')
|
||||
{
|
||||
if (tokenid != zeroid && tokenid == tx.GetHash() && v == 0) {
|
||||
//std::cerr << indentStr << "ValidateTokenOpret() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl;
|
||||
return funcid;
|
||||
}
|
||||
}
|
||||
else if (funcid == 't')
|
||||
{
|
||||
//std::cerr << indentStr << "ValidateTokenOpret() tokenid=" << tokenid.GetHex() << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
if (tokenid != zeroid && tokenid == tokenidOpret) {
|
||||
//std::cerr << indentStr << "ValidateTokenOpret() this is a transfer 't' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl;
|
||||
return funcid;
|
||||
}
|
||||
}
|
||||
//std::cerr << indentStr << "ValidateTokenOpret() return false funcid=" << (char)funcid << " tokenid=" << tokenid.GetHex() << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
return (uint8_t)0;
|
||||
}
|
||||
|
||||
// Checks if the vout is a really Tokens CC vout
|
||||
// also checks tokenid in opret or txid if this is 'c' tx
|
||||
// goDeeper is true: the func also validates amounts of the passed transaction:
|
||||
// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx
|
||||
// checkPubkeys is true: validates if the vout is token vout1 or token vout1of2. Should always be true!
|
||||
int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, int32_t v, uint256 reftokenid)
|
||||
{
|
||||
|
||||
// this is just for log messages indentation fur debugging recursive calls:
|
||||
std::string indentStr = std::string().append(tokenValIndentSize, '.');
|
||||
//std::cerr << indentStr << "IsTokensvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
|
||||
//TODO: validate cc vouts are EVAL_TOKENS!
|
||||
if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition()) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here
|
||||
{
|
||||
int32_t n = tx.vout.size();
|
||||
// just check boundaries:
|
||||
if (v >= n - 1) { // just moved this up (dimxy)
|
||||
std::cerr << indentStr << "isTokensvout() internal err: (v >= n - 1), returning 0" << std::endl;
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (goDeeper) {
|
||||
//std::cerr << indentStr << "IsTokensvout() maxTokenExactAmountDepth=" << maxTokenExactAmountDepth << std::endl;
|
||||
//validate all tx
|
||||
int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0;
|
||||
|
||||
tokenValIndentSize++;
|
||||
// false --> because we already at the 1-st level ancestor tx and do not need to dereference ancestors of next levels
|
||||
bool isEqual = TokensExactAmounts(false, cp, myCCVinsAmount, myCCVoutsAmount, eval, tx, reftokenid);
|
||||
tokenValIndentSize--;
|
||||
|
||||
if (!isEqual) {
|
||||
// if ccInputs != ccOutputs and it is not the tokenbase tx
|
||||
// this means it is possibly a fake tx (dimxy):
|
||||
if (reftokenid != tx.GetHash()) { // checking that this is the true tokenbase tx, by verifying that funcid=c, is done further in this function (dimxy)
|
||||
std::cerr << indentStr << "IsTokensvout() warning: for the verified tx detected a bad vintx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs and not the 'tokenbase' tx, skipping the verified tx" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// moved opret checking to this new reusable func (dimxy):
|
||||
std::vector<CPubKey> voutPubkeys;
|
||||
std::vector<uint8_t> vopretExtra;
|
||||
const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra);
|
||||
//std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (char)(funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
if (funcId != 0) {
|
||||
//std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned not-null" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
|
||||
if (checkPubkeys && funcId != 'c') { // verify that the vout is token's (for 'c' there is no pubkeys!):
|
||||
|
||||
//std::cerr << "IsTokensvout() vopretExtra=" << HexStr(vopretExtra) << std::endl;
|
||||
|
||||
uint8_t evalCodeInOpret;
|
||||
if (vopretExtra.size() >= 2 /*|| vopretExtra.size() != vopretExtra.begin()[0] <-- shold we check this?*/) {
|
||||
std::cerr << "IsTokensvout() empty or incorrect contract opret" << std::endl;
|
||||
evalCodeInOpret = vopretExtra.begin()[1];
|
||||
}
|
||||
else {
|
||||
// if payload is empty maybe it is a claim to non-payload-one-token-eval vout?
|
||||
evalCodeInOpret = EVAL_TOKENS;
|
||||
}
|
||||
|
||||
// maybe this is dual-eval 1 pubkey or 1of2 pubkey vout?
|
||||
if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) {
|
||||
CTxOut testDualVout;
|
||||
// check dual-eval 1 pubkey vout with the first pubkey
|
||||
testDualVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0]);
|
||||
if (tx.vout[v].scriptPubKey == testDualVout.scriptPubKey) {
|
||||
//std::cerr << indentStr << "IsTokensvout() this is dual-eval token vout (i=0), eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
|
||||
if(voutPubkeys.size() == 2) {
|
||||
// check dual eval 1of2 pubkeys vout
|
||||
testDualVout = MakeTokensCC1of2vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]);
|
||||
if (tx.vout[v].scriptPubKey == testDualVout.scriptPubKey) {
|
||||
//std::cerr << indentStr << "IsTokensvout() this is dual-eval token 1of2 vout, eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
|
||||
// check dual eval 1 pubkey vout with the second pubkey
|
||||
testDualVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[1]);
|
||||
if (tx.vout[v].scriptPubKey == testDualVout.scriptPubKey) {
|
||||
//std::cerr << indentStr << "IsTokensvout() this is dual-eval token vout (i=1), eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// maybe this is claim to single-eval token?
|
||||
CTxOut testTokenVout1;
|
||||
testTokenVout1 = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]);
|
||||
if (tx.vout[v].scriptPubKey == testTokenVout1.scriptPubKey) {
|
||||
//std::cerr << indentStr << "IsTokensvout() this is single-eval token vout (i=0), returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
|
||||
if (voutPubkeys.size() == 2) {
|
||||
testTokenVout1 = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[1]);
|
||||
if (tx.vout[v].scriptPubKey == testTokenVout1.scriptPubKey) {
|
||||
//std::cerr << indentStr << "IsTokensvout() this is single-eval token vout (i=1), returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// maybe it is single-eval or dual-eval token change?
|
||||
std::vector<CPubKey> vinPubkeys;
|
||||
ExtractTokensVinPubkeys(tx, vinPubkeys);
|
||||
|
||||
for(std::vector<CPubKey>::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) {
|
||||
CTxOut testTokenVout1 = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it);
|
||||
CTxOut testDualVout1 = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, *it);
|
||||
|
||||
if (tx.vout[v].scriptPubKey == testTokenVout1.scriptPubKey) {
|
||||
//std::cerr << indentStr << "IsTokensvout() this is single-eval token change, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
|
||||
if (tx.vout[v].scriptPubKey == testDualVout1.scriptPubKey) {
|
||||
//std::cerr << indentStr << "IsTokensvout() this is dual-eval token change, vout eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
//std::cerr << indentStr << "IsTokensvout() returns without pubkey check value=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
|
||||
return tx.vout[v].nValue;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << indentStr; fprintf(stderr,"IsTokensvout() CC vout v.%d of n=%d amount=%.8f txid=%s\n",v,n,(double)0/COIN, tx.GetHash().GetHex().c_str());
|
||||
}
|
||||
//std::cerr << indentStr; fprintf(stderr,"IsTokensvout() normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN);
|
||||
return(0);
|
||||
}
|
||||
|
||||
// compares cc inputs vs cc outputs (to prevent feeding vouts from normal inputs)
|
||||
bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cp, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid)
|
||||
{
|
||||
CTransaction vinTx;
|
||||
uint256 hashBlock;
|
||||
int64_t tokenoshis;
|
||||
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
int32_t numvins = tx.vin.size();
|
||||
int32_t numvouts = tx.vout.size();
|
||||
inputs = outputs = 0;
|
||||
|
||||
// this is just for log messages indentation for debugging recursive calls:
|
||||
std::string indentStr = std::string().append(tokenValIndentSize, '.');
|
||||
|
||||
for (int32_t i = 0; i<numvins; i++)
|
||||
{ // check for additional contracts which may send tokens to the Tokens contract
|
||||
if ((*cpTokens->ismyvin)(tx.vin[i].scriptSig) /*|| IsVinAllowed(tx.vin[i].scriptSig) != 0*/)
|
||||
{
|
||||
//std::cerr << indentStr << "TokensExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl;
|
||||
// we are not inside the validation code -- dimxy
|
||||
if ((eval && eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock) == 0) || (!eval && !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock)))
|
||||
{
|
||||
std::cerr << indentStr << "TokensExactAmounts() cannot read vintx for i." << i << " numvins." << numvins << std::endl;
|
||||
return (!eval) ? false : eval->Invalid("always should find vin tx, but didnt");
|
||||
}
|
||||
else {
|
||||
tokenValIndentSize++;
|
||||
// validate vouts of vintx
|
||||
//std::cerr << indentStr << "TokenExactAmounts() check vin i=" << i << " nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl;
|
||||
tokenoshis = IsTokensvout(goDeeper, true, cpTokens, eval, vinTx, tx.vin[i].prevout.n, tokenid);
|
||||
tokenValIndentSize--;
|
||||
if (tokenoshis != 0)
|
||||
{
|
||||
std::cerr << indentStr << "TokensExactAmounts() vin i=" << i << " tokenoshis=" << tokenoshis << std::endl;
|
||||
inputs += tokenoshis;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int32_t i = 0; i<numvouts; i++)
|
||||
{
|
||||
tokenValIndentSize++;
|
||||
// Note: we pass in here 'false' because we don't need to call TokenExactAmounts() recursively from IsTokensvout
|
||||
// indeed, in this case we'll be checking this tx again
|
||||
//std::cerr << indentStr << "TokenExactAmounts() check vout i=" << i << " nValue=" << tx.vout[i].nValue << std::endl;
|
||||
tokenoshis = IsTokensvout(false, true /*<--exclude non-tokens vouts*/, cpTokens, eval, tx, i, tokenid);
|
||||
tokenValIndentSize--;
|
||||
|
||||
if (tokenoshis != 0)
|
||||
{
|
||||
std::cerr << indentStr << "TokensExactAmounts() vout i=" << i << " tokenoshis=" << tokenoshis << std::endl;
|
||||
outputs += tokenoshis;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << indentStr << "TokensExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
|
||||
|
||||
if (inputs != outputs) {
|
||||
if (tx.GetHash() != tokenid)
|
||||
std::cerr << indentStr << "TokenExactAmounts() found unequal token cc inputs=" << inputs << " vs cc outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << " and this is not the create tx" << std::endl;
|
||||
return false; // do not call eval->Invalid() here!
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
// add inputs from token cc addr
|
||||
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs)
|
||||
{
|
||||
char tokenaddr[64], destaddr[64];
|
||||
int64_t threshold, nValue, price, totalinputs = 0;
|
||||
uint256 txid, hashBlock;
|
||||
//std::vector<uint8_t> vopretExtra;
|
||||
CTransaction vintx;
|
||||
int32_t j, vout, n = 0;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
|
||||
GetTokensCCaddress(cp, tokenaddr, pk);
|
||||
SetCCunspents(unspentOutputs, tokenaddr);
|
||||
|
||||
threshold = total / (maxinputs != 0 ? maxinputs : 64); // TODO: is maxinputs really could not be over 64? what if i want to calc total balance?
|
||||
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
vout = (int32_t)it->first.index;
|
||||
if (it->second.satoshis < threshold)
|
||||
continue;
|
||||
for (j = 0; j<mtx.vin.size(); j++)
|
||||
if (txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n)
|
||||
break;
|
||||
if (j != mtx.vin.size())
|
||||
continue;
|
||||
|
||||
if (GetTransaction(txid, vintx, hashBlock, false) != 0)
|
||||
{
|
||||
Getscriptaddress(destaddr, vintx.vout[vout].scriptPubKey);
|
||||
if (strcmp(destaddr, tokenaddr) != 0 && strcmp(destaddr, cp->unspendableCCaddr) != 0 && strcmp(destaddr, cp->unspendableaddr2) != 0)
|
||||
continue;
|
||||
//fprintf(stderr, "AddTokenCCInputs() check destaddress=%s vout amount=%.8f\n", destaddr, (double)vintx.vout[vout].nValue / COIN);
|
||||
|
||||
std::vector<CPubKey> vinPubkeys;
|
||||
|
||||
if ((nValue = IsTokensvout(true, true/*<--add only checked token uxtos */, cp, NULL, vintx, vout, tokenid)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0)
|
||||
{
|
||||
if (total != 0 && maxinputs != 0)
|
||||
mtx.vin.push_back(CTxIn(txid, vout, CScript()));
|
||||
nValue = it->second.satoshis;
|
||||
totalinputs += nValue;
|
||||
std::cerr << "AddTokenInputs() adding input nValue=" << nValue << std::endl;
|
||||
n++;
|
||||
if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << "AddTokenInputs() found totalinputs=" << totalinputs << std::endl;
|
||||
return(totalinputs);
|
||||
}
|
||||
|
||||
|
||||
std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; struct CCcontract_info *cp, C;
|
||||
if (assetsupply < 0)
|
||||
{
|
||||
fprintf(stderr, "negative assetsupply %lld\n", (long long)assetsupply);
|
||||
return("");
|
||||
}
|
||||
|
||||
cp = CCinit(&C, EVAL_TOKENS);
|
||||
if (name.size() > 32 || description.size() > 4096)
|
||||
{
|
||||
fprintf(stderr, "name.%d or description.%d is too big\n", (int32_t)name.size(), (int32_t)description.size());
|
||||
return("");
|
||||
}
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
|
||||
if (AddNormalinputs(mtx, mypk, assetsupply + 2 * txfee, 64) > 0)
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, assetsupply, mypk));
|
||||
mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(cp->CChexstr) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeTokenCreateOpRet('c', Mypubkey(), name, description)));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
|
||||
std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector<uint8_t> destpubkey, int64_t total)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; uint64_t mask; int64_t CCchange = 0, inputs = 0; struct CCcontract_info *cp, C;
|
||||
std::vector<uint8_t> emptyExtraOpret;
|
||||
|
||||
if (total < 0)
|
||||
{
|
||||
fprintf(stderr, "negative total %lld\n", (long long)total);
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C, EVAL_TOKENS);
|
||||
if (txfee == 0)
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
if (AddNormalinputs(mtx, mypk, txfee, 3) > 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 = AddTokenCCInputs(cp, mtx, mypk, assetid, total, 60)) > 0)
|
||||
{
|
||||
|
||||
if (inputs < total) { //added dimxy
|
||||
std::cerr << "AssetTransfer(): insufficient funds" << std::endl;
|
||||
return ("");
|
||||
}
|
||||
if (inputs > total)
|
||||
CCchange = (inputs - total);
|
||||
//for (i=0; i<n; i++)
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, total, pubkey2pk(destpubkey))); // TODO: or MakeTokensCC1vout??
|
||||
if (CCchange != 0)
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk));
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(pubkey2pk(destpubkey)); // dest pubkey for validating vout
|
||||
|
||||
return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet('t', EVAL_TOKENS, assetid, voutTokenPubkeys, CScript()))); // By setting EVAL_TOKENS we're getting out from assets validation code
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "not enough CC token inputs for %.8f\n", (double)total / COIN);
|
||||
}
|
||||
//} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size());
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "not enough normal inputs for txfee\n");
|
||||
}
|
||||
return("");
|
||||
}
|
||||
|
||||
|
||||
int64_t GetTokenBalance(CPubKey pk, uint256 tokenid)
|
||||
{
|
||||
uint256 hashBlock;
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction tokentx;
|
||||
|
||||
// CCerror = strprintf("obsolete, cannot return correct value without eval");
|
||||
// return 0;
|
||||
|
||||
if (GetTransaction(tokenid, tokentx, hashBlock, false) == 0)
|
||||
{
|
||||
fprintf(stderr, "cant find tokenid\n");
|
||||
CCerror = strprintf("cant find tokenid");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct CCcontract_info *cp, C;
|
||||
cp = CCinit(&C, EVAL_TOKENS);
|
||||
return(AddTokenCCInputs(cp, mtx, pk, tokenid, 0, 0));
|
||||
}
|
||||
|
||||
UniValue TokenInfo(uint256 tokenid)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; std::vector<uint8_t> origpubkey; std::string name, description; char str[67], numstr[65];
|
||||
if (GetTransaction(tokenid, vintx, hashBlock, false) == 0)
|
||||
{
|
||||
fprintf(stderr, "cant find assetid\n");
|
||||
result.push_back(Pair("result", "error"));
|
||||
result.push_back(Pair("error", "cant find tokenid"));
|
||||
return(result);
|
||||
}
|
||||
if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description) == 0)
|
||||
{
|
||||
fprintf(stderr, "assetid isnt token creation txid\n");
|
||||
result.push_back(Pair("result", "error"));
|
||||
result.push_back(Pair("error", "assetid isnt token creation txid"));
|
||||
}
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("tokenid", uint256_str(str, tokenid)));
|
||||
result.push_back(Pair("owner", pubkey33_str(str, origpubkey.data())));
|
||||
result.push_back(Pair("name", name));
|
||||
result.push_back(Pair("supply", vintx.vout[0].nValue));
|
||||
result.push_back(Pair("description", description));
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue TokenList()
|
||||
{
|
||||
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_TOKENS);
|
||||
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 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description) != 0)
|
||||
{
|
||||
result.push_back(uint256_str(str, txid));
|
||||
}
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
44
src/cc/CCtokens.h
Normal file
44
src/cc/CCtokens.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2018 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
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_TOKENS_H
|
||||
#define CC_TOKENS_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
|
||||
// CCcustom
|
||||
bool TokensValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
|
||||
bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid);
|
||||
//int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector<CPubKey> vinPubkeys);
|
||||
std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description);
|
||||
std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector<uint8_t> destpubkey, int64_t total);
|
||||
|
||||
int64_t GetTokenBalance(CPubKey pk, uint256 tokenid);
|
||||
UniValue TokenInfo(uint256 tokenid);
|
||||
UniValue TokenList();
|
||||
|
||||
//this is in CCinclude.h int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs);
|
||||
|
||||
//this is in CCinclude.h uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
|
||||
|
||||
|
||||
#endif
|
||||
173
src/cc/CCtx.cpp
173
src/cc/CCtx.cpp
@@ -16,6 +16,8 @@
|
||||
#include "CCinclude.h"
|
||||
#include "key_io.h"
|
||||
|
||||
std::vector<CPubKey> NULL_pubkeys;
|
||||
|
||||
/*
|
||||
FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn.
|
||||
|
||||
@@ -38,13 +40,18 @@ bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScrip
|
||||
return(false);
|
||||
}
|
||||
|
||||
std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret)
|
||||
std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret,std::vector<CPubKey> pubkeys)
|
||||
{
|
||||
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||
CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0;
|
||||
int64_t utxovalues[64],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=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,*othercond2=0,*othercond3=0,*cond; CPubKey unspendablepk;
|
||||
CTransaction vintx; std::string hex; CPubKey globalpk; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0;
|
||||
int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0;
|
||||
int32_t i,flag,utxovout,n,err = 0;
|
||||
char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], tokensunspendable[64];
|
||||
uint8_t *privkey, myprivkey[32], unspendablepriv[32], tokensunspendablepriv[32], *msg32 = 0;
|
||||
CC *mycond=0, *othercond=0, *othercond2=0,*othercond4=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL;
|
||||
CPubKey unspendablepk /*, tokensunspendablepk*/;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
globalpk = GetUnspendable(cp,0);
|
||||
n = mtx.vout.size();
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
@@ -52,17 +59,37 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
|
||||
normaloutputs += mtx.vout[i].nValue;
|
||||
totaloutputs += mtx.vout[i].nValue;
|
||||
}
|
||||
if ( (n= mtx.vin.size()) > 64 )
|
||||
if ( (n= mtx.vin.size()) > CC_MAXVINS )
|
||||
{
|
||||
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);
|
||||
|
||||
// to spend from single-eval evalcode 'unspendable'
|
||||
unspendablepk = GetUnspendable(cp, unspendablepriv);
|
||||
GetCCaddress(cp, unspendable, unspendablepk);
|
||||
othercond = MakeCCcond1(cp->evalcode, unspendablepk);
|
||||
|
||||
// tokens support:
|
||||
|
||||
// to spend from dual-eval mypk vout
|
||||
GetTokensCCaddress(cp, mytokensaddr, mypk);
|
||||
mytokenscond = MakeTokensCCcond1(cp->evalcode, mypk);
|
||||
|
||||
// to spend from single-eval EVAL_TOKENS mypk
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
GetCCaddress(cpTokens, mysingletokensaddr, mypk);
|
||||
mysingletokenscond = MakeCCcond1(EVAL_TOKENS, mypk);
|
||||
|
||||
// to spend from dual-eval EVAL_TOKEN+evalcode 'unspendable' pk
|
||||
//tokensunspendablepk = GetUnspendable(cpTokens, tokensunspendablepriv);
|
||||
GetTokensCCaddress(cp, tokensunspendable, unspendablepk);
|
||||
othertokenscond = MakeTokensCCcond1(cp->evalcode, unspendablepk);
|
||||
|
||||
//Reorder vins so that for multiple normal vins all other except vin0 goes to the end
|
||||
//This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation.
|
||||
for (i=0; i<n; i++)
|
||||
@@ -127,41 +154,96 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
|
||||
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 )
|
||||
//fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr);
|
||||
//std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " myaddr=" << myaddr << std::endl;
|
||||
if( strcmp(destaddr,myaddr) == 0 )
|
||||
{
|
||||
privkey = myprivkey;
|
||||
cond = mycond;
|
||||
|
||||
}
|
||||
else if (strcmp(destaddr, mytokensaddr) == 0) // if this is TokensCC1vout
|
||||
{
|
||||
privkey = myprivkey;
|
||||
cond = mytokenscond;
|
||||
//fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout CC addr.(%s)\n",mytokensaddr);
|
||||
}
|
||||
else if (strcmp(destaddr, mysingletokensaddr) == 0) // if this is TokensCC1vout
|
||||
{
|
||||
privkey = myprivkey;
|
||||
cond = mysingletokenscond;
|
||||
//fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout CC addr.(%s)\n", mytokensaddr);
|
||||
}
|
||||
else if ( strcmp(destaddr,unspendable) == 0 )
|
||||
{
|
||||
privkey = unspendablepriv;
|
||||
cond = othercond;
|
||||
//fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable);
|
||||
//fprintf(stderr,"FinalizeCCTx() matched unspendable CC addr.(%s)\n",unspendable);
|
||||
}
|
||||
else if (strcmp(destaddr, tokensunspendable) == 0)
|
||||
{
|
||||
privkey = unspendablepriv;
|
||||
cond = othertokenscond;
|
||||
//fprintf(stderr,"FinalizeCCTx() matched tokensunspendable CC addr.(%s)\n",unspendable);
|
||||
}
|
||||
// check if this is the 2nd additional evalcode + 'unspendable' cc addr:
|
||||
else if ( strcmp(destaddr,cp->unspendableaddr2) == 0)
|
||||
{
|
||||
//fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2);
|
||||
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2);
|
||||
privkey = cp->unspendablepriv2;
|
||||
if ( othercond2 == 0 && cp->evalcode != EVAL_CHANNELS && cp->evalcode != EVAL_HEIR )
|
||||
othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2);
|
||||
else if ( othercond2 == 0 && (cp->evalcode == EVAL_CHANNELS || cp->evalcode == EVAL_HEIR) )
|
||||
othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3);
|
||||
if ( othercond2 == 0 )
|
||||
othercond2 = MakeCCcond1(cp->evalcode2, cp->unspendablepk2);
|
||||
cond = othercond2;
|
||||
}
|
||||
// check if this is 3rd additional evalcode + 'unspendable' cc addr:
|
||||
else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 )
|
||||
{
|
||||
//fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3);
|
||||
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3);
|
||||
privkey = cp->unspendablepriv3;
|
||||
if ( othercond3 == 0 )
|
||||
othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3);
|
||||
cond = othercond3;
|
||||
}
|
||||
// check if this is spending from 1of2 cc coins addr:
|
||||
else if (strcmp(cp->coins1of2addr, destaddr) == 0)
|
||||
{
|
||||
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr);
|
||||
privkey = myprivkey;
|
||||
if (othercond1of2 == 0)
|
||||
othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->coins1of2pk[0], cp->coins1of2pk[1]);
|
||||
cond = othercond1of2;
|
||||
}
|
||||
// check if this is spending from 1of2 cc tokens addr:
|
||||
else if (strcmp(cp->tokens1of2addr, destaddr) == 0)
|
||||
{
|
||||
//fprintf(stderr,"FinalizeCCTx() matched %s cp->tokens1of2addr!\n", cp->tokens1of2addr);
|
||||
privkey = myprivkey;
|
||||
if (othercond1of2tokens == 0)
|
||||
othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->tokens1of2pk[0], cp->tokens1of2pk[1]);
|
||||
cond = othercond1of2tokens;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr);
|
||||
continue;
|
||||
flag = 0;
|
||||
if ( pubkeys != NULL_pubkeys )
|
||||
{
|
||||
char coinaddr[64];
|
||||
GetCCaddress1of2(cp,coinaddr,globalpk,pubkeys[i]);
|
||||
//fprintf(stderr,"%s + %s -> %s vs %s\n",HexStr(globalpk).c_str(),HexStr(pubkeys[i]).c_str(),coinaddr,destaddr);
|
||||
if ( strcmp(destaddr,coinaddr) == 0 )
|
||||
{
|
||||
privkey = cp->CCpriv;
|
||||
if ( othercond4 != 0 )
|
||||
cc_free(othercond4);
|
||||
othercond4 = MakeCCcond1of2(cp->evalcode,globalpk,pubkeys[i]);
|
||||
cond = othercond4;
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
if ( flag == 0 )
|
||||
{
|
||||
fprintf(stderr,"CC signing error: 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 )
|
||||
@@ -178,6 +260,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"vini.%d has CC signing error address.(%s)\n",i,destaddr);
|
||||
return("");
|
||||
}
|
||||
}
|
||||
} else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str());
|
||||
@@ -190,6 +273,8 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
|
||||
cc_free(othercond2);
|
||||
if ( othercond3 != 0 )
|
||||
cc_free(othercond3);
|
||||
if ( othercond4 != 0 )
|
||||
cc_free(othercond4);
|
||||
std::string strHex = EncodeHexTx(mtx);
|
||||
if ( strHex.size() > 0 )
|
||||
return(strHex);
|
||||
@@ -247,6 +332,40 @@ int64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout)
|
||||
return(0);
|
||||
}
|
||||
|
||||
int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag)
|
||||
{
|
||||
CCoins coins;
|
||||
if ( mempoolflag != 0 )
|
||||
{
|
||||
LOCK(mempool.cs);
|
||||
CCoinsViewMemPool view(pcoinsTip, mempool);
|
||||
if (!view.GetCoins(txid, coins))
|
||||
return(-1);
|
||||
if ( myIsutxo_spentinmempool(txid,vout) != 0 )
|
||||
return(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pcoinsTip->GetCoins(txid, coins))
|
||||
return(-1);
|
||||
}
|
||||
if ( vout < coins.vout.size() )
|
||||
return(coins.vout[vout].nValue);
|
||||
else return(-1);
|
||||
}
|
||||
|
||||
int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256 txid,int32_t vout)
|
||||
{
|
||||
CSpentIndexKey key(txid, vout);
|
||||
CSpentIndexValue value;
|
||||
if ( !GetSpentIndex(key, value) )
|
||||
return(-1);
|
||||
spenttxid = value.txid;
|
||||
vini = (int32_t)value.inputIndex;
|
||||
height = value.blockHeight;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t CCaddress_balance(char *coinaddr)
|
||||
{
|
||||
int64_t sum = 0; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
@@ -263,7 +382,7 @@ int64_t CCfullsupply(uint256 tokenid)
|
||||
uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector<uint8_t> origpubkey; std::string name,description;
|
||||
if ( GetTransaction(tokenid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
|
||||
{
|
||||
if ( DecodeAssetCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description) > 0 )
|
||||
if (DecodeTokenCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description))
|
||||
{
|
||||
return(tx.vout[0].nValue);
|
||||
}
|
||||
@@ -273,8 +392,11 @@ int64_t CCfullsupply(uint256 tokenid)
|
||||
|
||||
int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
|
||||
{
|
||||
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; std::vector<uint8_t> origpubkey;
|
||||
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock;
|
||||
std::vector<uint8_t> vopretExtra;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
uint8_t evalCode;
|
||||
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
|
||||
{
|
||||
@@ -282,7 +404,8 @@ int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
|
||||
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
|
||||
{
|
||||
char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN);
|
||||
if ( DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 && assetid == tokenid )
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
if ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, voutTokenPubkeys, vopretExtra) != 0 && assetid == tokenid )
|
||||
{
|
||||
sum += it->second.satoshis;
|
||||
}
|
||||
@@ -350,8 +473,8 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
|
||||
{
|
||||
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=64; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up;
|
||||
#ifdef ENABLE_WALLET
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
assert(pwalletMain != NULL);
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
|
||||
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
|
||||
|
||||
@@ -76,6 +76,54 @@ CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2)
|
||||
return(vout);
|
||||
}
|
||||
|
||||
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2)
|
||||
{
|
||||
// make 1of2 sigs cond
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk1));
|
||||
pks.push_back(CCNewSecp256k1(pk2));
|
||||
|
||||
std::vector<CC*> thresholds;
|
||||
thresholds.push_back( CCNewEval(E_MARSHAL(ss << evalcode)) );
|
||||
if( evalcode != EVAL_TOKENS ) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1of2()!
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
|
||||
thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc
|
||||
|
||||
return CCNewThreshold(thresholds.size(), thresholds);
|
||||
}
|
||||
|
||||
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk)
|
||||
{
|
||||
std::vector<CC*> pks;
|
||||
pks.push_back(CCNewSecp256k1(pk));
|
||||
|
||||
std::vector<CC*> thresholds;
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode)));
|
||||
if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1()!
|
||||
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
|
||||
thresholds.push_back(CCNewThreshold(1, pks)); // signature
|
||||
|
||||
return CCNewThreshold(thresholds.size(), thresholds);
|
||||
}
|
||||
|
||||
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeTokensCCcond1of2(evalcode, pk1, pk2);
|
||||
vout = CTxOut(nValue, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
|
||||
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk)
|
||||
{
|
||||
CTxOut vout;
|
||||
CC *payoutCond = MakeTokensCCcond1(evalcode, pk);
|
||||
vout = CTxOut(nValue, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
return(vout);
|
||||
}
|
||||
|
||||
CC* GetCryptoCondition(CScript const& scriptSig)
|
||||
{
|
||||
auto pc = scriptSig.begin();
|
||||
@@ -195,6 +243,22 @@ void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *
|
||||
strcpy(cp->unspendableaddr3,coinaddr);
|
||||
}
|
||||
|
||||
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 cryptocondition vout:
|
||||
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr)
|
||||
{
|
||||
cp->coins1of2pk[0] = pk1;
|
||||
cp->coins1of2pk[1] = pk2;
|
||||
strcpy(cp->coins1of2addr, coinaddr);
|
||||
}
|
||||
|
||||
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 tokens cryptocondition vout:
|
||||
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr)
|
||||
{
|
||||
cp->tokens1of2pk[0] = pk1;
|
||||
cp->tokens1of2pk[1] = pk2;
|
||||
strcpy(cp->tokens1of2addr, coinaddr);
|
||||
}
|
||||
|
||||
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
|
||||
{
|
||||
CTxDestination address; txnouttype whichType;
|
||||
@@ -287,6 +351,27 @@ bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
|
||||
return(_GetCCaddress(destaddr,cp->evalcode,pk));
|
||||
}
|
||||
|
||||
bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, CPubKey pk)
|
||||
{
|
||||
CC *payoutCond;
|
||||
destaddr[0] = 0;
|
||||
if ((payoutCond = MakeTokensCCcond1(evalcode, pk)) != 0)
|
||||
{
|
||||
Getscriptaddress(destaddr, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
}
|
||||
return(destaddr[0] != 0);
|
||||
}
|
||||
|
||||
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk)
|
||||
{
|
||||
destaddr[0] = 0;
|
||||
if (pk.size() == 0)
|
||||
pk = GetUnspendable(cp, 0);
|
||||
return(_GetTokensCCaddress(destaddr, cp->evalcode, pk));
|
||||
}
|
||||
|
||||
|
||||
bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2)
|
||||
{
|
||||
CC *payoutCond;
|
||||
@@ -299,17 +384,29 @@ bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubK
|
||||
return(destaddr[0] != 0);
|
||||
}
|
||||
|
||||
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue)
|
||||
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2)
|
||||
{
|
||||
CC *payoutCond;
|
||||
destaddr[0] = 0;
|
||||
if ((payoutCond = MakeTokensCCcond1of2(cp->evalcode, pk, pk2)) != 0)
|
||||
{
|
||||
Getscriptaddress(destaddr, CCPubKey(payoutCond));
|
||||
cc_free(payoutCond);
|
||||
}
|
||||
return(destaddr[0] != 0);
|
||||
}
|
||||
|
||||
bool ConstrainVout(CTxOut vout, int32_t CCflag, char *cmpaddr, int64_t nValue)
|
||||
{
|
||||
char destaddr[64];
|
||||
if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag )
|
||||
{
|
||||
fprintf(stderr,"constrain vout error isCC %d vs %d CCflag\n",vout.scriptPubKey.IsPayToCryptoCondition(),CCflag);
|
||||
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) )
|
||||
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:"");
|
||||
fprintf(stderr,"constrain vout error: check addr %s vs script addr %s\n", cmpaddr!=0?cmpaddr:"", destaddr!=0?destaddr:"");
|
||||
return(false);
|
||||
}
|
||||
else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || (
|
||||
@@ -502,3 +599,34 @@ bool komodo_txnotarizedconfirmed(uint256 txid)
|
||||
return (true);
|
||||
return (false);
|
||||
}
|
||||
|
||||
CPubKey check_signing_pubkey(CScript scriptSig)
|
||||
{
|
||||
|
||||
bool found = false;
|
||||
CPubKey pubkey;
|
||||
|
||||
auto findEval = [](CC *cond, struct CCVisitor _) {
|
||||
bool r = false;
|
||||
|
||||
if (cc_typeId(cond) == CC_Secp256k1) {
|
||||
*(CPubKey*)_.context=buf2pk(cond->publicKey);
|
||||
r = true;
|
||||
}
|
||||
// false for a match, true for continue
|
||||
return r ? 0 : 1;
|
||||
};
|
||||
|
||||
CC *cond = GetCryptoCondition(scriptSig);
|
||||
|
||||
if (cond) {
|
||||
CCVisitor visitor = { findEval, (uint8_t*)"", 0, &pubkey };
|
||||
bool out = !cc_visit(cond, visitor);
|
||||
cc_free(cond);
|
||||
|
||||
if (pubkey.IsValid()) {
|
||||
return pubkey;
|
||||
}
|
||||
}
|
||||
return CPubKey();
|
||||
}
|
||||
|
||||
@@ -45,32 +45,22 @@
|
||||
|
||||
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.1: CC output for marker
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
|
||||
|
||||
cancelbuy:
|
||||
vin.0: normal input
|
||||
vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
vin.2: CC marker from buyoffer for txfee
|
||||
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]
|
||||
vout.1: vin.2 back to users pubkey
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['o'] [assetid] 0 0 [origpubkey]
|
||||
|
||||
fillbuy:
|
||||
vin.0: normal input
|
||||
@@ -87,8 +77,9 @@
|
||||
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.1: CC output for marker
|
||||
vout.2: CC output for change (if any)
|
||||
vout.3: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey]
|
||||
|
||||
exchange:
|
||||
@@ -102,8 +93,10 @@
|
||||
cancel:
|
||||
vin.0: normal input
|
||||
vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx
|
||||
vin.2: CC marker from selloffer for txfee
|
||||
vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
|
||||
vout.1: normal output for change (if any)
|
||||
vout.1: vin.2 back to users pubkey
|
||||
vout.2: normal output for change (if any)
|
||||
vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
|
||||
|
||||
fillsell:
|
||||
@@ -133,45 +126,79 @@
|
||||
|
||||
|
||||
// tx validation
|
||||
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
static uint256 zero;
|
||||
CTxDestination address; CTransaction vinTx,createTx; uint256 hashBlock,assetid,assetid2; int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector<uint8_t> origpubkey,tmporigpubkey,ignorepubkey; uint8_t funcid; char destaddr[64],origaddr[64],CCaddr[64];
|
||||
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, evalCodeInOpret;
|
||||
char destaddr[64], origaddr[64], assetsCCaddr[64], userTokensCCaddr[64]; //, signleEvalTokensCCaddr[64];
|
||||
|
||||
//return true;
|
||||
|
||||
//CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL);
|
||||
//CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, NULL);
|
||||
//GetCCaddress(cpTokens, tokensUnspendableCCaddr, unspendableTokensPk);
|
||||
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
outputs = inputs = 0;
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
if ( (funcid= DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,remaining_price,origpubkey)) == 0 )
|
||||
return eval->Invalid("Invalid opreturn payload");
|
||||
|
||||
if (numvouts == 0)
|
||||
return eval->Invalid("AssetValidate: no vouts");
|
||||
|
||||
if((funcid = DecodeAssetTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 )
|
||||
return eval->Invalid("AssetValidate: invalid opreturn payload");
|
||||
|
||||
// find dual-eval tokens unspendable addr:
|
||||
char tokensUnspendableAddr[64];
|
||||
GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
|
||||
|
||||
// we need this for validating single-eval tokens' vins/vous:
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
// find single-eval token user cc addr:
|
||||
//GetCCaddress(cpTokens, signleEvalTokensCCaddr, pubkey2pk(origpubkey));
|
||||
|
||||
fprintf(stderr,"AssetValidate (%c)\n",funcid);
|
||||
if ( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid,createTx,hashBlock) == 0 )
|
||||
|
||||
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 )
|
||||
else if( funcid != 'o' && funcid != 'x' && assetid2 != zero && eval->GetTxUnconfirmed(assetid2, createTx, hashBlock) == 0 )
|
||||
return eval->Invalid("cant find asset2 create txid");
|
||||
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
|
||||
else if( IsCCInput(tx.vin[0].scriptSig) != 0 )
|
||||
return eval->Invalid("illegal asset vin0");
|
||||
else if ( numvouts < 1 )
|
||||
return eval->Invalid("no vouts");
|
||||
else if ( funcid != 'c' )
|
||||
else if( numvouts < 2 )
|
||||
return eval->Invalid("too few vouts"); // it was if(numvouts < 1) but it refers at least to vout[1] below
|
||||
else if( funcid != 'c' )
|
||||
{
|
||||
if ( funcid == 't' )
|
||||
/* if( funcid == 't' )
|
||||
starti = 0;
|
||||
else starti = 1;
|
||||
if ( assetid == zero )
|
||||
else
|
||||
starti = 1; */
|
||||
|
||||
if( assetid == zero )
|
||||
return eval->Invalid("illegal assetid");
|
||||
else if ( AssetExactAmounts(2, cp,inputs,starti,outputs,eval,tx,assetid) == false )
|
||||
return eval->Invalid("asset inputs != outputs");
|
||||
|
||||
else if (!AssetCalcAmounts(cpAssets, inputs, outputs, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs
|
||||
return false; // returns false if some problems with reading vintxes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch ( funcid )
|
||||
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");
|
||||
//if (evalCodeInOpret == EVAL_ASSETS)
|
||||
// return eval->Invalid("unexpected AssetValidate for createasset");
|
||||
// return
|
||||
return eval->Invalid("invalid asset funcid \'c\'");
|
||||
break;
|
||||
case 't': // transfer
|
||||
//vin.0: normal input
|
||||
@@ -179,36 +206,40 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//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 (%d %d)\n",(double)inputs/COIN,(double)outputs/COIN,preventCCvins,preventCCvouts);
|
||||
//if (inputs == 0)
|
||||
// return eval->Invalid("no asset inputs for transfer");
|
||||
//fprintf(stderr,"transfer preliminarily validated %.8f -> %.8f (%d %d)\n",(double)inputs/COIN,(double)outputs/COIN,preventCCvins,preventCCvouts);
|
||||
return eval->Invalid("invalid asset funcid \'t\'");
|
||||
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.1: CC output for marker
|
||||
//vout.2: normal output for change (if any)
|
||||
// vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
|
||||
if ( remaining_price == 0 )
|
||||
if( remaining_price == 0 )
|
||||
return eval->Invalid("illegal null amount for buyoffer");
|
||||
else if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[0],1,cpAssets->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);
|
||||
fprintf(stderr,"buy offer validated to destaddr.(%s)\n",cpAssets->unspendableCCaddr);
|
||||
break;
|
||||
|
||||
case 'o': // cancelbuy
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0]
|
||||
//vin.2: CC marker from buyoffer for txfee
|
||||
//vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey]
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.1: vin.2 back to users pubkey
|
||||
//vout.2: normal output for change (if any)
|
||||
//vout.n-1: opreturn [EVAL_ASSETS] ['o']
|
||||
if ( (nValue= AssetValidateBuyvin(cp,eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 )
|
||||
if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( ConstrainVout(tx.vout[0],0,origaddr,nValue) == 0 )
|
||||
else if( ConstrainVout(tx.vout[0],0, origaddr, nValue) == 0 )
|
||||
return eval->Invalid("invalid refund for cancelbuy");
|
||||
preventCCvins = 2;
|
||||
preventCCvins = 3;
|
||||
preventCCvouts = 0;
|
||||
fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origaddr);
|
||||
break;
|
||||
@@ -224,32 +255,33 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//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 )
|
||||
|
||||
if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( numvouts < 3 )
|
||||
else if( numvouts < 3 )
|
||||
return eval->Invalid("not enough vouts for fillbuy");
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
else if( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for fillbuy");
|
||||
else
|
||||
{
|
||||
if ( nValue != tx.vout[0].nValue+tx.vout[1].nValue )
|
||||
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 )
|
||||
else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, 0) == 0 ) // tokens on user cc addr
|
||||
return eval->Invalid("vout2 doesnt go to origpubkey fillbuy");
|
||||
else if ( inputs != tx.vout[2].nValue+tx.vout[3].nValue )
|
||||
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 )
|
||||
else if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, inputs) == 0 ) // tokens on user cc addr
|
||||
return eval->Invalid("vout2 doesnt match inputs fillbuy");
|
||||
else if ( ConstrainVout(tx.vout[1],0,0,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[1],0,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 )
|
||||
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 )
|
||||
else if( remaining_price != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
|
||||
if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) // coins on asset unspendable cc addr
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy");
|
||||
}
|
||||
}
|
||||
@@ -261,36 +293,43 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//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.1: CC output for marker
|
||||
//vout.2: CC output for change (if any)
|
||||
//vout.3: normal output for change (if any)
|
||||
//'s'.vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey]
|
||||
//'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey]
|
||||
preventCCvouts = 1;
|
||||
if ( remaining_price == 0 )
|
||||
preventCCvouts = 2;
|
||||
if( remaining_price == 0 )
|
||||
return eval->Invalid("illegal null remaining_price for selloffer");
|
||||
if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("invalid normal vout1 for sellvin");
|
||||
if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) // cc change
|
||||
{
|
||||
preventCCvouts++;
|
||||
if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer");
|
||||
else if ( tx.vout[0].nValue+tx.vout[1].nValue != inputs )
|
||||
return eval->Invalid("mismatched vout0+vout1 total for selloffer");
|
||||
} else if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,inputs) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer");
|
||||
if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // check also cc vout[0]
|
||||
return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
|
||||
else if( tx.vout[0].nValue + tx.vout[2].nValue != inputs )
|
||||
return eval->Invalid("mismatched vout0+vout2 total for selloffer");
|
||||
}
|
||||
else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // no cc change, just vout[0]
|
||||
return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
|
||||
//fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price);
|
||||
break;
|
||||
|
||||
case 'x': // cancel
|
||||
case 'x': // cancel
|
||||
//vin.0: normal input
|
||||
//vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx
|
||||
//vin.2: CC marker from selloffer for txfee
|
||||
//vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
|
||||
//vout.1: normal output for change (if any)
|
||||
//vout.1: vin.2 back to users pubkey
|
||||
//vout.2: 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 )
|
||||
|
||||
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 ) // NOTE:
|
||||
return(false);
|
||||
else if ( ConstrainVout(tx.vout[0],1,CCaddr,assetoshis) == 0 )
|
||||
else if( ConstrainVout(tx.vout[0], 1, userTokensCCaddr, assetoshis) == 0 )
|
||||
return eval->Invalid("invalid vout for cancel");
|
||||
preventCCvins = 2;
|
||||
preventCCvins = 3;
|
||||
preventCCvouts = 1;
|
||||
break;
|
||||
|
||||
@@ -303,31 +342,35 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//'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 )
|
||||
|
||||
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( numvouts < 3 )
|
||||
else if( numvouts < 3 )
|
||||
return eval->Invalid("not enough vouts for fillask");
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
else if( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for fillask");
|
||||
else
|
||||
{
|
||||
if ( assetoshis != tx.vout[0].nValue+tx.vout[1].nValue )
|
||||
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 )
|
||||
if( ValidateAskRemainder(remaining_price, tx.vout[0].nValue, assetoshis, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false )
|
||||
return eval->Invalid("mismatched remainder for fillask");
|
||||
else if ( ConstrainVout(tx.vout[1],1,0,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[1], 1, 0, 0) == 0 )
|
||||
return eval->Invalid("normal vout1 for fillask");
|
||||
else if ( ConstrainVout(tx.vout[2],0,origaddr,0) == 0 )
|
||||
else if( ConstrainVout(tx.vout[2], 0, origaddr, 0) == 0 )
|
||||
return eval->Invalid("normal vout1 for fillask");
|
||||
else if ( remaining_price != 0 )
|
||||
else if( remaining_price != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fill");
|
||||
//char tokensUnspendableAddr[64];
|
||||
//GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
|
||||
if ( ConstrainVout(tx.vout[0], 1, tokensUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/, 0) == 0 )
|
||||
return eval->Invalid("mismatched vout0 assets dual unspendable CCaddr for fill sell");
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"fill validated\n");
|
||||
break;
|
||||
case 'E': // fillexchange
|
||||
////////// not implemented yet ////////////
|
||||
return eval->Invalid("unexpected assets fillexchange funcid");
|
||||
break; // disable asset swaps
|
||||
//vin.0: normal input
|
||||
@@ -339,51 +382,63 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx
|
||||
//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(1, 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 )
|
||||
|
||||
//if ( AssetExactAmounts(false, cp,inputs,outputs,eval,tx,assetid2) == false )
|
||||
// eval->Invalid("asset2 inputs != outputs");
|
||||
|
||||
////////// not implemented yet ////////////
|
||||
if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 )
|
||||
return(false);
|
||||
else if ( numvouts < 3 )
|
||||
else if( numvouts < 3 )
|
||||
return eval->Invalid("not enough vouts for fillex");
|
||||
else if ( tmporigpubkey != origpubkey )
|
||||
else if( tmporigpubkey != origpubkey )
|
||||
return eval->Invalid("mismatched origpubkeys for fillex");
|
||||
else
|
||||
{
|
||||
if ( assetoshis != tx.vout[0].nValue+tx.vout[1].nValue )
|
||||
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 )
|
||||
else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
////////// not implemented yet ////////////
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 )
|
||||
if( ConstrainVout(tx.vout[2], 1, userTokensCCaddr, 0) == 0 )
|
||||
return eval->Invalid("vout2 doesnt go to origpubkey fillex");
|
||||
else if ( inputs != tx.vout[2].nValue+tx.vout[3].nValue )
|
||||
else if( inputs != tx.vout[2].nValue + tx.vout[3].nValue )
|
||||
{
|
||||
fprintf(stderr,"inputs %.8f != %.8f + %.8f\n",(double)inputs/COIN,(double)tx.vout[2].nValue/COIN,(double)tx.vout[3].nValue/COIN);
|
||||
return eval->Invalid("asset inputs doesnt match vout2+3 fillex");
|
||||
}
|
||||
}
|
||||
else if ( ConstrainVout(tx.vout[2],1,CCaddr,inputs) == 0 )
|
||||
////////// not implemented yet ////////////
|
||||
else if( ConstrainVout(tx.vout[2], 1, userTokensCCaddr, inputs) == 0 )
|
||||
return eval->Invalid("vout2 doesnt match inputs fillex");
|
||||
else if ( ConstrainVout(tx.vout[1],0,0,0) == 0 )
|
||||
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 )
|
||||
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 )
|
||||
else if( ConstrainVout(tx.vout[1], 1, 0, 0) == 0 )
|
||||
////////// not implemented yet ////////////
|
||||
return eval->Invalid("normal vout1 for fillex");
|
||||
else if ( remaining_price != 0 )
|
||||
else if( remaining_price != 0 )
|
||||
{
|
||||
if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 )
|
||||
if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) // TODO: unsure about this, but this is not impl yet anyway
|
||||
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillex");
|
||||
}
|
||||
}
|
||||
////////// not implemented yet ////////////
|
||||
fprintf(stderr,"fill validated\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,"illegal assets funcid.(%c)\n",funcid);
|
||||
return eval->Invalid("unexpected assets funcid");
|
||||
break;
|
||||
//break;
|
||||
}
|
||||
return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
|
||||
|
||||
// what does this do?
|
||||
bool bPrevent = PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts);
|
||||
std::cerr << "AssetsValidate() PreventCC returned=" << bPrevent << std::endl;
|
||||
return (bPrevent);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ bool AuctionExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransactio
|
||||
bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
return(false); // reject any auction CC for now
|
||||
return eval->Invalid("no validation yet");
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
|
||||
58
src/cc/cclib.cpp
Normal file
58
src/cc/cclib.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/******************************************************************************
|
||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||
* *
|
||||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
||||
* the top-level directory of this distribution for the individual copyright *
|
||||
* holder information and the developer policies on copyright and licensing. *
|
||||
* *
|
||||
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
||||
* SuperNET software, including this file may be copied, modified, propagated *
|
||||
* or distributed except according to the terms contained in the LICENSE file *
|
||||
* *
|
||||
* Removal or modification of this copyright notice is prohibited. *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <cryptoconditions.h>
|
||||
|
||||
#include "primitives/block.h"
|
||||
#include "primitives/transaction.h"
|
||||
#include "script/cc.h"
|
||||
#include "cc/eval.h"
|
||||
#include "cc/utils.h"
|
||||
#include "cc/CCinclude.h"
|
||||
#include "main.h"
|
||||
#include "chain.h"
|
||||
#include "core_io.h"
|
||||
#include "crosschain.h"
|
||||
|
||||
#define MYCCLIBNAME ((char *)"stub")
|
||||
|
||||
char *CClib_name() { return(MYCCLIBNAME); }
|
||||
|
||||
bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector<uint8_t> paramsNull,const CTransaction &txTo,unsigned int nIn)
|
||||
{
|
||||
uint8_t evalcode; int32_t height,from_mempool;
|
||||
if ( ASSETCHAINS_CCLIB != MYCCLIBNAME )
|
||||
{
|
||||
fprintf(stderr,"-ac_cclib=%s vs myname %s\n",ASSETCHAINS_CCLIB.c_str(),MYCCLIBNAME);
|
||||
return eval->Invalid("-ac_cclib name mismatches myname");
|
||||
}
|
||||
height = KOMODO_CONNECTING;
|
||||
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
|
||||
return(true);
|
||||
if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
|
||||
return eval->Invalid("CC are disabled or not active yet");
|
||||
if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
|
||||
{
|
||||
from_mempool = 1;
|
||||
height &= ((1<<30) - 1);
|
||||
}
|
||||
evalcode = cond->code[0];
|
||||
if ( evalcode >= EVAL_FIRSTUSER && evalcode <= EVAL_LASTUSER )
|
||||
{
|
||||
return(true);
|
||||
}
|
||||
return eval->Invalid("cclib CC must have evalcode between 16 and 127");
|
||||
}
|
||||
@@ -64,15 +64,16 @@ Possible third iteration:
|
||||
|
||||
int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub, CPubKey destpub,int32_t v)
|
||||
{
|
||||
char destaddr[65],channeladdr[65];
|
||||
char destaddr[65],channeladdr[65],tokenschanneladdr[65];
|
||||
|
||||
GetCCaddress1of2(cp,channeladdr,srcpub,destpub);
|
||||
GetTokensCCaddress1of2(cp,tokenschanneladdr,srcpub,destpub);
|
||||
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
{
|
||||
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,channeladdr) == 0 )
|
||||
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && (strcmp(destaddr,channeladdr) == 0 || strcmp(destaddr,tokenschanneladdr) == 0))
|
||||
return(tx.vout[v].nValue);
|
||||
}
|
||||
return(0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int64_t IsChannelsMarkervout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey pubkey,int32_t v)
|
||||
@@ -88,17 +89,31 @@ int64_t IsChannelsMarkervout(struct CCcontract_info *cp,const CTransaction& tx,C
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodeChannelsOpRet(uint8_t funcid,uint256 opentxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain)
|
||||
CScript EncodeChannelsOpRet(uint8_t funcid,uint256 tokenid,uint256 opentxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_CHANNELS;
|
||||
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << opentxid << srcpub << destpub << numpayments << payment << hashchain);
|
||||
if (tokenid!=zeroid)
|
||||
{
|
||||
std::vector<CPubKey> pks;
|
||||
pks.push_back(srcpub);
|
||||
pks.push_back(destpub);
|
||||
return(EncodeTokenOpRet(tokenid,pks,opret));
|
||||
}
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey,uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain)
|
||||
uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey, uint256 &tokenid, uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain)
|
||||
{
|
||||
std::vector<uint8_t> vopret; uint8_t *script,e,f;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
std::vector<uint8_t> vopret; uint8_t *script,e,f,tokenevalcode;
|
||||
std::vector<CPubKey> pubkeys; std::vector<uint8_t> vOpretExtra;
|
||||
|
||||
if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0)
|
||||
{
|
||||
if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0);
|
||||
}
|
||||
else GetOpReturnData(scriptPubKey, vopret);
|
||||
if ( vopret.size() > 2 )
|
||||
{
|
||||
script = (uint8_t *)vopret.data();
|
||||
@@ -115,46 +130,56 @@ uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey,uint256 &opentxid, CPubK
|
||||
|
||||
bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
|
||||
{
|
||||
static uint256 zerohash;
|
||||
uint256 txid,param3;
|
||||
uint256 txid,param3,tokenid;
|
||||
CPubKey srcpub,destpub;
|
||||
int32_t param1; int64_t param2; uint8_t funcid;
|
||||
CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
int32_t param1,numvouts; int64_t param2; uint8_t funcid;
|
||||
CTransaction vinTx; uint256 hashBlock; int64_t inputs=0,outputs=0;
|
||||
|
||||
if ((numvouts=tx.vout.size()) > 0 && DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)!=0)
|
||||
{
|
||||
for (i=0; i<numvins; i++)
|
||||
if ((numvouts=tx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, param1, param2, param3))!=0)
|
||||
{
|
||||
switch (funcid)
|
||||
{
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("cant find vinTx");
|
||||
else
|
||||
{
|
||||
inputs += vinTx.vout[tx.vin[i].prevout.n].nValue;
|
||||
}
|
||||
case 'O':
|
||||
return (true);
|
||||
case 'P':
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("cant find vinTx");
|
||||
inputs = vinTx.vout[tx.vin[1].prevout.n].nValue;
|
||||
outputs = tx.vout[0].nValue + tx.vout[3].nValue;
|
||||
break;
|
||||
case 'C':
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("cant find vinTx");
|
||||
inputs = vinTx.vout[tx.vin[1].prevout.n].nValue;
|
||||
outputs = tx.vout[0].nValue;
|
||||
break;
|
||||
case 'R':
|
||||
if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 )
|
||||
return eval->Invalid("cant find vinTx");
|
||||
inputs = vinTx.vout[tx.vin[1].prevout.n].nValue;
|
||||
outputs = tx.vout[2].nValue;
|
||||
break;
|
||||
default:
|
||||
return (false);
|
||||
}
|
||||
if ( inputs != outputs )
|
||||
{
|
||||
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
|
||||
return eval->Invalid("mismatched inputs != outputs");
|
||||
}
|
||||
else return (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return eval->Invalid("invalid op_return data");
|
||||
}
|
||||
for (i=0; i<numvouts; i++)
|
||||
{
|
||||
outputs += tx.vout[i].nValue;
|
||||
}
|
||||
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);
|
||||
return(false);
|
||||
}
|
||||
|
||||
bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,p1,param1; bool retval;
|
||||
uint256 txid,hashblock,p3,param3,opentxid,tmp_txid,genhashchain,hashchain;
|
||||
uint256 txid,hashblock,p3,param3,opentxid,tmp_txid,genhashchain,hashchain,tokenid;
|
||||
uint8_t funcid,hash[32],hashdest[32];
|
||||
int64_t p2,param2,payment;
|
||||
CPubKey srcpub, destpub;
|
||||
@@ -169,15 +194,13 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
{
|
||||
if (ChannelsExactAmounts(cp,eval,tx,1,10000) == false )
|
||||
{
|
||||
fprintf(stderr,"Channelsget invalid amount\n");
|
||||
return false;
|
||||
return eval->Invalid("invalid channel inputs vs. outputs!");
|
||||
}
|
||||
else
|
||||
{
|
||||
txid = tx.GetHash();
|
||||
memcpy(hash,&txid,sizeof(hash));
|
||||
|
||||
if ( (funcid = DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, opentxid, srcpub, destpub, param1, param2, param3)) != 0)
|
||||
if ( (funcid = DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, tokenid, opentxid, srcpub, destpub, param1, param2, param3)) != 0)
|
||||
{
|
||||
switch ( funcid )
|
||||
{
|
||||
@@ -213,9 +236,13 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
return eval->Invalid("vout.1 is CC for channelPayment (marker to srcPub)!");
|
||||
else if ( IsChannelsMarkervout(cp,tx,destpub,2)==0 )
|
||||
return eval->Invalid("vout.2 is CC for channelPayment (marker to dstPub)!");
|
||||
else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
else if ( tokenid!=zeroid && tx.vout[3].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("vout.3 is CC for channelPayment!");
|
||||
else if ( tokenid==zeroid && tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
return eval->Invalid("vout.3 is normal for channelPayment!");
|
||||
else if ( tx.vout[3].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)
|
||||
else if ( tokenid!=zeroid && tx.vout[3].scriptPubKey!=MakeCC1vout(EVAL_TOKENS,tx.vout[3].nValue,destpub).scriptPubKey)
|
||||
return eval->Invalid("payment funds do not go to receiver!");
|
||||
else if ( tokenid==zeroid && tx.vout[3].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)
|
||||
return eval->Invalid("payment funds do not go to receiver!");
|
||||
else if ( param1 > CHANNELS_MAXPAYMENTS)
|
||||
return eval->Invalid("too many payment increments!");
|
||||
@@ -223,7 +250,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
{
|
||||
if (myGetTransaction(opentxid,channelOpenTx,hashblock) != 0)
|
||||
{
|
||||
if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O')
|
||||
if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O')
|
||||
return eval->Invalid("invalid channelopen OP_RETURN data!");
|
||||
endiancpy(hash, (uint8_t * ) & param3, 32);
|
||||
for (i = 0; i < numpayments-param1; i++)
|
||||
@@ -239,7 +266,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
}
|
||||
if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
|
||||
{
|
||||
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
|
||||
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
|
||||
return eval->Invalid("invalid previous tx OP_RETURN data!");
|
||||
else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey)
|
||||
return eval->Invalid("invalid destination for sender marker!");
|
||||
@@ -279,13 +306,13 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
return eval->Invalid("too many payment increments!");
|
||||
else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0)
|
||||
return eval->Invalid("invalid open txid!");
|
||||
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
|
||||
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
|
||||
return eval->Invalid("invalid channelopen OP_RETURN data!");
|
||||
else if (tx.vout[0].nValue != param1*payment)
|
||||
return eval->Invalid("vout amount does not match number_of_payments*payment!");
|
||||
else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
|
||||
{
|
||||
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
|
||||
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
|
||||
return eval->Invalid("invalid previous tx OP_RETURN data!");
|
||||
else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey)
|
||||
return eval->Invalid("invalid destination for sender marker!");
|
||||
@@ -318,19 +345,23 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
return eval->Invalid("vout.0 is CC for channelRefund (marker to srcPub)!");
|
||||
else if ( IsChannelsMarkervout(cp,tx,destpub,1)==0 )
|
||||
return eval->Invalid("vout.1 is CC for channelRefund (marker to dstPub)!");
|
||||
else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
return eval->Invalid("vout.2 is normal for channelRefund!");
|
||||
else if ( tx.vout[2].scriptPubKey!=CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG)
|
||||
else if ( tokenid!=zeroid && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 )
|
||||
return eval->Invalid("vout.2 is CC for channelPayment!");
|
||||
else if ( tokenid==zeroid && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 )
|
||||
return eval->Invalid("vout.2 is normal for channelPayment!");
|
||||
else if ( tokenid!=zeroid && tx.vout[2].scriptPubKey!=MakeCC1vout(EVAL_TOKENS,tx.vout[2].nValue,srcpub).scriptPubKey)
|
||||
return eval->Invalid("payment funds do not go to sender!");
|
||||
else if ( tokenid==zeroid && tx.vout[2].scriptPubKey!=CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG)
|
||||
return eval->Invalid("payment funds do not go to sender!");
|
||||
else if ( param1 > CHANNELS_MAXPAYMENTS)
|
||||
return eval->Invalid("too many payment increments!");
|
||||
else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0)
|
||||
return eval->Invalid("invalid open txid!");
|
||||
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
|
||||
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
|
||||
return eval->Invalid("invalid channelopen OP_RETURN data!");
|
||||
else if (myGetTransaction(param3,channelCloseTx,hashblock) == 0)
|
||||
return eval->Invalid("invalid close txid!");
|
||||
else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, param1, param2, param3) != 'C')
|
||||
else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, param1, param2, param3) != 'C')
|
||||
return eval->Invalid("invalid channelclose OP_RETURN data!");
|
||||
else if (tmp_txid!=opentxid)
|
||||
return eval->Invalid("invalid close tx, opentxid do not match on close and refund!");
|
||||
@@ -338,7 +369,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
return eval->Invalid("vout amount does not match number_of_payments*payment!");
|
||||
else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
|
||||
{
|
||||
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
|
||||
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
|
||||
return eval->Invalid("invalid previous tx OP_RETURN data!");
|
||||
else if (tx.vout[0].scriptPubKey != prevTx.vout[1].scriptPubKey)
|
||||
return eval->Invalid("invalid destination for sender marker!");
|
||||
@@ -351,9 +382,9 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
default:
|
||||
fprintf(stderr,"illegal channels funcid.(%c)\n",funcid);
|
||||
return eval->Invalid("unexpected channels funcid");
|
||||
break;
|
||||
}
|
||||
} else return eval->Invalid("unexpected channels missing funcid");
|
||||
}
|
||||
else return eval->Invalid("unexpected channels missing funcid");
|
||||
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
|
||||
if ( retval != 0 )
|
||||
fprintf(stderr,"Channel tx validated\n");
|
||||
@@ -368,14 +399,15 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
|
||||
int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, CTransaction openTx, uint256 &prevtxid, CPubKey mypk)
|
||||
{
|
||||
char coinaddr[65]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t marker,param1;
|
||||
char coinaddr[65]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3,tokenid; CTransaction tx; int32_t marker,param1;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
CPubKey srcpub,destpub;
|
||||
uint8_t myprivkey[32];
|
||||
|
||||
if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)=='O')
|
||||
if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3)=='O')
|
||||
{
|
||||
GetCCaddress1of2(cp,coinaddr,srcpub,destpub);
|
||||
if (tokenid!=zeroid) GetTokensCCaddress1of2(cp,coinaddr,srcpub,destpub);
|
||||
else GetCCaddress1of2(cp,coinaddr,srcpub,destpub);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
}
|
||||
else
|
||||
@@ -389,9 +421,9 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C
|
||||
{
|
||||
if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0)
|
||||
{
|
||||
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 &&
|
||||
(tmp_txid==openTx.GetHash() || tx.GetHash()==openTx.GetHash()) &&
|
||||
(totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0)+IsChannelsMarkervout(cp,tx,srcpub,marker))>0)
|
||||
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 &&
|
||||
(tmp_txid==openTx.GetHash() || tx.GetHash()==openTx.GetHash()) && IsChannelsMarkervout(cp,tx,marker==1?srcpub:destpub,marker)>0 &&
|
||||
(totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0))>0)
|
||||
{
|
||||
txid = it->first.txhash;
|
||||
break;
|
||||
@@ -407,11 +439,11 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C
|
||||
const CTransaction &txmempool = e.GetTx();
|
||||
const uint256 &hash = txmempool.GetHash();
|
||||
|
||||
if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) != 0 &&
|
||||
if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) != 0 &&
|
||||
tmp_txid==openTx.GetHash() && param1 < mindepth)
|
||||
{
|
||||
txid=hash;
|
||||
totalinputs=txmempool.vout[0].nValue+txmempool.vout[1].nValue;
|
||||
totalinputs=txmempool.vout[0].nValue;
|
||||
mindepth=param1;
|
||||
}
|
||||
}
|
||||
@@ -421,19 +453,19 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C
|
||||
prevtxid=txid;
|
||||
mtx.vin.push_back(CTxIn(txid,0,CScript()));
|
||||
mtx.vin.push_back(CTxIn(txid,marker,CScript()));
|
||||
Myprivkey(myprivkey);
|
||||
CCaddr2set(cp,EVAL_CHANNELS,srcpub,myprivkey,coinaddr);
|
||||
CCaddr3set(cp,EVAL_CHANNELS,destpub,myprivkey,coinaddr);
|
||||
Myprivkey(myprivkey);
|
||||
if (tokenid!=zeroid) CCaddrTokens1of2set(cp,srcpub,destpub,coinaddr);
|
||||
else CCaddr1of2set(cp,srcpub,destpub,coinaddr);
|
||||
return totalinputs;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment)
|
||||
std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment, uint256 tokenid)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy;
|
||||
CPubKey mypk; struct CCcontract_info *cp,C;
|
||||
uint8_t hash[32],hashdest[32]; uint64_t amount,tokens=0,funds; int32_t i; uint256 hashchain,entropy,hentropy;
|
||||
CPubKey mypk; struct CCcontract_info *cp,*cpTokens,C,CTokens;
|
||||
|
||||
if ( numpayments <= 0 || payment <= 0 || numpayments > CHANNELS_MAXPAYMENTS )
|
||||
{
|
||||
@@ -442,11 +474,18 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
|
||||
return("");
|
||||
}
|
||||
cp = CCinit(&C,EVAL_CHANNELS);
|
||||
cpTokens = CCinit(&CTokens,EVAL_TOKENS);
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
funds = numpayments * payment;
|
||||
if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 )
|
||||
if (tokenid!=zeroid)
|
||||
{
|
||||
amount=AddNormalinputs(mtx,mypk,3*txfee,5);
|
||||
tokens=AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, funds, 64);
|
||||
}
|
||||
else amount=AddNormalinputs(mtx,mypk,funds+3*txfee,64);
|
||||
if (amount+tokens >= funds+2*txfee)
|
||||
{
|
||||
hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1);
|
||||
endiancpy(hash,(uint8_t *)&hentropy,32);
|
||||
@@ -456,10 +495,12 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
|
||||
memcpy(hash,hashdest,32);
|
||||
}
|
||||
endiancpy((uint8_t *)&hashchain,hashdest,32);
|
||||
mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub));
|
||||
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub));
|
||||
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',zeroid,mypk,destpub,numpayments,payment,hashchain)));
|
||||
if (tokenid!=zeroid && tokens>funds) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,tokens-funds,mypk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',tokenid,zeroid,mypk,destpub,numpayments,payment,hashchain)));
|
||||
}
|
||||
return("");
|
||||
}
|
||||
@@ -467,7 +508,7 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
|
||||
std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,gensecret,hashblock,entropy,hentropy,prevtxid,param3;
|
||||
CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,gensecret,hashblock,entropy,hentropy,prevtxid,param3,tokenid;
|
||||
struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments,totalnumpayments;
|
||||
int64_t payment,change,funds,param2;
|
||||
uint8_t hash[32],hashdest[32];
|
||||
@@ -482,83 +523,85 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
|
||||
fprintf(stderr, "invalid channel open txid\n");
|
||||
return ("");
|
||||
}
|
||||
if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O')
|
||||
{
|
||||
if (mypk != srcpub && mypk != destpub)
|
||||
{
|
||||
fprintf(stderr,"this is not our channel\n");
|
||||
return("");
|
||||
}
|
||||
else if (amount % payment != 0 || amount<payment)
|
||||
{
|
||||
fprintf(stderr,"invalid amount, not a magnitude of payment size\n");
|
||||
return ("");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "invalid channel open tx\n");
|
||||
return ("");
|
||||
}
|
||||
if (AddNormalinputs(mtx,mypk,2*txfee,3) > 0)
|
||||
{
|
||||
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && (change=funds-amount-txfee)>=0)
|
||||
{
|
||||
if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O')
|
||||
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && (change=funds-amount)>=0)
|
||||
{
|
||||
numpayments=amount/payment;
|
||||
if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0 && (numvouts=prevTx.vout.size()) > 0 &&
|
||||
((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, prevdepth, param2, param3)) != 0) &&
|
||||
(funcid == 'P' || funcid=='O'))
|
||||
{
|
||||
if (mypk != srcpub && mypk != destpub)
|
||||
if (numpayments > prevdepth)
|
||||
{
|
||||
fprintf(stderr,"this is not our channel\n");
|
||||
return("");
|
||||
}
|
||||
else if (amount % payment != 0 || amount<payment)
|
||||
fprintf(stderr,"not enough funds in channel for that amount\n");
|
||||
return ("");
|
||||
} else if (numpayments == 0)
|
||||
{
|
||||
fprintf(stderr,"invalid amount, not a magnitude of payment size\n");
|
||||
fprintf(stderr,"invalid amount\n");
|
||||
return ("");
|
||||
}
|
||||
numpayments=amount/payment;
|
||||
if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0 && (numvouts=prevTx.vout.size()) > 0 &&
|
||||
((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, param2, param3)) != 0) &&
|
||||
(funcid == 'P' || funcid=='O'))
|
||||
if (secret!=zeroid)
|
||||
{
|
||||
if (numpayments > prevdepth)
|
||||
endiancpy(hash, (uint8_t * ) & secret, 32);
|
||||
for (i = 0; i < totalnumpayments-(prevdepth-numpayments); i++)
|
||||
{
|
||||
fprintf(stderr,"not enough funds in channel for that amount\n");
|
||||
return ("");
|
||||
} else if (numpayments == 0)
|
||||
{
|
||||
fprintf(stderr,"invalid amount\n");
|
||||
return ("");
|
||||
vcalc_sha256(0, hashdest, hash, 32);
|
||||
memcpy(hash, hashdest, 32);
|
||||
}
|
||||
if (secret!=zeroid)
|
||||
endiancpy((uint8_t * ) & gensecret, hashdest, 32);
|
||||
if (gensecret!=hashchain)
|
||||
{
|
||||
endiancpy(hash, (uint8_t * ) & secret, 32);
|
||||
for (i = 0; i < totalnumpayments-(prevdepth-numpayments); i++)
|
||||
{
|
||||
vcalc_sha256(0, hashdest, hash, 32);
|
||||
memcpy(hash, hashdest, 32);
|
||||
}
|
||||
endiancpy((uint8_t * ) & gensecret, hashdest, 32);
|
||||
if (gensecret!=hashchain)
|
||||
{
|
||||
fprintf(stderr,"invalid secret supplied\n");
|
||||
return("");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hentropy = DiceHashEntropy(entropy,channelOpenTx.vin[0].prevout.hash,channelOpenTx.vin[0].prevout.n,1);
|
||||
if (prevdepth-numpayments)
|
||||
{
|
||||
endiancpy(hash, (uint8_t * ) & hentropy, 32);
|
||||
for (i = 0; i < prevdepth-numpayments; i++)
|
||||
{
|
||||
vcalc_sha256(0, hashdest, hash, 32);
|
||||
memcpy(hash, hashdest, 32);
|
||||
}
|
||||
endiancpy((uint8_t * ) & secret, hashdest, 32);
|
||||
}
|
||||
else endiancpy((uint8_t * ) & secret, (uint8_t * ) & hentropy, 32);
|
||||
fprintf(stderr,"invalid secret supplied\n");
|
||||
return("");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"invalid previous tx\n");
|
||||
return("");
|
||||
hentropy = DiceHashEntropy(entropy,channelOpenTx.vin[0].prevout.hash,channelOpenTx.vin[0].prevout.n,1);
|
||||
if (prevdepth-numpayments)
|
||||
{
|
||||
endiancpy(hash, (uint8_t * ) & hentropy, 32);
|
||||
for (i = 0; i < prevdepth-numpayments; i++)
|
||||
{
|
||||
vcalc_sha256(0, hashdest, hash, 32);
|
||||
memcpy(hash, hashdest, 32);
|
||||
}
|
||||
endiancpy((uint8_t * ) & secret, hashdest, 32);
|
||||
}
|
||||
else endiancpy((uint8_t * ) & secret, (uint8_t * ) & hentropy, 32);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "invalid channel open tx\n");
|
||||
return ("");
|
||||
}
|
||||
mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub));
|
||||
fprintf(stderr,"invalid previous tx\n");
|
||||
return("");
|
||||
}
|
||||
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub));
|
||||
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,srcpub));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
|
||||
mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG));
|
||||
return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', opentxid, srcpub, destpub, prevdepth-numpayments, numpayments, secret)));
|
||||
if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, amount, destpub));
|
||||
else mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG));
|
||||
return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', tokenid, opentxid, srcpub, destpub, prevdepth-numpayments, numpayments, secret)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -575,7 +618,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid)
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk,srcpub,destpub; struct CCcontract_info *cp,C;
|
||||
CTransaction channelOpenTx;
|
||||
uint256 hashblock,tmp_txid,prevtxid,hashchain;
|
||||
uint256 hashblock,tmp_txid,prevtxid,hashchain,tokenid;
|
||||
int32_t numvouts,numpayments;
|
||||
int64_t payment,funds;
|
||||
|
||||
@@ -589,7 +632,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid)
|
||||
fprintf(stderr, "invalid channel open txid\n");
|
||||
return ("");
|
||||
}
|
||||
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
|
||||
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
|
||||
{
|
||||
fprintf(stderr, "invalid channel open tx\n");
|
||||
return ("");
|
||||
@@ -603,10 +646,11 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid)
|
||||
{
|
||||
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds-txfee>0)
|
||||
{
|
||||
mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds-txfee, mypk, destpub));
|
||||
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, funds-txfee, mypk, destpub));
|
||||
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds-txfee, mypk, destpub));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',opentxid,mypk,destpub,(funds-txfee)/payment,payment,zeroid)));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',tokenid,opentxid,mypk,destpub,(funds-txfee)/payment,payment,zeroid)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -623,10 +667,9 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CPubKey mypk; struct CCcontract_info *cp,C; int64_t funds,payment,param2;
|
||||
int32_t i,numpayments,numvouts,param1;
|
||||
uint256 hashchain,hashblock,txid,prevtxid,param3,entropy,hentropy,secret;
|
||||
uint256 hashchain,hashblock,txid,prevtxid,param3,tokenid;
|
||||
CTransaction channelOpenTx,channelCloseTx,prevTx;
|
||||
CPubKey srcpub,destpub;
|
||||
uint8_t funcid,hash[32],hashdest[32];;
|
||||
|
||||
// verify stoptxid and origtxid match and are mine
|
||||
cp = CCinit(&C,EVAL_CHANNELS);
|
||||
@@ -638,7 +681,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
|
||||
fprintf(stderr, "invalid channel close txid\n");
|
||||
return ("");
|
||||
}
|
||||
if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,param1,param2,param3)!='C')
|
||||
if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,param1,param2,param3)!='C')
|
||||
{
|
||||
fprintf(stderr, "invalid channel close tx\n");
|
||||
return ("");
|
||||
@@ -653,7 +696,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
|
||||
fprintf(stderr, "invalid channel open txid\n");
|
||||
return ("");
|
||||
}
|
||||
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
|
||||
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
|
||||
{
|
||||
fprintf(stderr, "invalid channel open tx\n");
|
||||
return ("");
|
||||
@@ -668,20 +711,13 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
|
||||
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds-txfee>0)
|
||||
{
|
||||
if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 0 &&
|
||||
DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3) != 0)
|
||||
DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, param1, param2, param3) != 0)
|
||||
{
|
||||
hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash, channelOpenTx.vin[0].prevout.n,1);
|
||||
endiancpy(hash, (uint8_t * ) & hentropy, 32);
|
||||
for (i = 0; i < param1; i++)
|
||||
{
|
||||
vcalc_sha256(0, hashdest, hash, 32);
|
||||
memcpy(hash, hashdest, 32);
|
||||
}
|
||||
endiancpy((uint8_t * ) & secret, hashdest, 32);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
|
||||
mtx.vout.push_back(CTxOut(funds-txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,destpub,param1,payment,closetxid)));
|
||||
if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,funds-txfee,mypk));
|
||||
else mtx.vout.push_back(CTxOut(funds-txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',tokenid,opentxid,mypk,destpub,param1,payment,closetxid)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -699,7 +735,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
|
||||
}
|
||||
UniValue ChannelsList()
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); std::vector<std::pair<CAddressIndexKey, CAmount> > txids; struct CCcontract_info *cp,C; uint256 txid,hashBlock,tmp_txid,param3;
|
||||
UniValue result(UniValue::VOBJ); std::vector<std::pair<CAddressIndexKey, CAmount> > txids; struct CCcontract_info *cp,C; uint256 txid,hashBlock,tmp_txid,param3,tokenid;
|
||||
CTransaction tx; char myCCaddr[65],addr[65],str[256]; CPubKey mypk,srcpub,destpub; int32_t vout,numvouts,param1;
|
||||
int64_t nValue,param2;
|
||||
|
||||
@@ -716,7 +752,7 @@ UniValue ChannelsList()
|
||||
nValue = (int64_t)it->second;
|
||||
if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
|
||||
{
|
||||
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O')
|
||||
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O')
|
||||
{
|
||||
GetCCaddress1of2(cp,addr,srcpub,destpub);
|
||||
sprintf(str,"%s - %lld payments of %lld satoshi",addr,(long long)param1,(long long)param2);
|
||||
@@ -729,16 +765,16 @@ UniValue ChannelsList()
|
||||
|
||||
UniValue ChannelsInfo(uint256 channeltxid)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ),array(UniValue::VARR); CTransaction tx,opentx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain,prevtxid;
|
||||
UniValue result(UniValue::VOBJ),array(UniValue::VARR); CTransaction tx,opentx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain,prevtxid,tokenid;
|
||||
struct CCcontract_info *cp,C; char CCaddr[65],addr[65],str[512]; int32_t vout,numvouts,param1,numpayments;
|
||||
int64_t nValue,param2,payment; CPubKey srcpub,destpub,mypk;
|
||||
int64_t param2,payment; CPubKey srcpub,destpub,mypk;
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; std::vector<uint256> txids;
|
||||
|
||||
cp = CCinit(&C,EVAL_CHANNELS);
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
|
||||
if (GetTransaction(channeltxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 &&
|
||||
(DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O'))
|
||||
(DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,opentxid,srcpub,destpub,param1,param2,param3) == 'O'))
|
||||
{
|
||||
GetCCaddress(cp,CCaddr,mypk);
|
||||
Getscriptaddress(addr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG);
|
||||
@@ -746,13 +782,22 @@ UniValue ChannelsInfo(uint256 channeltxid)
|
||||
result.push_back(Pair("Channel CC address",CCaddr));
|
||||
result.push_back(Pair("Destination address",addr));
|
||||
result.push_back(Pair("Number of payments",param1));
|
||||
result.push_back(Pair("Denomination",i64tostr(param2)+" satoshi"));
|
||||
result.push_back(Pair("Amount",i64tostr(param1*param2)+" satoshi"));
|
||||
if(tokenid!=zeroid)
|
||||
{
|
||||
result.push_back(Pair("Token id",tokenid.GetHex().data()));
|
||||
result.push_back(Pair("Denomination (token satoshi)",i64tostr(param2)));
|
||||
result.push_back(Pair("Amount (token satoshi)",i64tostr(param1*param2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(Pair("Denomination (satoshi)",i64tostr(param2)));
|
||||
result.push_back(Pair("Amount (satoshi)",i64tostr(param1*param2)));
|
||||
}
|
||||
SetCCtxids(addressIndex,CCaddr);
|
||||
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
|
||||
{
|
||||
if (GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
|
||||
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && (tmp_txid==channeltxid || tx.GetHash()==channeltxid))
|
||||
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && (tmp_txid==channeltxid || tx.GetHash()==channeltxid))
|
||||
txids.push_back(it->first.txhash);
|
||||
}
|
||||
BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx)
|
||||
@@ -760,7 +805,7 @@ UniValue ChannelsInfo(uint256 channeltxid)
|
||||
const CTransaction &txmempool = e.GetTx();
|
||||
const uint256 &hash = txmempool.GetHash();
|
||||
|
||||
if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'P' && tmp_txid==channeltxid)
|
||||
if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) == 'P' && tmp_txid==channeltxid)
|
||||
txids.push_back(hash);
|
||||
}
|
||||
prevtxid=zeroid;
|
||||
@@ -770,14 +815,14 @@ UniValue ChannelsInfo(uint256 channeltxid)
|
||||
if (txid!=prevtxid && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
|
||||
{
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O' && tx.GetHash()==channeltxid)
|
||||
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O' && tx.GetHash()==channeltxid)
|
||||
{
|
||||
obj.push_back(Pair("Open",txid.GetHex().data()));
|
||||
}
|
||||
else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'P' && opentxid==channeltxid)
|
||||
else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,opentxid,srcpub,destpub,param1,param2,param3) == 'P' && opentxid==channeltxid)
|
||||
{
|
||||
if (GetTransaction(opentxid,opentx,hashBlock,false) != 0 && (numvouts=opentx.vout.size()) > 0 &&
|
||||
DecodeChannelsOpRet(opentx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O')
|
||||
DecodeChannelsOpRet(opentx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O')
|
||||
{
|
||||
Getscriptaddress(str,tx.vout[3].scriptPubKey);
|
||||
obj.push_back(Pair("Payment",txid.GetHex().data()));
|
||||
@@ -788,11 +833,11 @@ UniValue ChannelsInfo(uint256 channeltxid)
|
||||
obj.push_back(Pair("Payments left",param1));
|
||||
}
|
||||
}
|
||||
else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C' && opentxid==channeltxid)
|
||||
else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,opentxid,srcpub,destpub,param1,param2,param3) == 'C' && opentxid==channeltxid)
|
||||
{
|
||||
obj.push_back(Pair("Close",txid.GetHex().data()));
|
||||
}
|
||||
else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'R' && opentxid==channeltxid)
|
||||
else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,opentxid,srcpub,destpub,param1,param2,param3) == 'R' && opentxid==channeltxid)
|
||||
{
|
||||
Getscriptaddress(str,tx.vout[2].scriptPubKey);
|
||||
obj.push_back(Pair("Refund",txid.GetHex().data()));
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "core_io.h"
|
||||
#include "crosschain.h"
|
||||
|
||||
bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector<uint8_t> paramsNull,const CTransaction &txTo,unsigned int nIn);
|
||||
char *CClib_name();
|
||||
|
||||
Eval* EVAL_TEST = 0;
|
||||
struct CCcontract_info CCinfos[0x100];
|
||||
@@ -38,8 +40,9 @@ bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn)
|
||||
pthread_mutex_lock(&KOMODO_CC_mutex);
|
||||
bool out = eval->Dispatch(cond, tx, nIn);
|
||||
pthread_mutex_unlock(&KOMODO_CC_mutex);
|
||||
//fprintf(stderr,"out %d vs %d isValid\n",(int32_t)out,(int32_t)eval->state.IsValid());
|
||||
assert(eval->state.IsValid() == out);
|
||||
if ( eval->state.IsValid() != out)
|
||||
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;
|
||||
|
||||
@@ -64,13 +67,24 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
|
||||
return Invalid("empty-eval");
|
||||
|
||||
uint8_t ecode = cond->code[0];
|
||||
if ( ASSETCHAINS_CCDISABLES[ecode] != 0 )
|
||||
{
|
||||
fprintf(stderr,"%s evalcode.%d %02x\n",txTo.GetHash().GetHex().c_str(),ecode,ecode);
|
||||
return Invalid("disabled-code, -ac_ccenables didnt include this ecode");
|
||||
}
|
||||
std::vector<uint8_t> vparams(cond->code+1, cond->code+cond->codeLength);
|
||||
if ( ecode >= EVAL_FIRSTUSER && ecode <= EVAL_LASTUSER )
|
||||
{
|
||||
if ( ASSETCHAINS_CCLIB.size() > 0 && ASSETCHAINS_CCLIB == CClib_name() )
|
||||
return CClib_Dispatch(cond,this,vparams,txTo,nIn);
|
||||
else return Invalid("mismatched -ac_cclib vs CClib_name");
|
||||
}
|
||||
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);
|
||||
switch ( ecode )
|
||||
{
|
||||
case EVAL_IMPORTPAYOUT:
|
||||
|
||||
@@ -55,9 +55,14 @@
|
||||
EVAL(EVAL_PEGS, 0xee) \
|
||||
EVAL(EVAL_MARMARA, 0xef) \
|
||||
EVAL(EVAL_PAYMENTS, 0xf0) \
|
||||
EVAL(EVAL_GATEWAYS, 0xf1)
|
||||
EVAL(EVAL_GATEWAYS, 0xf1) \
|
||||
EVAL(EVAL_TOKENS, 0xf2)
|
||||
|
||||
|
||||
// evalcodes 0x10 to 0x7f are reserved for cclib dynamic CC
|
||||
#define EVAL_FIRSTUSER 0x10
|
||||
#define EVAL_LASTUSER 0x7f
|
||||
|
||||
typedef uint8_t EvalCode;
|
||||
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ bool FSMExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
|
||||
bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
return(false); // reject any FSM CC for now
|
||||
return eval->Invalid("no validation yet");
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
|
||||
@@ -132,14 +132,18 @@
|
||||
|
||||
|
||||
Implementation Issues:
|
||||
When thinking about validation, it is clear that we cant use EVAL_ASSETS for the locked coins as there wont be any enforcement of the gateways locking. This means we need a way to transfer assets into gateways outputs and back. It seems a tokenconvert rpc will be needed and hopefully that will be enough to make it all work properly.
|
||||
-- When thinking about validation, it is clear that we cant use EVAL_ASSETS for the locked coins as there wont be any enforcement of the gateways locking.
|
||||
-- This means we need a way to transfer assets into gateways outputs and back. It seems a tokenconvert rpc will be needed and hopefully that will be enough to make it all work properly.
|
||||
++ The use of tokenconvert has been changed to the use of the new Tokens contract which can enforce other contracts validation by forwarding eval->validate call to GatewaysValidate
|
||||
++ So all tokens remain within that Tokens contract eval code.
|
||||
|
||||
Care must be taken so that tokens are not lost and can be converted back.
|
||||
|
||||
This changes the usage to require tokenconvert before doing the bind and also tokenconvert before doing a withdraw. EVAL_GATEWAYS has evalcode of 241
|
||||
|
||||
The gatewaysclaim automatically converts the deposit amount of tokens back to EVAL_ASSETS.
|
||||
-- Care must be taken so that tokens are not lost and can be converted back.
|
||||
-- This changes the usage to require tokenconvert before doing the bind and also tokenconvert before doing a withdraw. EVAL_GATEWAYS has evalcode of 241
|
||||
++ tokenconvert now returns 'not implemented', no need to use it at all.
|
||||
|
||||
-- The gatewaysclaim automatically converts the deposit amount of tokens back to EVAL_ASSETS.
|
||||
++ The gatewaysclaim automatically transfers the deposit amount of tokens to depositor's address (within EVAL_TOKENS).
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -204,38 +208,42 @@ uint8_t DecodeGatewaysDepositOpRet(const CScript &scriptPubKey,std::string &coin
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodeGatewaysClaimOpRet(uint8_t funcid,uint256 assetid,std::string refcoin,uint256 bindtxid,uint256 deposittxid,CPubKey destpub,int64_t amount)
|
||||
// encodes payload for the token opret (needs to be added to the tail of it)
|
||||
CScript EncodeGatewaysClaimOpRet(uint8_t funcid, std::string refcoin, uint256 bindtxid, uint256 deposittxid, CPubKey destpub, int64_t amount)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_ASSETS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << refcoin << bindtxid << deposittxid << destpub << amount);
|
||||
CScript opret;
|
||||
|
||||
opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << bindtxid << deposittxid << destpub << amount);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &assetid,std::string &refcoin,uint256 &bindtxid,uint256 &deposittxid,CPubKey &destpub,int64_t &amount)
|
||||
uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &tokenid,std::string &refcoin,uint256 &bindtxid,uint256 &deposittxid,CPubKey &destpub,int64_t &amount)
|
||||
{
|
||||
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 >> assetid; ss >> refcoin; ss >> bindtxid; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 )
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> bindtxid; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 )
|
||||
{
|
||||
return(f);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid,uint256 assetid, std::string refcoin, CPubKey withdrawpub, int64_t amount)
|
||||
CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid, std::string refcoin, CPubKey withdrawpub, int64_t amount)
|
||||
{
|
||||
CScript opret; uint8_t evalcode = EVAL_GATEWAYS;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << refcoin << withdrawpub << amount);
|
||||
CScript opret;
|
||||
opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << withdrawpub << amount);
|
||||
return(opret);
|
||||
}
|
||||
|
||||
uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &assetid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount)
|
||||
uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &tokenid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount)
|
||||
{
|
||||
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 >> assetid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 )
|
||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 )
|
||||
{
|
||||
return(f);
|
||||
}
|
||||
@@ -304,7 +312,7 @@ uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey)
|
||||
std::vector<uint8_t> vopret; uint8_t *script,e,f;
|
||||
GetOpReturnData(scriptPubKey, vopret);
|
||||
script = (uint8_t *)vopret.data();
|
||||
if ( vopret.size() > 2 && (script[0] == EVAL_GATEWAYS || script[0] == EVAL_ASSETS) && E_UNMARSHAL(vopret,ss >> e; ss >> f) != 0 )
|
||||
if ( vopret.size() > 2 && (script[0] == EVAL_GATEWAYS || script[0] == EVAL_TOKENS) && E_UNMARSHAL(vopret,ss >> e; ss >> f) != 0 )
|
||||
{
|
||||
if (f == 'B' && f == 'D' && f == 't' && f == 'W' && f == 'P' && f == 'M')
|
||||
return(f);
|
||||
@@ -512,7 +520,7 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks,height,claimvout; bool retval; uint8_t funcid,hash[32],M,N,taddr,prefix,prefix2;
|
||||
char str[65],destaddr[64],depositaddr[65],validationError[512];
|
||||
std::vector<uint256> txids; std::vector<CPubKey> pubkeys,publishers,tmppublishers; std::vector<uint8_t> proof; int64_t totalsupply,amount,tmpamount;
|
||||
uint256 hashblock,txid,bindtxid,deposittxid,assetid,oracletxid,tokenid,cointxid,tmptxid,tmpxtxid2,merkleroot,mhash; CTransaction bindtx,deposittx,oracletx;
|
||||
uint256 hashblock,txid,bindtxid,deposittxid,tokenidClaim,oracletxid,tokenidBind,cointxid,tmptxid,tmpxtxid2,merkleroot,mhash; CTransaction bindtx,deposittx,oracletx;
|
||||
std::string refcoin,tmprefcoin,deposithex; CPubKey destpub,tmpdestpub;
|
||||
|
||||
fprintf(stderr,"return true without gateways validation\n");
|
||||
@@ -565,8 +573,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
//vin.2: CC input of marker from gatewaysdeposit tx
|
||||
//vout.0: CC vout of total tokens from deposit amount to asset eval code
|
||||
//(vout.1): CC vout if there is change of unused tokens back to owner of tokens (deposit amount less than available tokens)
|
||||
//vout.n-1: opreturn - 't' assetid zeroid 0 mypubkey (NOTE: opreturn is with asset eval code)
|
||||
if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,refcoin,bindtxid,deposittxid,destpub,amount)==0)
|
||||
//vout.n-1: opreturn - 't' tokenid zeroid 0 mypubkey (NOTE: opreturn is with asset eval code)
|
||||
if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,tokenidClaim,refcoin,bindtxid,deposittxid,destpub,amount)==0)
|
||||
return eval->Invalid("invalid gatewaysclaim OP_RETURN data!");
|
||||
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
|
||||
return eval->Invalid("vin.0 is normal for gatewaysClaim!");
|
||||
@@ -580,12 +588,12 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
return eval->Invalid("vout.1 is CC for gatewaysClaim!");
|
||||
else if (myGetTransaction(bindtxid,bindtx,hashblock) == 0)
|
||||
return eval->Invalid("invalid gatewaysbind txid!");
|
||||
else if ((numvouts=bindtx.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B')
|
||||
else if ((numvouts=bindtx.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenidBind,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B')
|
||||
return eval->Invalid("invalid gatewaysbind OP_RETURN data!");
|
||||
else if (tmprefcoin!=refcoin)
|
||||
return eval->Invalid("refcoin different in bind tx");
|
||||
else if (tokenid!=assetid)
|
||||
return eval->Invalid("assetid does not match tokenid from gatewaysbind");
|
||||
else if (tokenidClaim!=tokenidBind)
|
||||
return eval->Invalid("tokenid does not match tokenid from gatewaysbind");
|
||||
else if (komodo_txnotarizedconfirmed(bindtxid) == false)
|
||||
return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!");
|
||||
else if (myGetTransaction(deposittxid,deposittx,hashblock) == 0)
|
||||
@@ -642,7 +650,7 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
//vout.1: normal vout txfee marker to withdraw destination pubkey
|
||||
//vout.2: CC vout txfee marker to gateways CC address
|
||||
//vout.n-2: CC vout if there is change of unused tokens back to owner of tokens (withdraw amount less than owner available tokens)
|
||||
//vout.n-1: opreturn - 'W' assetid refcoin withdrawpub amount
|
||||
//vout.n-1: opreturn - 'W' tokenid refcoin withdrawpub amount
|
||||
break;
|
||||
case 'P':
|
||||
//vin.0: normal input
|
||||
@@ -675,9 +683,9 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &
|
||||
|
||||
// helper functions for rpc calls in rpcwallet.cpp
|
||||
|
||||
int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 refassetid,int64_t total,int32_t maxinputs)
|
||||
int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 reftokenid,int64_t total,int32_t maxinputs)
|
||||
{
|
||||
char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 assetid,txid,hashBlock; std::vector<uint8_t> origpubkey; std::vector<uint8_t> vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid;
|
||||
char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 tokenid,txid,hashBlock; std::vector<uint8_t> origpubkey; std::vector<uint8_t> vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
GetCCaddress(cp,coinaddr,pk);
|
||||
SetCCunspents(unspentOutputs,coinaddr);
|
||||
@@ -701,11 +709,11 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP
|
||||
if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
|
||||
continue;
|
||||
GetOpReturnData(vintx.vout[vintx.vout.size()-1].scriptPubKey, vopret);
|
||||
if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> assetid) != 0 )
|
||||
if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> tokenid) != 0 )
|
||||
{
|
||||
assetid = revuint256(assetid);
|
||||
char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for refassetid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,refassetid),uint256_str(str2,assetid),(double)vintx.vout[vout].nValue/COIN);
|
||||
if ( assetid == refassetid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
tokenid = revuint256(tokenid);
|
||||
char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for reftokenid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,reftokenid),uint256_str(str2,tokenid),(double)vintx.vout[vout].nValue/COIN);
|
||||
if ( tokenid == reftokenid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
|
||||
{
|
||||
//fprintf(stderr,"total %llu maxinputs.%d %.8f\n",(long long)total,maxinputs,(double)it->second.satoshis/COIN);
|
||||
if ( total != 0 && maxinputs != 0 )
|
||||
@@ -905,7 +913,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui
|
||||
CTransaction tx; CPubKey mypk,gatewayspk,tmpdestpub; struct CCcontract_info *cp,C; uint8_t M,N,taddr,prefix,prefix2;
|
||||
std::string coin, deposithex; std::vector<CPubKey> msigpubkeys,publishers; int64_t totalsupply,depositamount,tmpamount,inputs,CCchange=0;
|
||||
int32_t numvouts,claimvout,height; std::vector<uint8_t> proof;
|
||||
uint256 hashBlock,assetid,oracletxid,tmptxid,cointxid; char str[65],depositaddr[64],coinaddr[64],destaddr[64]; std::vector<uint256> txids;
|
||||
uint256 hashBlock,tokenid,oracletxid,tmptxid,cointxid; char str[65],depositaddr[64],coinaddr[64],destaddr[64]; std::vector<uint256> txids;
|
||||
|
||||
cp = CCinit(&C,EVAL_GATEWAYS);
|
||||
if ( txfee == 0 )
|
||||
@@ -917,7 +925,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui
|
||||
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
|
||||
return("");
|
||||
}
|
||||
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
|
||||
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
|
||||
{
|
||||
fprintf(stderr,"invalid coin - bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
|
||||
return("");
|
||||
@@ -945,17 +953,24 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui
|
||||
//fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2);
|
||||
if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 )
|
||||
{
|
||||
if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,assetid,amount,60)) > 0 )
|
||||
///////// if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,tokenid,amount,60)) > 0 )
|
||||
if ((inputs = AddTokenCCInputs(cp, mtx, gatewayspk, tokenid, amount, 60)) > 0)
|
||||
{
|
||||
if ( inputs > amount )
|
||||
CCchange = (inputs - amount);
|
||||
_GetCCaddress(destaddr,EVAL_GATEWAYS,mypk);
|
||||
//printf("expecting deposittxid/v0 to be to %s\n",destaddr);
|
||||
mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); // triggers EVAL_GATEWAYS validation
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk)); // transfer back to normal token
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,amount,mypk)); // transfer back to normal token
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysClaimOpRet('t',assetid,refcoin,bindtxid,deposittxid,destpub,amount)));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk));
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(mypk); // the pubkey where tokens are going (vout[0])
|
||||
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,
|
||||
EncodeTokenOpRet('t', EVAL_GATEWAYS, tokenid, voutTokenPubkeys,
|
||||
EncodeGatewaysClaimOpRet('t', refcoin, bindtxid, deposittxid, destpub, amount)))); // yes, 't' is passed twice
|
||||
}
|
||||
}
|
||||
CCerror = strprintf("cant find enough inputs or mismatched total");
|
||||
@@ -966,39 +981,67 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui
|
||||
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount)
|
||||
{
|
||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
|
||||
CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C;
|
||||
uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin;
|
||||
CTransaction tx;
|
||||
CPubKey mypk, gatewayspk;
|
||||
uint256 tokenid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin;
|
||||
std::vector<CPubKey> msigpubkeys; char depositaddr[64],str[65],coinaddr[64];
|
||||
cp = CCinit(&C,EVAL_GATEWAYS);
|
||||
struct CCcontract_info *cpGateways, gatewaysC;
|
||||
struct CCcontract_info *cpTokens, tokensC;
|
||||
|
||||
cpGateways = CCinit(&gatewaysC, EVAL_GATEWAYS);
|
||||
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
|
||||
|
||||
if ( txfee == 0 )
|
||||
txfee = 10000;
|
||||
|
||||
mypk = pubkey2pk(Mypubkey());
|
||||
gatewayspk = GetUnspendable(cp,0);
|
||||
if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
|
||||
gatewayspk = GetUnspendable(cpGateways, 0);
|
||||
|
||||
if( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 )
|
||||
{
|
||||
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
|
||||
return("");
|
||||
}
|
||||
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
|
||||
if( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin )
|
||||
{
|
||||
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str());
|
||||
return("");
|
||||
}
|
||||
if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 )
|
||||
if( AddNormalinputs(mtx, mypk, 3*txfee, 4) > 0 )
|
||||
{
|
||||
if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,assetid,amount,60)) > 0 )
|
||||
/////if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,tokenid,amount,60)) > 0 )
|
||||
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, amount, 60)) > 0)
|
||||
{
|
||||
if ( inputs > amount )
|
||||
CCchange = (inputs - amount);
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,amount,gatewayspk));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, amount, gatewayspk));
|
||||
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS, txfee, gatewayspk));
|
||||
if ( CCchange != 0 )
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,mypk));
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysWithdrawOpRet('W',assetid,refcoin,withdrawpub,amount)));
|
||||
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk));
|
||||
|
||||
char unspendableGatewaysAddr[64];
|
||||
GetCCaddress(cpGateways, unspendableGatewaysAddr, gatewayspk);
|
||||
|
||||
uint8_t unspendableGatewaysPrivkey[32];
|
||||
GetUnspendable(cpGateways, unspendableGatewaysPrivkey);
|
||||
|
||||
// add additional unspendable addr from Gateways:
|
||||
CCaddr2set(cpTokens, EVAL_GATEWAYS, gatewayspk, unspendableGatewaysPrivkey, unspendableGatewaysAddr);
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeys;
|
||||
voutTokenPubkeys.push_back(gatewayspk); // the pubkey where tokens are going vout[0] (and for checking the 'change' the Tokens contract will find pubkeys itself)
|
||||
|
||||
return(FinalizeCCTx(0, cpTokens, mtx, mypk, txfee,
|
||||
EncodeTokenOpRet('t', EVAL_GATEWAYS, tokenid, voutTokenPubkeys,
|
||||
EncodeGatewaysWithdrawOpRet('W', refcoin, withdrawpub, amount))));
|
||||
}
|
||||
CCerror = strprintf("cant find enough token inputs or mismatched total");
|
||||
fprintf(stderr, "%s\n", CCerror.c_str());
|
||||
return("");
|
||||
|
||||
}
|
||||
CCerror = strprintf("cant find enough inputs or mismatched total");
|
||||
CCerror = strprintf("cant find enough normal inputs or mismatched total");
|
||||
fprintf(stderr,"%s\n", CCerror.c_str() );
|
||||
return("");
|
||||
}
|
||||
@@ -1073,7 +1116,7 @@ std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string ref
|
||||
UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string tmprefcoin; CPubKey mypk,gatewayspk,withdrawpub; std::vector<CPubKey> msigpubkeys;
|
||||
uint256 hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2;
|
||||
uint256 hashBlock,tokenid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2;
|
||||
char depositaddr[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],cctxidaddr[64],signeraddr[64];
|
||||
int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
@@ -1087,7 +1130,7 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
|
||||
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
|
||||
return(result);
|
||||
}
|
||||
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin )
|
||||
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin )
|
||||
{
|
||||
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str());
|
||||
return(result);
|
||||
@@ -1108,7 +1151,7 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
|
||||
nValue = (int64_t)it->second.satoshis;
|
||||
fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue);
|
||||
if ( vout == 2 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 &&
|
||||
DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0)
|
||||
DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0)
|
||||
{
|
||||
Getscriptaddress(destaddr,tx.vout[0].scriptPubKey);
|
||||
Getscriptaddress(withaddr,tx.vout[1].scriptPubKey);
|
||||
@@ -1141,7 +1184,7 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin)
|
||||
UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ),processed(UniValue::VARR); CTransaction tx; std::string tmprefcoin,hex; CPubKey mypk,gatewayspk,withdrawpub; std::vector<CPubKey> msigpubkeys;
|
||||
uint256 withdrawtxid,hashBlock,txid,assetid,oracletxid; uint8_t M,N,taddr,prefix,prefix2;
|
||||
uint256 withdrawtxid,hashBlock,txid,tokenid,oracletxid; uint8_t M,N,taddr,prefix,prefix2;
|
||||
char depositaddr[64],coinaddr[64],str[65],numstr[32],txidaddr[64],cctxidaddr[64],withaddr[64];
|
||||
int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,nValue,amount; struct CCcontract_info *cp,C;
|
||||
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
|
||||
@@ -1155,7 +1198,7 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin)
|
||||
fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid));
|
||||
return(result);
|
||||
}
|
||||
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin )
|
||||
if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin )
|
||||
{
|
||||
fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str());
|
||||
return(result);
|
||||
@@ -1178,7 +1221,7 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin)
|
||||
if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 &&
|
||||
DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,tmprefcoin,withdrawtxid,hex) == 'C' && myIsutxo_spentinmempool(txid,vout) == 0)
|
||||
{
|
||||
if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,tmprefcoin,withdrawpub,amount) == 'W')
|
||||
if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W')
|
||||
{
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
obj.push_back(Pair("txid",uint256_str(str,txid)));
|
||||
|
||||
1291
src/cc/heir.cpp
1291
src/cc/heir.cpp
File diff suppressed because it is too large
Load Diff
631
src/cc/heir_validate.h
Normal file
631
src/cc/heir_validate.h
Normal file
@@ -0,0 +1,631 @@
|
||||
#ifndef HEIR_VALIDATE_H
|
||||
#define HEIR_VALIDATE_H
|
||||
|
||||
#include "CCinclude.h"
|
||||
#include "CCHeir.h"
|
||||
|
||||
#define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos)
|
||||
|
||||
// makes coin initial tx opret
|
||||
CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName);
|
||||
CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan);
|
||||
|
||||
uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan);
|
||||
//uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false);
|
||||
//uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false);
|
||||
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false);
|
||||
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging = false);
|
||||
|
||||
inline static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); }
|
||||
inline static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); }
|
||||
|
||||
// helper class to allow polymorphic behaviour for HeirXXX() functions in case of coins
|
||||
class CoinHelper {
|
||||
public:
|
||||
|
||||
static uint8_t getMyEval() { return EVAL_HEIR; }
|
||||
static int64_t addOwnerInputs(uint256 dummyid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) {
|
||||
return AddNormalinputs(mtx, ownerPubkey, total, maxinputs);
|
||||
}
|
||||
|
||||
static CScript makeCreateOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) {
|
||||
return EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName);
|
||||
}
|
||||
static CScript makeAddOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
|
||||
return EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan);
|
||||
}
|
||||
static CScript makeClaimOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
|
||||
return EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan);
|
||||
}
|
||||
static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) {
|
||||
return MakeCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey);
|
||||
}
|
||||
static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) {
|
||||
return CTxOut(amount, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG);
|
||||
}
|
||||
/* static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) {
|
||||
return CTxOut(amount, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG);
|
||||
} */
|
||||
static bool GetCoinsOrTokensCCaddress1of2(char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) {
|
||||
struct CCcontract_info *cpHeir, heirC;
|
||||
cpHeir = CCinit(&heirC, EVAL_HEIR);
|
||||
return GetCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey);
|
||||
}
|
||||
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) {
|
||||
CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr);
|
||||
}
|
||||
};
|
||||
|
||||
// helper class to allow polymorphic behaviour for HeirXXX() functions in case of tokens
|
||||
class TokenHelper {
|
||||
public:
|
||||
static uint8_t getMyEval() { return EVAL_TOKENS; }
|
||||
static int64_t addOwnerInputs(uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) {
|
||||
struct CCcontract_info *cpHeir, heirC;
|
||||
cpHeir = CCinit(&heirC, EVAL_TOKENS);
|
||||
return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs);
|
||||
}
|
||||
|
||||
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) {
|
||||
return EncodeTokenOpRet(tokenid, voutTokenPubkeys,
|
||||
EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName));
|
||||
}
|
||||
static CScript makeAddOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
|
||||
return EncodeTokenOpRet(tokenid, voutTokenPubkeys,
|
||||
EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan));
|
||||
}
|
||||
static CScript makeClaimOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
|
||||
return EncodeTokenOpRet(tokenid, voutTokenPubkeys,
|
||||
EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan));
|
||||
}
|
||||
|
||||
static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) {
|
||||
return MakeTokensCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey);
|
||||
}
|
||||
static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) {
|
||||
return MakeCC1vout(EVAL_TOKENS, amount, myPubkey); // yes EVAL_TOKENS
|
||||
}
|
||||
/* static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) {
|
||||
return MakeCC1vout(EVAL_TOKENS, amount, myPubkey); // yes EVAL_TOKENS
|
||||
} */
|
||||
static bool GetCoinsOrTokensCCaddress1of2(char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) {
|
||||
struct CCcontract_info *cpHeir, heirC;
|
||||
cpHeir = CCinit(&heirC, EVAL_HEIR);
|
||||
return GetTokensCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey);
|
||||
}
|
||||
|
||||
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) {
|
||||
|
||||
CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Small framework for vins and vouts validation implementing a variation of 'chain of responsibility' pattern:
|
||||
* It consists of two classes CInputValidationPlan and COutputValidationPlan which both are configured with an array of vectors of validators
|
||||
* (These validators are derived from the class CValidatorBase).
|
||||
*
|
||||
* A example of a validator may verify for a vout if its public key corresponds to the public key which is stored in opreturn.
|
||||
* Or, vin validator may check if this vin depicts correctly to the CC contract's address.
|
||||
*
|
||||
* For validating vins CInputValidator additionally is provided with an instance of a class derived from the CInputIdentifierBase class.
|
||||
* this identifier class allows to select identical vins (for example, normal vins or cc input vins) and apply validators from the corresponding vector to it.
|
||||
* Note: CInputValidator treats that at least one identified vin should be present, otherwise it returns eval->invalid() and false.
|
||||
*
|
||||
* For validating vouts COutputValidator is configured for each vector of validators with the vout index to which these validators are applied
|
||||
* (see constructors of both CInputValidator and COutputValidator)
|
||||
*/
|
||||
|
||||
/**
|
||||
* base class for all validators
|
||||
*/
|
||||
class CValidatorBase
|
||||
{
|
||||
public:
|
||||
CValidatorBase(CCcontract_info* cp) : m_cp(cp) {}
|
||||
virtual bool isVinValidator() const = 0;
|
||||
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const = 0;
|
||||
virtual bool validateVout(CTxOut vout, std::string& message) const = 0;
|
||||
|
||||
protected:
|
||||
CCcontract_info * m_cp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for classes which identify vins as normal or cc inputs
|
||||
*/
|
||||
class CInputIdentifierBase
|
||||
{
|
||||
public:
|
||||
CInputIdentifierBase(CCcontract_info* cp) : m_cp(cp) {}
|
||||
virtual std::string inputName() const = 0;
|
||||
virtual bool identifyInput(CTxIn vin) const = 0;
|
||||
protected:
|
||||
CCcontract_info * m_cp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates an array containing rows of validators
|
||||
* Each row is a vector of validators (zero is possible) for validating vins or prev tx's vouts
|
||||
* this validation plan is used for validating tx inputs
|
||||
*/
|
||||
template <typename TValidatorBase>
|
||||
class CInputValidationPlan
|
||||
{
|
||||
using ValidatorsRow = std::vector<TValidatorBase*>;
|
||||
|
||||
public:
|
||||
|
||||
// Pushes a row of validators for validating a vin or vout
|
||||
// @param CInputIdentifierBase* pointer to class-identifier which determines several identical adjacent vins (like in schema "vin.0+: normal inputs")
|
||||
// @param pargs parameter pack of zero or more pointer to validator objects
|
||||
// Why pointers? because we store the base class in validators' row and then call its virtual functions
|
||||
template <typename TValidatorBaseX, typename... ARGS>
|
||||
void pushValidators(CInputIdentifierBase *identifier, ARGS*... pargs) // validators row passed as variadic arguments CValidatorX *val1, CValidatorY *val2 ...
|
||||
{
|
||||
ValidatorsRow vValidators({ (TValidatorBase*)pargs... });
|
||||
m_arrayValidators.push_back(std::make_pair(identifier, vValidators));
|
||||
}
|
||||
|
||||
// validate tx inputs and corresponding prev tx vouts
|
||||
bool validate(const CTransaction& tx, Eval* eval)
|
||||
{
|
||||
std::string message = "<empty>";
|
||||
//std::cerr << "CInputValidationPlan::validate() starting vins validation..." << std::endl;
|
||||
|
||||
int32_t ival = 0;
|
||||
int32_t iv = 0;
|
||||
int32_t numv = tx.vin.size();
|
||||
int32_t numValidators = m_arrayValidators.size();
|
||||
|
||||
// run over vins:
|
||||
while (iv < numv && ival < numValidators) {
|
||||
|
||||
int32_t identifiedCount = 0;
|
||||
CInputIdentifierBase *identifier = m_arrayValidators[ival].first;
|
||||
// check if this is 'our' input:
|
||||
while (iv < numv && identifier->identifyInput(tx.vin[iv])) {
|
||||
|
||||
// get prev tx:
|
||||
CTransaction prevTx, *pPrevTxOrNull = NULL;
|
||||
uint256 hashBlock;
|
||||
|
||||
if (!eval->GetTxUnconfirmed(tx.vin[iv].prevout.hash, prevTx, hashBlock)) {
|
||||
std::ostringstream stream;
|
||||
stream << "can't find vinTx for vin=" << iv << ".";
|
||||
return eval->Invalid(stream.str().c_str());
|
||||
}
|
||||
pPrevTxOrNull = &prevTx; // TODO: get prev tx only if it required (i.e. if vout validators are present)
|
||||
|
||||
// exec 'validators' from validator row of ival index, for tx.vin[iv]
|
||||
if (!execValidatorsInRow(&tx, pPrevTxOrNull, iv, ival, message)) {
|
||||
std::ostringstream stream;
|
||||
stream << "invalid tx vin[" << iv << "]:" << message;
|
||||
return eval->Invalid(stream.str().c_str()); // ... if not, return 'invalid'
|
||||
}
|
||||
|
||||
identifiedCount++; // how many vins we identified
|
||||
iv++; // advance to the next vin
|
||||
}
|
||||
|
||||
// CInputValidationPlan treats that there must be at least one identified vin for configured validators' row
|
||||
// like in 'vin.0: normal input'
|
||||
if (identifiedCount == 0) {
|
||||
std::ostringstream stream;
|
||||
stream << "can't find required vins for " << identifier->inputName() << ".";
|
||||
return eval->Invalid(stream.str().c_str());
|
||||
}
|
||||
|
||||
ival++; // advance to the next validator row
|
||||
// and it will try the same vin with the new CInputIdentifierBase and validators row
|
||||
}
|
||||
|
||||
// validation is successful if all validators have been used (i.e. ival = numValidators)
|
||||
if (ival < numValidators) {
|
||||
std::cerr << "CInputValidationPlan::validate() incorrect tx" << " ival=" << ival << " numValidators=" << numValidators << std::endl;
|
||||
return eval->Invalid("incorrect tx structure: not all required vins are present.");
|
||||
}
|
||||
|
||||
//std::cerr << "CInputValidationPlan::validate() returns with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Executes validators from the requested row of validators (selected by iValidators) for selected vin or vout (selected by iv)
|
||||
bool execValidatorsInRow(const CTransaction* pTx, const CTransaction* pPrevTx, int32_t iv, int32_t ival, std::string& refMessage) const
|
||||
{
|
||||
// check boundaries:
|
||||
if (ival < 0 || ival >= m_arrayValidators.size()) {
|
||||
std::cerr << "CInputValidationPlan::execValidatorsInRow() internal error: incorrect param ival=" << ival << " size=" << m_arrayValidators.size();
|
||||
refMessage = "internal error: incorrect param ival index";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iv < 0 || iv >= pTx->vin.size()) {
|
||||
std::cerr << "CInputValidationPlan::execValidatorsInRow() internal error: incorrect param iv=" << iv << " size=" << m_arrayValidators.size();
|
||||
refMessage = "internal error: incorrect param iv index";
|
||||
return false;
|
||||
}
|
||||
|
||||
// get requested row of validators:
|
||||
ValidatorsRow vValidators = m_arrayValidators[ival].second;
|
||||
|
||||
//std::cerr << "CInputValidationPlan::execValidatorsInRow() calling validators" << " for vin iv=" << iv << " ival=" << ival << std::endl;
|
||||
|
||||
for (auto v : vValidators) {
|
||||
bool result;
|
||||
|
||||
if (v->isVinValidator())
|
||||
// validate this vin and previous vout:
|
||||
result = v->validateVin(pTx->vin[iv], pPrevTx->vout[pTx->vin[iv].prevout.n], refMessage);
|
||||
else
|
||||
// if it is vout validator pass the previous tx vout:
|
||||
result = v->validateVout( pPrevTx->vout[pTx->vin[iv].prevout.n], refMessage);
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return true; // validation OK
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
//std::map<CInputIdentifierBase*, ValidatorsRow> m_arrayValidators;
|
||||
std::vector< std::pair<CInputIdentifierBase*, ValidatorsRow> > m_arrayValidators;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates an array containing rows of validators
|
||||
* Each row is a vector of validators (zero is possible) for validating vouts
|
||||
* this validation plan is used for validating tx outputs
|
||||
*/
|
||||
template <typename TValidatorBase>
|
||||
class COutputValidationPlan
|
||||
{
|
||||
using ValidatorsRow = std::vector<TValidatorBase*>;
|
||||
|
||||
public:
|
||||
// Pushes a row of validators for validating a vout
|
||||
// @param ivout index to vout to validate
|
||||
// @param pargs parameter pack of zero or more pointer to validator objects
|
||||
// Why pointers? because we store base class and call its virtual functions
|
||||
|
||||
template <typename TValidatorBaseX, typename... ARGS>
|
||||
void pushValidators(int32_t ivout, ARGS*... pargs) // validators row passed as variadic arguments CValidatorX *val1, CValidatorY *val2 ...
|
||||
{
|
||||
ValidatorsRow vValidators({ (TValidatorBase*)pargs... });
|
||||
m_arrayValidators.push_back(std::make_pair(ivout, vValidators));
|
||||
}
|
||||
|
||||
// validate tx outputs
|
||||
bool validate(const CTransaction& tx, Eval* eval)
|
||||
{
|
||||
std::string message = "<empty>";
|
||||
//std::cerr << "COutputValidationPlan::validateOutputs() starting vouts validation..." << std::endl;
|
||||
|
||||
int32_t ival = 0;
|
||||
int32_t numVouts = tx.vout.size();
|
||||
int32_t numValidators = m_arrayValidators.size();
|
||||
|
||||
// run over vouts:
|
||||
while (ival < numValidators) {
|
||||
|
||||
int32_t ivout = m_arrayValidators[ival].first;
|
||||
if (ivout >= numVouts) {
|
||||
std::cerr << "COutputValidationPlan::validate() incorrect tx" << "for ival=" << ival << " in tx.vout no such ivout=" << ivout << std::endl;
|
||||
return eval->Invalid("incorrect tx structure: not all required vouts are present.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// exec 'validators' from validator row of ival index, for tx.vout[ivout]
|
||||
if (!execValidatorsInRow(&tx, ivout, ival, message)) {
|
||||
std::ostringstream stream;
|
||||
stream << "invalid tx vout[" << ivout << "]:" << message;
|
||||
return eval->Invalid(stream.str().c_str()); // ... if not, return 'invalid'
|
||||
}
|
||||
}
|
||||
ival++; // advance to the next vout
|
||||
}
|
||||
//std::cerr << "COutputValidationPlan::validate() returns with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Executes validators from the requested row of validators (selected by iValidators) for selected vin or vout (selected by iv)
|
||||
bool execValidatorsInRow(const CTransaction* pTx, int32_t iv, int32_t ival, std::string& refMessage) const
|
||||
{
|
||||
// check boundaries:
|
||||
if (ival < 0 || ival >= m_arrayValidators.size()) {
|
||||
std::cerr << "COutputValidationPlan::execValidatorsInRow() internal error: incorrect param ival=" << ival << " size=" << m_arrayValidators.size();
|
||||
refMessage = "internal error: incorrect param ival index";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iv < 0 || iv >= pTx->vout.size()) {
|
||||
std::cerr << "COutputValidationPlan::execValidatorsInRow() internal error: incorrect param iv=" << iv << " size=" << m_arrayValidators.size();
|
||||
refMessage = "internal error: incorrect param iv index";
|
||||
return false;
|
||||
}
|
||||
|
||||
// get requested row of validators:
|
||||
ValidatorsRow vValidators = m_arrayValidators[ival].second;
|
||||
|
||||
//std::cerr << "COutputValidationPlan::execRow() calling validators" << " for vout iv=" << iv << " ival=" << ival << std::endl;
|
||||
|
||||
for (auto v : vValidators) {
|
||||
|
||||
if (!v->isVinValidator()) {
|
||||
// if this is a 'in' validation plan then pass the previous tx vout:
|
||||
bool result = v->validateVout(pTx->vout[iv], refMessage);
|
||||
if (!result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return true; // validation OK
|
||||
}
|
||||
|
||||
private:
|
||||
//std::map<int32_t, ValidatorsRow> m_mapValidators;
|
||||
std::vector< std::pair<int32_t, ValidatorsRow> > m_arrayValidators;
|
||||
|
||||
};
|
||||
|
||||
class CNormalInputIdentifier : CInputIdentifierBase {
|
||||
public:
|
||||
CNormalInputIdentifier(CCcontract_info* cp) : CInputIdentifierBase(cp) {}
|
||||
virtual std::string inputName() const { return std::string("normal input"); }
|
||||
virtual bool identifyInput(CTxIn vin) const {
|
||||
return !IsCCInput(vin.scriptSig);
|
||||
}
|
||||
};
|
||||
|
||||
class CCCInputIdentifier : CInputIdentifierBase {
|
||||
public:
|
||||
CCCInputIdentifier(CCcontract_info* cp) : CInputIdentifierBase(cp) {}
|
||||
virtual std::string inputName() const { return std::string("CC input"); }
|
||||
virtual bool identifyInput(CTxIn vin) const {
|
||||
return IsCCInput(vin.scriptSig);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Validates 1of2address for vout (may be used for either this or prev tx)
|
||||
*/
|
||||
template <class Helper> class CCC1of2AddressValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
CCC1of2AddressValidator(CCcontract_info* cp, CScript opRetScript, std::string customMessage = "") :
|
||||
m_fundingOpretScript(opRetScript), m_customMessage(customMessage), CValidatorBase(cp) {}
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, std::string& message) const
|
||||
{
|
||||
//std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl;
|
||||
CPubKey ownerPubkey, heirPubkey;
|
||||
int64_t inactivityTime;
|
||||
std::string heirName;
|
||||
uint256 tokenid;
|
||||
|
||||
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
|
||||
if (funcId == 0) {
|
||||
message = m_customMessage + std::string(" invalid opreturn format");
|
||||
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
char shouldBeAddr[65], ccAddr[65];
|
||||
|
||||
//GetCCaddress1of2(m_cp, shouldBeAddr, ownerPubkey, heirPubkey);
|
||||
Helper::GetCoinsOrTokensCCaddress1of2(shouldBeAddr, ownerPubkey, heirPubkey);
|
||||
|
||||
if (vout.scriptPubKey.IsPayToCryptoCondition()) {
|
||||
if (Getscriptaddress(ccAddr, vout.scriptPubKey) && strcmp(shouldBeAddr, ccAddr) == 0) {
|
||||
//std::cerr << "CCC1of2AddressValidator::validateVout() exits with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
message = m_customMessage + std::string(" incorrect heir funding address: incorrect pubkey(s)");
|
||||
}
|
||||
}
|
||||
else {
|
||||
message = m_customMessage + std::string(" incorrect heir funding address: not a 1of2addr");
|
||||
}
|
||||
|
||||
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
|
||||
return false;
|
||||
}
|
||||
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return false; }
|
||||
|
||||
private:
|
||||
CScript m_fundingOpretScript;
|
||||
std::string m_customMessage;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Validates if this is vout to owner or heir from opret (funding or change)
|
||||
*/
|
||||
template <class Helper> class CMyPubkeyVoutValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
CMyPubkeyVoutValidator(CCcontract_info* cp, CScript opRetScript, bool checkNormals)
|
||||
: m_fundingOpretScript(opRetScript), m_checkNormals(checkNormals), CValidatorBase(cp) { }
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, std::string& message) const
|
||||
{
|
||||
//std::cerr << "CMyPubkeyVoutValidator::validateVout() entered" << std::endl;
|
||||
|
||||
CPubKey ownerPubkey, heirPubkey;
|
||||
int64_t inactivityTime;
|
||||
std::string heirName;
|
||||
uint256 tokenid;
|
||||
|
||||
///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl;
|
||||
|
||||
// get both pubkeys:
|
||||
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
|
||||
if (funcId == 0) {
|
||||
message = std::string("invalid opreturn format");
|
||||
return false;
|
||||
}
|
||||
|
||||
CScript ownerScript;
|
||||
CScript heirScript;
|
||||
if (m_checkNormals) { //not used, incorrect check, too strict
|
||||
ownerScript = CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey;
|
||||
heirScript = CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey;
|
||||
std::cerr << "CMyPubkeyVoutValidator::validateVout() vout.scriptPubKey=" << vout.scriptPubKey.ToString() << " makeUserVout(coin,owner)=" << CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey.ToString() << " makeUserVout(coin,heir)=" << CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey.ToString() << std::endl;
|
||||
}
|
||||
else {
|
||||
ownerScript = Helper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey;
|
||||
heirScript = Helper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey;
|
||||
std::cerr << "CMyPubkeyVoutValidator::validateVout() vout.scriptPubKey=" << vout.scriptPubKey.ToString() << " makeUserVout(owner)=" << Helper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey.ToString() << " makeUserVout(heir)=" << Helper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey.ToString() << std::endl;
|
||||
}
|
||||
|
||||
// recreate scriptPubKey for owner and heir and compare it with that of the vout to check:
|
||||
if (vout.scriptPubKey == ownerScript || vout.scriptPubKey == heirScript) {
|
||||
// this is vout to owner or heir addr:
|
||||
//std::cerr << "CMyPubkeyVoutValidator::validateVout() exits with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::cerr << "CMyPubkeyVoutValidator::validateVout() exits with false (not the owner's or heir's addresses)" << std::endl;
|
||||
message = std::string("invalid pubkey");
|
||||
return false;
|
||||
}
|
||||
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; }
|
||||
|
||||
private:
|
||||
CScript m_fundingOpretScript;
|
||||
//uint256 m_lasttxid;
|
||||
bool m_checkNormals;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the user is the heir and the heir is allowed to spend (duration > inactivityTime)
|
||||
*/
|
||||
template <class Helper> class CHeirSpendValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
CHeirSpendValidator(CCcontract_info* cp, CScript opRetScript, uint256 latesttxid, uint8_t isHeirSpendingBegan)
|
||||
: m_fundingOpretScript(opRetScript), m_latesttxid(latesttxid), m_isHeirSpendingBegan(isHeirSpendingBegan), CValidatorBase(cp) {}
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, std::string& message) const
|
||||
{
|
||||
//std::cerr << "CHeirSpendValidator::validateVout() entered" << std::endl;
|
||||
|
||||
CPubKey ownerPubkey, heirPubkey;
|
||||
int64_t inactivityTime;
|
||||
std::string heirName;
|
||||
uint256 tokenid;
|
||||
|
||||
// get heir pubkey:
|
||||
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
|
||||
if (funcId == 0) {
|
||||
message = std::string("invalid opreturn format");
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t numblocks;
|
||||
int64_t durationSec = CCduration(numblocks, m_latesttxid);
|
||||
|
||||
// recreate scriptPubKey for heir and compare it with that of the vout:
|
||||
if (vout.scriptPubKey == Helper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey) {
|
||||
// this is the heir is trying to spend
|
||||
if (!m_isHeirSpendingBegan && durationSec <= inactivityTime) {
|
||||
message = "heir is not allowed yet to spend funds";
|
||||
std::cerr << "CHeirSpendValidator::validateVout() heir is not allowed yet to spend funds" << std::endl;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// heir is allowed to spend
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << "CHeirSpendValidator::validateVout() exits with true" << std::endl;
|
||||
|
||||
// this is not heir:
|
||||
return true;
|
||||
}
|
||||
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; }
|
||||
|
||||
private:
|
||||
CScript m_fundingOpretScript;
|
||||
uint256 m_latesttxid;
|
||||
uint8_t m_isHeirSpendingBegan;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates this opreturn and compares it with the opreturn from the previous tx
|
||||
*/
|
||||
template <class Helper> class COpRetValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
COpRetValidator(CCcontract_info* cp, CScript opret)
|
||||
: m_fundingOpretScript(opret), CValidatorBase(cp) {}
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, std::string& message) const
|
||||
{
|
||||
//std::cerr << "COpRetValidator::validateVout() entered" << std::endl;
|
||||
|
||||
uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid;
|
||||
uint8_t dummyIsHeirSpendingBegan;
|
||||
|
||||
uint8_t funcId = DecodeHeirEitherOpRet(vout.scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true);
|
||||
if (funcId == 0) {
|
||||
message = std::string("invalid opreturn format");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t initialFuncId = DecodeHeirEitherOpRet(m_fundingOpretScript, initialTokenid, dummyTxid, dummyIsHeirSpendingBegan, true);
|
||||
if (initialFuncId == 0) {
|
||||
message = std::string("invalid initial tx opreturn format");
|
||||
return false;
|
||||
}
|
||||
|
||||
// validation rules:
|
||||
if (!isMyFuncId(funcId)) {
|
||||
message = std::string("invalid funcid in opret");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeid(Helper) == typeid(TokenHelper)) {
|
||||
if (tokenid != initialTokenid) {
|
||||
message = std::string("invalid tokenid in opret");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//std::cerr << "COpRetValidator::validateVout() exits with true" << std::endl;
|
||||
return true;
|
||||
}
|
||||
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; }
|
||||
|
||||
private:
|
||||
CScript m_fundingOpretScript;
|
||||
};
|
||||
|
||||
/**
|
||||
* empty validator always returns true
|
||||
*/
|
||||
template <class Helper> class CNullValidator : CValidatorBase
|
||||
{
|
||||
public:
|
||||
CNullValidator(CCcontract_info* cp)
|
||||
: CValidatorBase(cp) { }
|
||||
|
||||
virtual bool isVinValidator() const { return false; }
|
||||
virtual bool validateVout(CTxOut vout, std::string& message) const { return true; }
|
||||
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -115,7 +115,7 @@ bool LottoExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
|
||||
bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval;
|
||||
return(false); // reject any lotto CC for now
|
||||
return eval->Invalid("no validation yet");
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
preventCCvins = preventCCvouts = -1;
|
||||
|
||||
1
src/cc/makecclib
Executable file
1
src/cc/makecclib
Executable file
@@ -0,0 +1 @@
|
||||
gcc -std=c++11 -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../cclib.so cclib.cpp
|
||||
1070
src/cc/marmara.cpp
1070
src/cc/marmara.cpp
File diff suppressed because it is too large
Load Diff
@@ -75,7 +75,7 @@ bool PaymentsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti
|
||||
bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
|
||||
return(false);
|
||||
return eval->Invalid("no validation yet");
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
|
||||
@@ -82,7 +82,7 @@ bool PegsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &
|
||||
bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
|
||||
return(false);
|
||||
return eval->Invalid("no validation yet");
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
|
||||
@@ -89,7 +89,7 @@ uint8_t DecodePricesFundingOpRet(CScript scriptPubKey,CPubKey &planpk,uint256 &o
|
||||
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
|
||||
{
|
||||
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
|
||||
return(false);
|
||||
return eval->Invalid("no validation yet");
|
||||
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
|
||||
numvins = tx.vin.size();
|
||||
numvouts = tx.vout.size();
|
||||
@@ -326,7 +326,11 @@ std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingt
|
||||
CCchange = (inputs - amount);
|
||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk));
|
||||
// add addr2
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',bettoken,zeroid,0,Mypubkey())));
|
||||
|
||||
std::vector<CPubKey> voutTokenPubkeysEmpty; //TODO: add token vout pubkeys
|
||||
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,
|
||||
EncodeTokenOpRet(bettoken, voutTokenPubkeysEmpty,
|
||||
EncodeAssetOpRet('t',/*bettoken,*/zeroid, 0, Mypubkey()))));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
|
||||
strNetworkID = "main";
|
||||
strCurrencyUnits = "KMD";
|
||||
bip44CoinType = 141; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md (ZCASH, should be VRSC)
|
||||
bip44CoinType = 141; // As registered in https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
||||
consensus.fCoinbaseMustBeProtected = false; // true this is only true wuth Verus and enforced after block 12800
|
||||
consensus.nSubsidySlowStartInterval = 20000;
|
||||
consensus.nSubsidyHalvingInterval = 840000;
|
||||
|
||||
@@ -799,6 +799,11 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
|
||||
uint64_t signedmask,voutmask; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp;
|
||||
uint8_t scriptbuf[10001],pubkeys[64][33],rmd160[20],scriptPubKey[35]; uint256 zero,btctxid,txhash;
|
||||
int32_t i,j,k,numnotaries,notarized,scriptlen,isratification,nid,numvalid,specialtx,notarizedheight,notaryid,len,numvouts,numvins,height,txn_count;
|
||||
if ( pindex == 0 )
|
||||
{
|
||||
fprintf(stderr,"komodo_connectblock null pindex\n");
|
||||
return;
|
||||
}
|
||||
memset(&zero,0,sizeof(zero));
|
||||
komodo_init(pindex->GetHeight());
|
||||
KOMODO_INITDONE = (uint32_t)time(NULL);
|
||||
|
||||
@@ -643,6 +643,10 @@ int32_t komodo_isPoS(CBlock *pblock)
|
||||
{
|
||||
txid = pblock->vtx[n-1].vin[0].prevout.hash;
|
||||
vout = pblock->vtx[n-1].vin[0].prevout.n;
|
||||
if ( ASSETCHAINS_MARMARA != 0 )
|
||||
{
|
||||
// need to verify it was signed by the non-Marmarapk of the 1of2
|
||||
}
|
||||
txtime = komodo_txtime(&value,txid,vout,destaddr);
|
||||
if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) )
|
||||
{
|
||||
@@ -1162,15 +1166,22 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height)
|
||||
n = pblock->vtx[i].vout.size();
|
||||
for (j=0; j<n; j++)
|
||||
{
|
||||
//fprintf(stderr,"(%d %.8f).%d ",i,dstr(block.vtx[i].vout[j].nValue),j);
|
||||
//fprintf(stderr,"(%d %.8f).%d ",i,dstr(pblock->vtx[i].vout[j].nValue),j);
|
||||
if ( i != 0 || j != 1 )
|
||||
total += pblock->vtx[i].vout[j].nValue;
|
||||
if ( total > 1000000 * COIN )
|
||||
{
|
||||
total = 1000000 * COIN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
commission = ((total * ASSETCHAINS_COMMISSION) / COIN);
|
||||
commission = ((total / 10000) * ASSETCHAINS_COMMISSION) / 10000;
|
||||
//commission = ((total * ASSETCHAINS_COMMISSION) / COIN);
|
||||
}
|
||||
if ( commission < 10000 )
|
||||
commission = 0;
|
||||
//fprintf(stderr,"-> %.8f\n",(double)commission/COIN);
|
||||
return(commission);
|
||||
}
|
||||
|
||||
@@ -1699,13 +1710,19 @@ int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
|
||||
if ( ASSETCHAINS_COMMISSION != 0 )
|
||||
{
|
||||
checktoshis = komodo_commission(pblock,height);
|
||||
//fprintf(stderr,"height.%d commission %.8f\n",height,(double)checktoshis/COIN);
|
||||
/*if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 ) jl777: not sure why this was here
|
||||
if ( checktoshis >= 10000 && pblock->vtx[0].vout.size() < 2 )
|
||||
{
|
||||
//fprintf(stderr,"komodo_checkcommission vsize.%d height.%d commission %.8f\n",(int32_t)pblock->vtx[0].vout.size(),height,(double)checktoshis/COIN);
|
||||
return(-1);
|
||||
else*/ if ( checktoshis != 0 )
|
||||
}
|
||||
else if ( checktoshis != 0 )
|
||||
{
|
||||
script = (uint8_t *)&pblock->vtx[0].vout[1].scriptPubKey[0];
|
||||
scriptlen = (int32_t)pblock->vtx[0].vout[1].scriptPubKey.size();
|
||||
//int32_t i;
|
||||
//for (i=0; i<scriptlen; i++)
|
||||
// fprintf(stderr,"%02x",script[i]);
|
||||
//fprintf(stderr," vout[1] %.8f vs %.8f\n",(double)checktoshis/COIN,(double)pblock->vtx[0].vout[1].nValue/COIN);
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 )
|
||||
{
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size()/2 == scriptlen && scriptlen < sizeof(scripthex) )
|
||||
@@ -1721,10 +1738,7 @@ int64_t komodo_checkcommission(CBlock *pblock,int32_t height)
|
||||
matched = 25;
|
||||
if ( matched == 0 )
|
||||
{
|
||||
//int32_t i;
|
||||
//for (i=0; i<25; i++)
|
||||
// fprintf(stderr,"%02x",script[i]);
|
||||
//fprintf(stderr," payment to wrong pubkey scriptlen.%d, scriptpub[%d]\n",scriptlen,(int32_t)ASSETCHAINS_SCRIPTPUB.size()/2);
|
||||
fprintf(stderr," payment to wrong pubkey scriptlen.%d, scriptpub[%d] checktoshis.%llu\n",scriptlen,(int32_t)ASSETCHAINS_SCRIPTPUB.size()/2,(long long)checktoshis);
|
||||
return(-1);
|
||||
|
||||
}
|
||||
@@ -1742,7 +1756,7 @@ bool KOMODO_TEST_ASSETCHAIN_SKIP_POW = 0;
|
||||
|
||||
int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
{
|
||||
uint256 hash; arith_uint256 bnTarget,bhash; bool fNegative,fOverflow; uint8_t *script,pubkey33[33],pubkeys[64][33]; int32_t i,possible,PoSperc,is_PoSblock=0,n,failed = 0,notaryid = -1; int64_t checktoshis,value; CBlockIndex *pprev;
|
||||
uint256 hash; arith_uint256 bnTarget,bhash; bool fNegative,fOverflow; uint8_t *script,pubkey33[33],pubkeys[64][33]; int32_t i,scriptlen,possible,PoSperc,is_PoSblock=0,n,failed = 0,notaryid = -1; int64_t checktoshis,value; CBlockIndex *pprev;
|
||||
if ( KOMODO_TEST_ASSETCHAIN_SKIP_POW == 0 && Params().NetworkIDString() == "regtest" )
|
||||
KOMODO_TEST_ASSETCHAIN_SKIP_POW = 1;
|
||||
if ( !CheckEquihashSolution(pblock, Params()) )
|
||||
@@ -1849,7 +1863,8 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
|
||||
else
|
||||
{
|
||||
script = (uint8_t *)&pblock->vtx[0].vout[0].scriptPubKey[0];
|
||||
if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
|
||||
scriptlen = (int32_t)pblock->vtx[0].vout[0].scriptPubKey.size();
|
||||
if ( scriptlen != 35 || script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 )
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
@@ -2028,9 +2043,12 @@ uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komod
|
||||
kp->hashval = UintToArith256(hash);
|
||||
segid = ((nHeight + kp->segid32) & 0x3f);
|
||||
hashval = _komodo_eligible(kp,ratio,blocktime,maxiters,minage,segid,nHeight,prevtime);
|
||||
//for (int i=32; i>=0; i--)
|
||||
// fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
|
||||
//fprintf(stderr," b.%u minage.%d segid.%d ht.%d prev.%u\n",blocktime,minage,segid,nHeight,prevtime);
|
||||
/*for (int i=31; i>=16; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]);
|
||||
fprintf(stderr," vs ");
|
||||
for (int i=31; i>=16; i--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]);
|
||||
fprintf(stderr," b.%u minage.%d segid.%d ht.%d prev.%u\n",blocktime,minage,segid,nHeight,prevtime);*/
|
||||
if ( hashval <= bnTarget )
|
||||
{
|
||||
for (iter=0; iter<maxiters; iter++)
|
||||
@@ -2073,7 +2091,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
komodo_segids(hashbuf,nHeight-101,100);
|
||||
if ( *blocktimep < tipindex->nTime+60 )
|
||||
*blocktimep = tipindex->nTime+60;
|
||||
//fprintf(stderr,"Start scan of utxo for staking %u ht.%d\n",(uint32_t)time(NULL),nHeight);
|
||||
//fprintf(stderr,"Start scan of utxo for staking %u ht.%d\n",(uint32_t)time(NULL),nHeight);
|
||||
|
||||
bool resetstaker = false;
|
||||
if ( array != 0 )
|
||||
@@ -2098,34 +2116,42 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
maxkp = numkp = 0;
|
||||
lasttime = 0;
|
||||
}
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
if ( ASSETCHAINS_MARMARA == 0 || 1 )
|
||||
{
|
||||
if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
{
|
||||
fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
|
||||
return(0);
|
||||
}
|
||||
counter++;
|
||||
if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
|
||||
{
|
||||
fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth);
|
||||
continue;
|
||||
}
|
||||
CAmount nValue = out.tx->vout[out.i].nValue;
|
||||
if ( nValue < COIN || !out.fSpendable )
|
||||
continue;
|
||||
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
|
||||
if ( ExtractDestination(pk,address) != 0 )
|
||||
{
|
||||
if ( IsMine(*pwalletMain,address) == 0 )
|
||||
continue;
|
||||
if ( GetTransaction(out.tx->GetHash(),tx,hashBlock,true) != 0 && (pindex= komodo_getblockindex(hashBlock)) != 0 )
|
||||
if ( (tipindex= chainActive.Tip()) == 0 || tipindex->GetHeight()+1 > nHeight )
|
||||
{
|
||||
array = komodo_addutxo(array,&numkp,&maxkp,(uint32_t)pindex->nTime,(uint64_t)nValue,out.tx->GetHash(),out.i,(char *)CBitcoinAddress(address).ToString().c_str(),hashbuf,(CScript)pk);
|
||||
//fprintf(stderr,"addutxo numkp.%d vs max.%d\n",numkp,maxkp);
|
||||
fprintf(stderr,"chain tip changed during staking loop t.%u counter.%d\n",(uint32_t)time(NULL),counter);
|
||||
return(0);
|
||||
}
|
||||
counter++;
|
||||
if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth )
|
||||
{
|
||||
fprintf(stderr,"komodo_staked invalid depth %d\n",(int32_t)out.nDepth);
|
||||
continue;
|
||||
}
|
||||
CAmount nValue = out.tx->vout[out.i].nValue;
|
||||
if ( nValue < COIN || !out.fSpendable )
|
||||
continue;
|
||||
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
|
||||
if ( ExtractDestination(pk,address) != 0 )
|
||||
{
|
||||
if ( IsMine(*pwalletMain,address) == 0 )
|
||||
continue;
|
||||
if ( GetTransaction(out.tx->GetHash(),tx,hashBlock,true) != 0 && (pindex= komodo_getblockindex(hashBlock)) != 0 )
|
||||
{
|
||||
array = komodo_addutxo(array,&numkp,&maxkp,(uint32_t)pindex->nTime,(uint64_t)nValue,out.tx->GetHash(),out.i,(char *)CBitcoinAddress(address).ToString().c_str(),hashbuf,(CScript)pk);
|
||||
//fprintf(stderr,"addutxo numkp.%d vs max.%d\n",numkp,maxkp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// calc 1of2 address
|
||||
// iterate all unspents not spent in mempool and komodo_addutxo
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -2162,7 +2188,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"ht.%d error validating winning blocktime %u -> %.8f eligible.%u test prior\n",nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
|
||||
//fprintf(stderr,"ht.%d error validating winning blocktime %u -> %.8f eligible.%u test prior\n",nHeight,*blocktimep,(double)kp->nValue/COIN,eligible);
|
||||
continue;
|
||||
}
|
||||
eligible = besttime;
|
||||
@@ -2204,7 +2230,15 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
txNew.vout[0].nValue = *utxovaluep - txfee;
|
||||
txNew.nLockTime = earliest;
|
||||
CTransaction txNewConst(txNew);
|
||||
signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
|
||||
if ( ASSETCHAINS_MARMARA == 0 || 1 )
|
||||
{
|
||||
signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// add opreturn
|
||||
// signSuccess = CCFinalizetx(...)
|
||||
}
|
||||
if (!signSuccess)
|
||||
fprintf(stderr,"failed to create signature\n");
|
||||
else
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
#define KOMODO_SAPLING_DEADLINE 1550188800 // Feb 15th, 2019
|
||||
#define _COINBASE_MATURITY 100
|
||||
|
||||
#define SETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] |= (1 << ((bitoffset) & 7)))
|
||||
#define GETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] & (1 << ((bitoffset) & 7)))
|
||||
#define CLEARBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] &= ~(1 << ((bitoffset) & 7)))
|
||||
|
||||
extern uint8_t ASSETCHAINS_TXPOW,ASSETCHAINS_PUBLIC;
|
||||
int32_t MAX_BLOCK_SIZE(int32_t height);
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
// paxdeposit equivalent in reverse makes opreturn and KMD does the same in reverse
|
||||
#include "komodo_defs.h"
|
||||
|
||||
int32_t MarmaraValidateCoinbase(int32_t height,CTransaction tx);
|
||||
|
||||
int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base)
|
||||
{
|
||||
int32_t baseid; struct komodo_state *sp; int64_t netliability,maxallowed,maxval;
|
||||
@@ -687,6 +689,14 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( height > 0 && ASSETCHAINS_MARMARA != 0 && (height & 1) == 0 )
|
||||
{
|
||||
if ( MarmaraValidateCoinbase(height,block.vtx[0]) < 0 )
|
||||
{
|
||||
fprintf(stderr,"MARMARA error ht.%d constrains even height blocks to pay 100%% to CC in vout0 with opreturn\n",height);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
// we don't want these checks in VRSC, leave it at the Sapling upgrade
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 ||
|
||||
(ASSETCHAINS_COMMISSION != 0 && height > 1) ||
|
||||
@@ -1378,7 +1388,7 @@ void komodo_passport_iteration()
|
||||
{
|
||||
static long lastpos[34]; static char userpass[33][1024]; static uint32_t lasttime,callcounter,lastinterest;
|
||||
int32_t maxseconds = 10;
|
||||
FILE *fp; uint8_t *filedata; long fpos,datalen,lastfpos; int32_t baseid,limit,n,ht,isrealtime,expired,refid,blocks,longest; struct komodo_state *sp,*refsp; char *retstr,fname[512],*base,symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; uint32_t buf[3],starttime; cJSON *infoobj,*result; uint64_t RTmask = 0; //CBlockIndex *pindex;
|
||||
FILE *fp; uint8_t *filedata; long fpos,datalen,lastfpos; int32_t baseid,limit,n,ht,isrealtime,expired,refid,blocks,longest; struct komodo_state *sp,*refsp; char *retstr,fname[512],*base,symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; uint32_t buf[3],starttime; uint64_t RTmask = 0; //CBlockIndex *pindex;
|
||||
expired = 0;
|
||||
while ( KOMODO_INITDONE == 0 )
|
||||
{
|
||||
|
||||
@@ -48,8 +48,8 @@ unsigned int WITNESS_CACHE_SIZE = _COINBASE_MATURITY+10;
|
||||
|
||||
int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,KOMODO_CONNECTING = -1,KOMODO_DEALERNODE,KOMODO_EXTRASATOSHI,ASSETCHAINS_FOUNDERS;
|
||||
int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1;
|
||||
std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,ASSETCHAINS_SELFIMPORT;
|
||||
uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEYHASH[20],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW;
|
||||
std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,ASSETCHAINS_SELFIMPORT,ASSETCHAINS_CCLIB;
|
||||
uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEYHASH[20],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW,ASSETCHAINS_MARMARA;
|
||||
bool VERUS_MINTBLOCKS;
|
||||
|
||||
char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096];
|
||||
@@ -71,6 +71,7 @@ uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0;
|
||||
|
||||
uint32_t ASSETCHAINS_LASTERA = 1;
|
||||
uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS];
|
||||
uint8_t ASSETCHAINS_CCDISABLES[256];
|
||||
|
||||
#define _ASSETCHAINS_EQUIHASH 0
|
||||
uint32_t ASSETCHAINS_NUMALGOS = 2;
|
||||
|
||||
@@ -629,7 +629,7 @@ uint64_t jumblr_increment(uint8_t r,int32_t height,uint64_t total,uint64_t bigge
|
||||
void jumblr_iteration()
|
||||
{
|
||||
static int32_t lastheight; static uint32_t lasttime;
|
||||
char *zaddr,*addr,*retstr,secretaddr[64]; cJSON *array; int32_t i,iter,height,acpublic,counter,chosen_one,n; uint64_t smallest,medium,biggest,amount=0,total=0; double fee; struct jumblr_item *ptr,*tmp; uint16_t r,s;
|
||||
char *zaddr,*addr,*retstr=0,secretaddr[64]; cJSON *array; int32_t i,iter,height,acpublic,counter,chosen_one,n; uint64_t smallest,medium,biggest,amount=0,total=0; double fee; struct jumblr_item *ptr,*tmp; uint16_t r,s;
|
||||
acpublic = ASSETCHAINS_PUBLIC;
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && GetTime() >= KOMODO_SAPLING_DEADLINE )
|
||||
acpublic = 1;
|
||||
@@ -648,7 +648,7 @@ void jumblr_iteration()
|
||||
}
|
||||
free_json(array);
|
||||
}
|
||||
free(retstr);
|
||||
free(retstr), retstr = 0;
|
||||
}
|
||||
}
|
||||
height = (int32_t)chainActive.LastTip()->GetHeight();
|
||||
@@ -691,7 +691,7 @@ void jumblr_iteration()
|
||||
if ( amount > 0 && (retstr= jumblr_sendt_to_z(Jumblr_deposit,addr,dstr(amount))) != 0 )
|
||||
{
|
||||
printf("sendt_to_z.(%s)\n",retstr);
|
||||
free(retstr);
|
||||
free(retstr), retstr = 0;
|
||||
}
|
||||
free(zaddr);
|
||||
} else printf("no zaddr from jumblr_zgetnewaddress\n");
|
||||
@@ -723,7 +723,7 @@ void jumblr_iteration()
|
||||
if ( (retstr= jumblr_sendz_to_z(ptr->dest,addr,dstr(total))) != 0 )
|
||||
{
|
||||
printf("n.%d counter.%d chosen_one.%d send z_to_z.(%s)\n",n,counter,chosen_one,retstr);
|
||||
free(retstr);
|
||||
free(retstr), retstr = 0;
|
||||
}
|
||||
ptr->spent = (uint32_t)time(NULL);
|
||||
free(zaddr);
|
||||
@@ -768,7 +768,7 @@ void jumblr_iteration()
|
||||
if ( (retstr= jumblr_sendz_to_t(ptr->dest,secretaddr,dstr(total))) != 0 )
|
||||
{
|
||||
printf("%s send z_to_t.(%s)\n",secretaddr,retstr);
|
||||
free(retstr);
|
||||
free(retstr), retstr = 0;
|
||||
} else printf("null return from jumblr_sendz_to_t\n");
|
||||
ptr->spent = (uint32_t)time(NULL);
|
||||
break;
|
||||
|
||||
@@ -1654,9 +1654,10 @@ extern int64_t MAX_MONEY;
|
||||
void komodo_args(char *argv0)
|
||||
{
|
||||
extern const char *Notaries_elected1[][2];
|
||||
std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,baseid,len,n,extralen = 0;
|
||||
std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],disablebits[32],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,nonz,baseid,len,n,extralen = 0; uint64_t ccenables[256];
|
||||
IS_KOMODO_NOTARY = GetBoolArg("-notary", false);
|
||||
|
||||
memset(ccenables,0,sizeof(ccenables));
|
||||
memset(disablebits,0,sizeof(disablebits));
|
||||
if ( GetBoolArg("-gen", false) != 0 )
|
||||
{
|
||||
KOMODO_MININGTHREADS = GetArg("-genproclimit",-1);
|
||||
@@ -1778,6 +1779,34 @@ void komodo_args(char *argv0)
|
||||
ASSETCHAINS_SCRIPTPUB = GetArg("-ac_script","");
|
||||
ASSETCHAINS_BEAMPORT = GetArg("-ac_beam",0);
|
||||
ASSETCHAINS_CODAPORT = GetArg("-ac_coda",0);
|
||||
ASSETCHAINS_MARMARA = GetArg("-ac_marmara",0);
|
||||
if ( ASSETCHAINS_CC != 0 )
|
||||
{
|
||||
ASSETCHAINS_CCLIB = GetArg("-ac_cclib","");
|
||||
Split(GetArg("-ac_ccenable",""), ccenables, 0);
|
||||
for (i=nonz=0; i<0x100; i++)
|
||||
{
|
||||
if ( ccenables[i] != 0 )
|
||||
{
|
||||
nonz++;
|
||||
fprintf(stderr,"%d ",(uint8_t)(ccenables[i] & 0xff));
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"nonz.%d ccenables[]\n",nonz);
|
||||
if ( nonz > 0 )
|
||||
{
|
||||
for (i=0; i<256; i++)
|
||||
{
|
||||
ASSETCHAINS_CCDISABLES[i] = 1;
|
||||
SETBIT(disablebits,i);
|
||||
}
|
||||
for (i=0; i<256; i++)
|
||||
{
|
||||
CLEARBIT(disablebits,(ccenables[i] & 0xff));
|
||||
ASSETCHAINS_CCDISABLES[ccenables[i] & 0xff] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ASSETCHAINS_BEAMPORT != 0 && ASSETCHAINS_CODAPORT != 0 )
|
||||
{
|
||||
fprintf(stderr,"can only have one of -ac_beam or -ac_coda\n");
|
||||
@@ -1857,7 +1886,12 @@ void komodo_args(char *argv0)
|
||||
printf("ASSETCHAINS_FOUNDERS needs an ASETCHAINS_OVERRIDE_PUBKEY\n");
|
||||
}
|
||||
}
|
||||
if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 )
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 && ASSETCHAINS_MARMARA != 0 )
|
||||
{
|
||||
fprintf(stderr,"-ac_script and -ac_marmara are mutually exclusive\n");
|
||||
exit(0);
|
||||
}
|
||||
if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 )
|
||||
{
|
||||
fprintf(stderr,"perc %.4f%% ac_pub=[%02x%02x%02x...] acsize.%d\n",dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0],ASSETCHAINS_OVERRIDE_PUBKEY33[1],ASSETCHAINS_OVERRIDE_PUBKEY33[2],(int32_t)ASSETCHAINS_SCRIPTPUB.size());
|
||||
extraptr = extrabuf;
|
||||
@@ -1931,8 +1965,24 @@ void komodo_args(char *argv0)
|
||||
extraptr[extralen++] = 'b';
|
||||
if ( ASSETCHAINS_CODAPORT != 0 )
|
||||
extraptr[extralen++] = 'c';
|
||||
if ( ASSETCHAINS_MARMARA != 0 )
|
||||
extraptr[extralen++] = ASSETCHAINS_MARMARA;
|
||||
if ( nonz > 0 )
|
||||
{
|
||||
memcpy(&extraptr[extralen],disablebits,sizeof(disablebits));
|
||||
extralen += sizeof(disablebits);
|
||||
}
|
||||
if ( ASSETCHAINS_CCLIB.size() > 1 )
|
||||
{
|
||||
for (i=0; i<ASSETCHAINS_CCLIB.size(); i++)
|
||||
{
|
||||
extraptr[extralen++] = ASSETCHAINS_CCLIB[i];
|
||||
fprintf(stderr,"%c",ASSETCHAINS_CCLIB[i]);
|
||||
}
|
||||
fprintf(stderr," <- CCLIB name\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
addn = GetArg("-seednode","");
|
||||
if ( strlen(addn.c_str()) > 0 )
|
||||
ASSETCHAINS_SEED = 1;
|
||||
|
||||
@@ -3462,7 +3462,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
{
|
||||
if ( block.vtx[0].vout.size() >= 2 && block.vtx[0].vout[1].nValue == checktoshis )
|
||||
blockReward += checktoshis;
|
||||
else fprintf(stderr,"checktoshis %.8f numvouts %d\n",dstr(checktoshis),(int32_t)block.vtx[0].vout.size());
|
||||
else if ( pindex->GetHeight() > 1 )
|
||||
fprintf(stderr,"checktoshis %.8f vs %.8f numvouts %d\n",dstr(checktoshis),dstr(block.vtx[0].vout[1].nValue),(int32_t)block.vtx[0].vout.size());
|
||||
}
|
||||
}
|
||||
if (ASSETCHAINS_SYMBOL[0] != 0 && pindex->GetHeight() == 1 && block.vtx[0].GetValueOut() != blockReward)
|
||||
@@ -3496,6 +3497,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
CDiskBlockPos pos;
|
||||
if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
|
||||
return error("ConnectBlock(): FindUndoPos failed");
|
||||
if ( pindex->pprev == 0 )
|
||||
fprintf(stderr,"ConnectBlock: unexpected null pprev\n");
|
||||
if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
|
||||
return AbortNode(state, "Failed to write undo data");
|
||||
|
||||
|
||||
118
src/miner.cpp
118
src/miner.cpp
@@ -18,6 +18,7 @@
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
#include "pubkey.h"
|
||||
#include "miner.h"
|
||||
#ifdef ENABLE_MINING
|
||||
#include "pow/tromp/equi_miner.h"
|
||||
@@ -141,7 +142,7 @@ extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||
extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY,ASSETCHAINS_SCRIPTPUB;
|
||||
void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
|
||||
|
||||
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
|
||||
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_MARMARA;
|
||||
uint32_t Mining_start,Mining_height;
|
||||
int32_t My_notaryid = -1;
|
||||
int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp);
|
||||
@@ -155,19 +156,26 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
|
||||
int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, uint8_t *utxosig, CPubKey &pk);
|
||||
int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33);
|
||||
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
|
||||
CScript Marmara_scriptPubKey(int32_t height,CPubKey pk);
|
||||
CScript MarmaraCoinbaseOpret(uint8_t funcid,int32_t height,CPubKey pk);
|
||||
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
|
||||
|
||||
CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake)
|
||||
CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake)
|
||||
{
|
||||
CScript scriptPubKeyIn(_scriptPubKeyIn);
|
||||
|
||||
CPubKey pk = CPubKey();
|
||||
std::vector<std::vector<unsigned char>> vAddrs;
|
||||
txnouttype txT;
|
||||
if ( scriptPubKeyIn.size() > 0 && Solver(scriptPubKeyIn, txT, vAddrs))
|
||||
CPubKey pk;
|
||||
if ( _pk.size() != 33 )
|
||||
{
|
||||
if (txT == TX_PUBKEY)
|
||||
pk = CPubKey(vAddrs[0]);
|
||||
}
|
||||
pk = CPubKey();
|
||||
std::vector<std::vector<unsigned char>> vAddrs;
|
||||
txnouttype txT;
|
||||
if ( scriptPubKeyIn.size() > 0 && Solver(scriptPubKeyIn, txT, vAddrs))
|
||||
{
|
||||
if (txT == TX_PUBKEY)
|
||||
pk = CPubKey(vAddrs[0]);
|
||||
}
|
||||
} else pk = _pk;
|
||||
|
||||
uint64_t deposits; int32_t isrealtime,kmdheight; uint32_t blocktime; const CChainParams& chainparams = Params();
|
||||
//fprintf(stderr,"create new block\n");
|
||||
@@ -531,36 +539,17 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
|
||||
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 && IS_KOMODO_NOTARY != 0 && My_notaryid >= 0 )
|
||||
txNew.vout[0].nValue += 5000;
|
||||
pblock->vtx[0] = txNew;
|
||||
|
||||
// check if coinbase transactions must be time locked at current subsidy and prepend the time lock
|
||||
// to transaction if so, cast for GTE operator
|
||||
if ((uint64_t)(txNew.vout[0].nValue) >= ASSETCHAINS_TIMELOCKGTE)
|
||||
if ( ASSETCHAINS_MARMARA != 0 && nHeight > 0 && (nHeight & 1) == 0 )
|
||||
{
|
||||
int32_t opretlen, p2shlen, scriptlen;
|
||||
CScriptExt opretScript = CScriptExt();
|
||||
|
||||
char checkaddr[64];
|
||||
Getscriptaddress(checkaddr,txNew.vout[0].scriptPubKey);
|
||||
//`fprintf(stderr,"set mining coinbase -> %s\n",checkaddr);
|
||||
txNew.vout.resize(2);
|
||||
|
||||
// prepend time lock to original script unless original script is P2SH, in which case, we will leave the coins
|
||||
// protected only by the time lock rather than 100% inaccessible
|
||||
opretScript.AddCheckLockTimeVerify(komodo_block_unlocktime(nHeight));
|
||||
if (scriptPubKeyIn.IsPayToScriptHash() || scriptPubKeyIn.IsPayToCryptoCondition())
|
||||
{
|
||||
fprintf(stderr,"CreateNewBlock: attempt to add timelock to pay2sh or pay2cc\n");
|
||||
if ( ASSETCHAINS_SYMBOL[0] == 0 || (ASSETCHAINS_SYMBOL[0] != 0 && !isStake) )
|
||||
{
|
||||
LEAVE_CRITICAL_SECTION(cs_main);
|
||||
LEAVE_CRITICAL_SECTION(mempool.cs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
opretScript += scriptPubKeyIn;
|
||||
|
||||
txNew.vout[0].scriptPubKey = CScriptExt().PayToScriptHash(CScriptID(opretScript));
|
||||
txNew.vout[1].scriptPubKey = CScriptExt().OpReturnScript(opretScript, OPRETTYPE_TIMELOCK);
|
||||
txNew.vout[1].nValue = 0;
|
||||
} // timelocks and commissions are currently incompatible due to validation complexity of the combination
|
||||
txNew.vout[1].scriptPubKey = MarmaraCoinbaseOpret('C',nHeight,pk);
|
||||
}
|
||||
else if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission((CBlock*)&pblocktemplate->block,(int32_t)nHeight)) != 0 )
|
||||
{
|
||||
int32_t i; uint8_t *ptr;
|
||||
@@ -568,6 +557,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
|
||||
txNew.vout[1].nValue = commission;
|
||||
if ( ASSETCHAINS_SCRIPTPUB.size() > 1 )
|
||||
{
|
||||
//fprintf(stderr,"mine to -ac_script\n");
|
||||
//txNew.vout[1].scriptPubKey = CScript() << ParseHex();
|
||||
int32_t len = strlen(ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
len >>= 1;
|
||||
@@ -581,11 +571,37 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
|
||||
ptr = (uint8_t *)&txNew.vout[1].scriptPubKey[0];
|
||||
ptr[0] = 33;
|
||||
for (i=0; i<33; i++)
|
||||
{
|
||||
ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i];
|
||||
//fprintf(stderr,"%02x",ptr[i+1]);
|
||||
}
|
||||
ptr[34] = OP_CHECKSIG;
|
||||
//fprintf(stderr," set ASSETCHAINS_OVERRIDE_PUBKEY33 into vout[1]\n");
|
||||
}
|
||||
//printf("autocreate commision vout\n");
|
||||
}
|
||||
else if ( (uint64_t)(txNew.vout[0].nValue) >= ASSETCHAINS_TIMELOCKGTE)
|
||||
{
|
||||
int32_t opretlen, p2shlen, scriptlen;
|
||||
CScriptExt opretScript = CScriptExt();
|
||||
|
||||
txNew.vout.resize(2);
|
||||
|
||||
// prepend time lock to original script unless original script is P2SH, in which case, we will leave the coins
|
||||
// protected only by the time lock rather than 100% inaccessible
|
||||
opretScript.AddCheckLockTimeVerify(komodo_block_unlocktime(nHeight));
|
||||
if (scriptPubKeyIn.IsPayToScriptHash() || scriptPubKeyIn.IsPayToCryptoCondition())
|
||||
{
|
||||
fprintf(stderr,"CreateNewBlock: attempt to add timelock to pay2sh or pay2cc\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
opretScript += scriptPubKeyIn;
|
||||
|
||||
txNew.vout[0].scriptPubKey = CScriptExt().PayToScriptHash(CScriptID(opretScript));
|
||||
txNew.vout[1].scriptPubKey = CScriptExt().OpReturnScript(opretScript, OPRETTYPE_TIMELOCK);
|
||||
txNew.vout[1].nValue = 0;
|
||||
} // timelocks and commissions are currently incompatible due to validation complexity of the combination
|
||||
|
||||
pblock->vtx[0] = txNew;
|
||||
pblocktemplate->vTxFees[0] = -nFees;
|
||||
@@ -753,7 +769,10 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
|
||||
if ( nHeight == 1 && ASSETCHAINS_COMMISSION != 0 )
|
||||
{
|
||||
if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
|
||||
scriptPubKey = CScript() << ParseHex(ASSETCHAINS_OVERRIDE_PUBKEY) << OP_CHECKSIG;
|
||||
{
|
||||
pubkey = ParseHex(ASSETCHAINS_OVERRIDE_PUBKEY);
|
||||
scriptPubKey = CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = strlen(ASSETCHAINS_SCRIPTPUB.c_str());
|
||||
@@ -766,7 +785,8 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
|
||||
else if ( USE_EXTERNAL_PUBKEY != 0 )
|
||||
{
|
||||
//fprintf(stderr,"use notary pubkey\n");
|
||||
scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
|
||||
pubkey = ParseHex(NOTARY_PUBKEY);
|
||||
scriptPubKey = CScript() << ParseHex(HexStr(pubkey)) << OP_CHECKSIG;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -785,7 +805,11 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight,
|
||||
//scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
|
||||
}
|
||||
}
|
||||
return CreateNewBlock(scriptPubKey, gpucount, isStake);
|
||||
if ( ASSETCHAINS_MARMARA != 0 && nHeight > 0 && (nHeight & 1) == 0 )
|
||||
scriptPubKey = Marmara_scriptPubKey(nHeight,pubkey);
|
||||
if ( ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0 )
|
||||
isStake = true;
|
||||
return CreateNewBlock(pubkey,scriptPubKey, gpucount, isStake);
|
||||
}
|
||||
|
||||
void komodo_broadcast(CBlock *pblock,int32_t limit)
|
||||
@@ -1181,14 +1205,14 @@ void static BitcoinMiner_noeq()
|
||||
miningTimer.start();
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, Mining_height, 0);
|
||||
CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, Mining_height, ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0);
|
||||
#else
|
||||
CBlockTemplate *ptr = CreateNewBlockWithKey();
|
||||
#endif
|
||||
if ( ptr == 0 )
|
||||
{
|
||||
static uint32_t counter;
|
||||
if ( counter++ < 100 )
|
||||
if ( counter++ < 10 )
|
||||
fprintf(stderr,"created illegal block, retry\n");
|
||||
continue;
|
||||
}
|
||||
@@ -1476,15 +1500,15 @@ void static BitcoinMiner()
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
// notaries always default to staking
|
||||
CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, pindexPrev->GetHeight()+1, gpucount, ASSETCHAINS_STAKED != 0 && GetArg("-genproclimit", -1) == 0);
|
||||
CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, pindexPrev->GetHeight()+1, gpucount, ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0);
|
||||
#else
|
||||
CBlockTemplate *ptr = CreateNewBlockWithKey();
|
||||
#endif
|
||||
if ( ptr == 0 )
|
||||
{
|
||||
static uint32_t counter;
|
||||
if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 )
|
||||
fprintf(stderr,"created illegal block, retry\n");
|
||||
if ( counter++ < 10 && ASSETCHAINS_STAKED == 0 )
|
||||
fprintf(stderr,"created illegal blockB, retry\n");
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
@@ -1582,11 +1606,11 @@ void static BitcoinMiner()
|
||||
int32_t percPoS,z; bool fNegative,fOverflow;
|
||||
HASHTarget_POW = komodo_PoWtarget(&percPoS,HASHTarget,Mining_height,ASSETCHAINS_STAKED);
|
||||
HASHTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow);
|
||||
if ( ASSETCHAINS_STAKED < 100 )
|
||||
if ( ASSETCHAINS_STAKED < 100 && KOMODO_MININGTHREADS == 0 )
|
||||
{
|
||||
for (z=31; z>=0; z--)
|
||||
fprintf(stderr,"%02x",((uint8_t *)&HASHTarget_POW)[z]);
|
||||
fprintf(stderr," PoW for staked coin PoS %d%% vs target %d%%\n",percPoS,(int32_t)ASSETCHAINS_STAKED);
|
||||
fprintf(stderr," PoW for staked coin PoS %d%% vs target %d%% ht.%d\n",percPoS,(int32_t)ASSETCHAINS_STAKED,Mining_height);
|
||||
}
|
||||
}
|
||||
while (true)
|
||||
@@ -1889,12 +1913,12 @@ void static BitcoinMiner()
|
||||
for (int i = 0; i < nThreads; i++) {
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
|
||||
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH || (ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0) )
|
||||
minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
|
||||
else
|
||||
minerThreads->create_thread(boost::bind(&BitcoinMiner_noeq, pwallet));
|
||||
#else
|
||||
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH)
|
||||
if (ASSETCHAINS_ALGO == ASSETCHAINS_EQUIHASH || (ASSETCHAINS_STAKED != 0 && KOMODO_MININGTHREADS == 0) )
|
||||
minerThreads->create_thread(&BitcoinMiner);
|
||||
else
|
||||
minerThreads->create_thread(&BitcoinMiner_noeq);
|
||||
|
||||
@@ -43,7 +43,7 @@ struct CBlockTemplate
|
||||
#define KOMODO_MAXGPUCOUNT 65
|
||||
|
||||
/** Generate a new block, without valid proof-of-work */
|
||||
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, int32_t gpucount, bool isStake = false);
|
||||
CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& scriptPubKeyIn, int32_t gpucount, bool isStake = false);
|
||||
#ifdef ENABLE_WALLET
|
||||
boost::optional<CScript> GetMinerScriptPubKey(CReserveKey& reservekey);
|
||||
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, int32_t gpucount, bool isStake = false);
|
||||
|
||||
@@ -406,8 +406,16 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "faucet", "faucetget", &faucetget, true },
|
||||
{ "faucet", "faucetaddress", &faucetaddress, true },
|
||||
|
||||
// Heir
|
||||
{ "heir", "heiraddress", &heiraddress, true },
|
||||
// Heir
|
||||
{ "heir", "heiraddress", &heiraddress, true },
|
||||
{ "heir", "heirfund", &heirfund, true },
|
||||
{ "heir", "heiradd", &heiradd, true },
|
||||
{ "heir", "heirclaim", &heirclaim, true },
|
||||
/* { "heir", "heirfundtokens", &heirfundtokens, true },
|
||||
{ "heir", "heiraddtokens", &heiraddtokens, true },
|
||||
{ "heir", "heirclaimtokens", &heirclaimtokens, true },*/
|
||||
{ "heir", "heirinfo", &heirinfo, true },
|
||||
{ "heir", "heirlist", &heirlist, true },
|
||||
|
||||
// Channels
|
||||
{ "channels", "channelsaddress", &channelsaddress, true },
|
||||
@@ -442,7 +450,15 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "pegs", "pegsaddress", &pegsaddress, true },
|
||||
|
||||
// Marmara
|
||||
{ "marmara", "Marmaraaddress", &marmaraaddress, true },
|
||||
{ "marmara", "marmaraaddress", &marmaraaddress, true },
|
||||
{ "marmara", "marmarapoolpayout", &marmara_poolpayout, true },
|
||||
{ "marmara", "marmarareceive", &marmara_receive, true },
|
||||
{ "marmara", "marmaraissue", &marmara_issue, true },
|
||||
{ "marmara", "marmaratransfer", &marmara_transfer, true },
|
||||
{ "marmara", "marmarainfo", &marmara_info, true },
|
||||
{ "marmara", "marmaracreditloop", &marmara_creditloop, true },
|
||||
{ "marmara", "marmarasettlement", &marmara_settlement, true },
|
||||
{ "marmara", "marmaralock", &marmara_lock, true },
|
||||
|
||||
// Payments
|
||||
{ "payments", "paymentsaddress", &paymentsaddress, true },
|
||||
@@ -472,7 +488,8 @@ static const CRPCCommand vRPCCommands[] =
|
||||
{ "dice", "dicestatus", &dicestatus, true },
|
||||
{ "dice", "diceaddress", &diceaddress, true },
|
||||
|
||||
// tokens
|
||||
// tokens & assets
|
||||
{ "tokens", "assetsaddress", &assetsaddress, true },
|
||||
{ "tokens", "tokeninfo", &tokeninfo, true },
|
||||
{ "tokens", "tokenlist", &tokenlist, true },
|
||||
{ "tokens", "tokenorders", &tokenorders, true },
|
||||
|
||||
@@ -242,6 +242,7 @@ 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 assetsaddress(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);
|
||||
@@ -253,6 +254,11 @@ extern UniValue tokencancelask(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenfillask(const UniValue& params, bool fHelp);
|
||||
extern UniValue tokenconvert(const UniValue& params, bool fHelp);
|
||||
extern UniValue heiraddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue heirfund(const UniValue& params, bool fHelp);
|
||||
extern UniValue heiradd(const UniValue& params, bool fHelp);
|
||||
extern UniValue heirclaim(const UniValue& params, bool fHelp);
|
||||
extern UniValue heirinfo(const UniValue& params, bool fHelp);
|
||||
extern UniValue heirlist(const UniValue& params, bool fHelp);
|
||||
extern UniValue channelsaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue oraclesaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue oracleslist(const UniValue& params, bool fHelp);
|
||||
@@ -272,6 +278,14 @@ extern UniValue pricesstatus(const UniValue& params, bool fHelp);
|
||||
extern UniValue pricesfinish(const UniValue& params, bool fHelp);
|
||||
extern UniValue pegsaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue marmaraaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue marmara_poolpayout(const UniValue& params, bool fHelp);
|
||||
extern UniValue marmara_receive(const UniValue& params, bool fHelp);
|
||||
extern UniValue marmara_issue(const UniValue& params, bool fHelp);
|
||||
extern UniValue marmara_transfer(const UniValue& params, bool fHelp);
|
||||
extern UniValue marmara_info(const UniValue& params, bool fHelp);
|
||||
extern UniValue marmara_creditloop(const UniValue& params, bool fHelp);
|
||||
extern UniValue marmara_settlement(const UniValue& params, bool fHelp);
|
||||
extern UniValue marmara_lock(const UniValue& params, bool fHelp);
|
||||
extern UniValue paymentsaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue gatewaysaddress(const UniValue& params, bool fHelp);
|
||||
extern UniValue gatewayslist(const UniValue& params, bool fHelp);
|
||||
|
||||
@@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i)
|
||||
{
|
||||
// Simple block creation, nothing special yet:
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
|
||||
CBlock *pblock = &pblocktemplate->block; // pointer for convenience
|
||||
pblock->nVersion = 4;
|
||||
@@ -273,7 +273,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
}
|
||||
|
||||
// Just to make sure we can still make simple blocks
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
|
||||
// block sigops > limit: 1000 CHECKMULTISIG + 1
|
||||
@@ -292,7 +292,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
|
||||
tx.vin[0].prevout.hash = hash;
|
||||
}
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
||||
@@ -313,14 +313,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
|
||||
tx.vin[0].prevout.hash = hash;
|
||||
}
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
||||
// orphan in mempool
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
||||
@@ -338,7 +338,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
tx.vout[0].nValue = 49000LL;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
||||
@@ -349,7 +349,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
tx.vout[0].nValue = 0;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
||||
@@ -367,7 +367,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
tx.vout[0].nValue -= 10000;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
||||
@@ -381,17 +381,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
tx.vout[0].scriptPubKey = CScript() << OP_2;
|
||||
hash = tx.GetHash();
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
mempool.clear();
|
||||
|
||||
// subsidy changing
|
||||
int nHeight = chainActive.Height();
|
||||
chainActive.Tip()->SetHeight(209999);
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
chainActive.Tip()->SetHeight(210000);
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
delete pblocktemplate;
|
||||
chainActive.Tip()->SetHeight(nHeight);
|
||||
|
||||
@@ -423,7 +423,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx2));
|
||||
BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST));
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
|
||||
// Neither tx should have made it into the template.
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 1);
|
||||
@@ -438,7 +438,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
//BOOST_CHECK(CheckFinalTx(tx));
|
||||
//BOOST_CHECK(CheckFinalTx(tx2));
|
||||
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey,-1));
|
||||
BOOST_CHECK(pblocktemplate = CreateNewBlock(CPubKey(),scriptPubKey,-1));
|
||||
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2);
|
||||
delete pblocktemplate;
|
||||
|
||||
|
||||
@@ -2979,7 +2979,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||
BlockMap::const_iterator it = mapBlockIndex.find(hashBlock);
|
||||
if (it != mapBlockIndex.end()) {
|
||||
nHeight = it->second->GetHeight();
|
||||
fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight);
|
||||
//fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight);
|
||||
} else {
|
||||
// TODO: should we throw JSONRPCError ?
|
||||
fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() );
|
||||
@@ -3013,7 +3013,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp)
|
||||
BlockMap::const_iterator it = mapBlockIndex.find(hashBlock);
|
||||
if (it != mapBlockIndex.end()) {
|
||||
nHeight = it->second->GetHeight();
|
||||
fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight);
|
||||
//fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight);
|
||||
} else {
|
||||
// TODO: should we throw JSONRPCError ?
|
||||
fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() );
|
||||
@@ -3804,7 +3804,7 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
|
||||
BlockMap::const_iterator it = mapBlockIndex.find(hashBlock);
|
||||
if (it != mapBlockIndex.end()) {
|
||||
nHeight = it->second->GetHeight();
|
||||
fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight);
|
||||
//fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight);
|
||||
} else {
|
||||
fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() );
|
||||
}
|
||||
@@ -3836,7 +3836,7 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
|
||||
BlockMap::const_iterator it = mapBlockIndex.find(hashBlock);
|
||||
if (it != mapBlockIndex.end()) {
|
||||
nHeight = it->second->GetHeight();
|
||||
fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight);
|
||||
//fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight);
|
||||
} else {
|
||||
fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() );
|
||||
}
|
||||
@@ -5094,8 +5094,8 @@ int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33)
|
||||
if (!EnsureWalletIsAvailable(0))
|
||||
return 0;
|
||||
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
assert(pwalletMain != NULL);
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
utxovalue = 0;
|
||||
memset(&utxotxid,0,sizeof(utxotxid));
|
||||
@@ -5417,27 +5417,19 @@ UniValue gatewaysaddress(const UniValue& params, bool fHelp)
|
||||
|
||||
UniValue heiraddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> destPubkey;
|
||||
|
||||
cp = CCinit(&C,EVAL_HEIR);
|
||||
if ( fHelp || (params.size() != 4 && params.size() != 3))
|
||||
throw runtime_error("heiraddress func txid amount [destpubkey]\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());
|
||||
|
||||
char funcid = ((char *)params[0].get_str().c_str())[0];
|
||||
uint256 assetid = Parseuint256((char *)params[1].get_str().c_str());
|
||||
int64_t funds = atof(params[2].get_str().c_str()) * COIN ;
|
||||
if(params.size() == 4)
|
||||
destPubkey = ParseHex(params[3].get_str().c_str());
|
||||
|
||||
//return HeirFundBad(funcid, assetid, funds, destPubkey);
|
||||
|
||||
return(CCaddress(cp,(char *)"Heir",destPubkey));
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
cp = CCinit(&C,EVAL_HEIR);
|
||||
if ( fHelp || params.size() > 1 )
|
||||
throw runtime_error("heiraddress [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 *)"Heir",pubkey));
|
||||
}
|
||||
|
||||
|
||||
|
||||
UniValue lottoaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
@@ -5518,17 +5510,200 @@ UniValue rewardsaddress(const UniValue& params, bool fHelp)
|
||||
return(CCaddress(cp,(char *)"Rewards",pubkey));
|
||||
}
|
||||
|
||||
UniValue assetsaddress(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("assetsaddress [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 tokenaddress(const UniValue& params, bool fHelp)
|
||||
{
|
||||
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
|
||||
cp = CCinit(&C,EVAL_ASSETS);
|
||||
cp = CCinit(&C,EVAL_TOKENS);
|
||||
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));
|
||||
return(CCaddress(cp,(char *)"Tokens", pubkey));
|
||||
}
|
||||
|
||||
UniValue marmara_poolpayout(const UniValue& params, bool fHelp)
|
||||
{
|
||||
int32_t firstheight; double perc; char *jsonstr;
|
||||
if ( fHelp || params.size() != 3 )
|
||||
{
|
||||
// marmarapoolpayout 0.5 2 '[["024131032ed90941e714db8e6dd176fe5a86c9d873d279edecf005c06f773da686",1000],["02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92",100]]';
|
||||
//marmarapoolpayout 0 2 '[["024131032ed90941e714db8e6dd176fe5a86c9d873d279edecf005c06f773da686",1000]]'
|
||||
throw runtime_error("marmarapoolpayout perc firstheight \"[[\\\"pubkey\\\":shares], ...]\"\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");
|
||||
perc = atof(params[0].get_str().c_str()) / 100.;
|
||||
firstheight = atol(params[1].get_str().c_str());
|
||||
jsonstr = (char *)params[2].get_str().c_str();
|
||||
return(MarmaraPoolPayout(0,firstheight,perc,jsonstr)); // [[pk0, shares0], [pk1, shares1], ...]
|
||||
}
|
||||
|
||||
UniValue marmara_receive(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 batontxid; std::vector<uint8_t> senderpub; int64_t amount; int32_t matures; std::string currency;
|
||||
if ( fHelp || (params.size() != 5 && params.size() != 4) )
|
||||
{
|
||||
// automatic flag -> lsb of matures
|
||||
// 1st marmarareceive 028076d42eb20efc10007fafb5ca66a2052523c0d2221e607adf958d1a332159f6 7.5 MARMARA 1440
|
||||
// after marmarareceive 039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775 7.5 MARMARA 1168 d72d87aa0d50436de695c93e2bf3d7273c63c92ef6307913aa01a6ee6a16548b
|
||||
throw runtime_error("marmarareceive senderpk amount currency matures batontxid\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");
|
||||
memset(&batontxid,0,sizeof(batontxid));
|
||||
senderpub = ParseHex(params[0].get_str().c_str());
|
||||
if (senderpub.size()!= 33)
|
||||
{
|
||||
ERR_RESULT("invalid sender pubkey");
|
||||
return result;
|
||||
}
|
||||
amount = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
currency = params[2].get_str();
|
||||
if ( params.size() == 5 )
|
||||
{
|
||||
matures = atol(params[3].get_str().c_str());
|
||||
batontxid = Parseuint256((char *)params[4].get_str().c_str());
|
||||
} else matures = atol(params[3].get_str().c_str()) + chainActive.LastTip()->GetHeight() + 1;
|
||||
return(MarmaraReceive(0,pubkey2pk(senderpub),amount,currency,matures,batontxid,true));
|
||||
}
|
||||
|
||||
UniValue marmara_issue(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 approvaltxid; std::vector<uint8_t> receiverpub; int64_t amount; int32_t matures; std::string currency;
|
||||
if ( fHelp || params.size() != 5 )
|
||||
{
|
||||
// marmaraissue 039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775 7.5 MARMARA 1168 32da4cb3e886ee42de90b4a15042d71169077306badf909099c5c5c692df3f27
|
||||
// marmaraissue 039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775 700 MARMARA 2629 11fe8bf1de80c2ef69124d08907f259aef7f41e3a632ca2d48ad072a8c8f3078 -> 335df3a5dd6b92a3d020c9465d4d76e0d8242126106b83756dcecbad9813fdf3
|
||||
|
||||
throw runtime_error("marmaraissue receiverpk amount currency matures approvaltxid\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");
|
||||
receiverpub = ParseHex(params[0].get_str().c_str());
|
||||
if (receiverpub.size()!= 33)
|
||||
{
|
||||
ERR_RESULT("invalid receiverpub pubkey");
|
||||
return result;
|
||||
}
|
||||
amount = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
currency = params[2].get_str();
|
||||
matures = atol(params[3].get_str().c_str());
|
||||
approvaltxid = Parseuint256((char *)params[4].get_str().c_str());
|
||||
return(MarmaraIssue(0,'I',pubkey2pk(receiverpub),amount,currency,matures,approvaltxid,zeroid));
|
||||
}
|
||||
|
||||
UniValue marmara_transfer(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 approvaltxid,batontxid; std::vector<uint8_t> receiverpub; int64_t amount; int32_t matures; std::string currency; std::vector<uint256> creditloop;
|
||||
if ( fHelp || params.size() != 5 )
|
||||
{
|
||||
// marmaratransfer 028076d42eb20efc10007fafb5ca66a2052523c0d2221e607adf958d1a332159f6 7.5 MARMARA 1168 1506c774e4b2804a6e25260920840f4cfca8d1fb400e69fe6b74b8e593dbedc5
|
||||
throw runtime_error("marmaratransfer receiverpk amount currency matures approvaltxid\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");
|
||||
receiverpub = ParseHex(params[0].get_str().c_str());
|
||||
if (receiverpub.size()!= 33)
|
||||
{
|
||||
ERR_RESULT("invalid receiverpub pubkey");
|
||||
return result;
|
||||
}
|
||||
amount = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
currency = params[2].get_str();
|
||||
matures = atol(params[3].get_str().c_str());
|
||||
approvaltxid = Parseuint256((char *)params[4].get_str().c_str());
|
||||
if ( MarmaraGetbatontxid(creditloop,batontxid,approvaltxid) < 0 )
|
||||
throw runtime_error("couldnt find batontxid\n");
|
||||
return(MarmaraIssue(0,'T',pubkey2pk(receiverpub),amount,currency,matures,approvaltxid,batontxid));
|
||||
}
|
||||
|
||||
UniValue marmara_info(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); CPubKey issuerpk; std::vector<uint8_t> issuerpub; int64_t minamount,maxamount; int32_t firstheight,lastheight; std::string currency;
|
||||
if ( fHelp || params.size() < 4 || params.size() > 6 )
|
||||
{
|
||||
throw runtime_error("marmarainfo firstheight lastheight minamount maxamount [currency issuerpk]\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");
|
||||
firstheight = atol(params[0].get_str().c_str());
|
||||
lastheight = atol(params[1].get_str().c_str());
|
||||
minamount = atof(params[2].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
maxamount = atof(params[3].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
if ( params.size() >= 5 )
|
||||
currency = params[4].get_str();
|
||||
if ( params.size() == 6 )
|
||||
{
|
||||
issuerpub = ParseHex(params[5].get_str().c_str());
|
||||
if ( issuerpub.size()!= 33 )
|
||||
{
|
||||
ERR_RESULT("invalid issuer pubkey");
|
||||
return result;
|
||||
}
|
||||
issuerpk = pubkey2pk(issuerpub);
|
||||
}
|
||||
result = MarmaraInfo(issuerpk,firstheight,lastheight,minamount,maxamount,currency);
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue marmara_creditloop(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 txid;
|
||||
if ( fHelp || params.size() != 1 )
|
||||
{
|
||||
// marmaracreditloop 010ff7f9256cefe3b5dee3d72c0eeae9fc6f34884e6f32ffe5b60916df54a9be
|
||||
throw runtime_error("marmaracreditloop 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");
|
||||
txid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
result = MarmaraCreditloop(txid);
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue marmara_settlement(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); uint256 batontxid;
|
||||
if ( fHelp || params.size() != 1 )
|
||||
{
|
||||
// marmarasettlement 010ff7f9256cefe3b5dee3d72c0eeae9fc6f34884e6f32ffe5b60916df54a9be
|
||||
// marmarasettlement ff3e259869196f3da9b5ea3f9e088a76c4fc063cf36ab586b652e121d441a603
|
||||
throw runtime_error("marmarasettlement batontxid\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");
|
||||
batontxid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
result = MarmaraSettlement(0,batontxid);
|
||||
return(result);
|
||||
}
|
||||
|
||||
UniValue marmara_lock(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); int64_t amount; int32_t height;
|
||||
if ( fHelp || params.size() > 2 || params.size() == 0 )
|
||||
{
|
||||
throw runtime_error("marmaralock amount unlockht\n");
|
||||
}
|
||||
amount = atof(params[0].get_str().c_str()) * COIN + 0.00000000499999;
|
||||
if ( params.size() == 2 )
|
||||
height = atol(params[1].get_str().c_str());
|
||||
else height = chainActive.LastTip()->GetHeight() + 1;
|
||||
return(MarmaraLock(0,amount,height));
|
||||
}
|
||||
|
||||
UniValue channelslist(const UniValue& params, bool fHelp)
|
||||
@@ -5556,8 +5731,10 @@ UniValue channelsinfo(const UniValue& params, bool fHelp)
|
||||
UniValue channelsopen(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); int32_t numpayments; int64_t payment; std::vector<unsigned char> destpub; struct CCcontract_info *cp,C; std::string hex;
|
||||
uint256 tokenid=zeroid;
|
||||
|
||||
cp = CCinit(&C,EVAL_CHANNELS);
|
||||
if ( fHelp || params.size() != 3 )
|
||||
if ( fHelp || params.size() < 3 || params.size() > 4)
|
||||
throw runtime_error("channelsopen destpubkey numpayments payment\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");
|
||||
@@ -5581,7 +5758,11 @@ UniValue channelsopen(const UniValue& params, bool fHelp)
|
||||
ERR_RESULT("invalid payment amount, must be greater than 0");
|
||||
return result;
|
||||
}
|
||||
hex = ChannelOpen(0,pubkey2pk(destpub),numpayments,payment);
|
||||
if (params.size()==4)
|
||||
{
|
||||
tokenid=Parseuint256((char *)params[3].get_str().c_str());
|
||||
}
|
||||
hex = ChannelOpen(0,pubkey2pk(destpub),numpayments,payment,tokenid);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
@@ -5594,7 +5775,7 @@ UniValue channelspayment(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,secret=zeroid; int32_t n; int64_t amount;
|
||||
cp = CCinit(&C,EVAL_CHANNELS);
|
||||
if ( fHelp || params.size() != 2 )
|
||||
if ( fHelp || params.size() < 2 || params.size() >3 )
|
||||
throw runtime_error("channelspayment opentxid amount [secret]\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");
|
||||
@@ -6663,7 +6844,7 @@ UniValue tokenlist(const UniValue& params, bool fHelp)
|
||||
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());
|
||||
return(TokenList());
|
||||
}
|
||||
|
||||
UniValue tokeninfo(const UniValue& params, bool fHelp)
|
||||
@@ -6674,7 +6855,7 @@ UniValue tokeninfo(const UniValue& params, bool fHelp)
|
||||
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));
|
||||
return(TokenInfo(tokenid));
|
||||
}
|
||||
|
||||
UniValue tokenorders(const UniValue& params, bool fHelp)
|
||||
@@ -6684,31 +6865,51 @@ UniValue tokenorders(const UniValue& params, bool fHelp)
|
||||
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));
|
||||
if (params.size() == 1) {
|
||||
tokenid = Parseuint256((char *)params[0].get_str().c_str());
|
||||
if (tokenid == zeroid)
|
||||
throw runtime_error("incorrect tokenid\n");
|
||||
}
|
||||
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);
|
||||
UniValue result(UniValue::VOBJ); uint256 tokenid; uint64_t balance; std::vector<unsigned char> pubkey; struct CCcontract_info *cp,C;
|
||||
CCerror.clear();
|
||||
|
||||
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");
|
||||
LOCK(cs_main);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
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));
|
||||
else
|
||||
pubkey = Mypubkey();
|
||||
|
||||
balance = GetTokenBalance(pubkey2pk(pubkey),tokenid);
|
||||
|
||||
if (CCerror.empty()) {
|
||||
char destaddr[64];
|
||||
|
||||
result.push_back(Pair("result", "success"));
|
||||
cp = CCinit(&C,EVAL_TOKENS);
|
||||
if (GetCCaddress(cp, destaddr, pubkey2pk(pubkey)) != 0)
|
||||
result.push_back(Pair("CCaddress", destaddr));
|
||||
|
||||
result.push_back(Pair("tokenid", params[0].get_str()));
|
||||
result.push_back(Pair("balance", (int64_t)balance));
|
||||
}
|
||||
else {
|
||||
ERR_RESULT(CCerror);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
@@ -6742,7 +6943,7 @@ UniValue tokencreate(const UniValue& params, bool fHelp)
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
hex = CreateAsset(0,supply,name,description);
|
||||
hex = CreateToken(0,supply,name,description);
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
result.push_back(Pair("result", "success"));
|
||||
@@ -6774,7 +6975,7 @@ UniValue tokentransfer(const UniValue& params, bool fHelp)
|
||||
ERR_RESULT("amount must be positive");
|
||||
return(result);
|
||||
}
|
||||
hex = AssetTransfer(0,tokenid,pubkey,amount);
|
||||
hex = TokenTransfer(0,tokenid,pubkey,amount);
|
||||
if (amount > 0) {
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
@@ -6811,7 +7012,11 @@ UniValue tokenconvert(const UniValue& params, bool fHelp)
|
||||
ERR_RESULT("amount must be positive");
|
||||
return(result);
|
||||
}
|
||||
hex = AssetConvert(0,tokenid,pubkey,amount,evalcode);
|
||||
|
||||
ERR_RESULT("deprecated");
|
||||
return(result);
|
||||
|
||||
/* hex = AssetConvert(0,tokenid,pubkey,amount,evalcode);
|
||||
if (amount > 0) {
|
||||
if ( hex.size() > 0 )
|
||||
{
|
||||
@@ -6821,7 +7026,7 @@ UniValue tokenconvert(const UniValue& params, bool fHelp)
|
||||
} else {
|
||||
ERR_RESULT("amount must be positive");
|
||||
}
|
||||
return(result);
|
||||
return(result); */
|
||||
}
|
||||
|
||||
UniValue tokenbid(const UniValue& params, bool fHelp)
|
||||
@@ -7041,7 +7246,7 @@ UniValue tokenfillask(const UniValue& params, bool fHelp)
|
||||
result.push_back(Pair("result", "success"));
|
||||
result.push_back(Pair("hex", hex));
|
||||
} else {
|
||||
ERR_RESULT("couldnt fill bid");
|
||||
ERR_RESULT("couldnt fill ask");
|
||||
}
|
||||
} else {
|
||||
ERR_RESULT("fillunits must be positive");
|
||||
@@ -7118,6 +7323,139 @@ UniValue getbalance64(const UniValue& params, bool fHelp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// heir contract functions for coins and tokens
|
||||
UniValue heirfund(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result(UniValue::VOBJ);
|
||||
uint256 tokenid = zeroid;
|
||||
uint64_t txfee;
|
||||
int64_t amount;
|
||||
int64_t inactivitytime;
|
||||
std::string hex;
|
||||
std::vector<unsigned char> pubkey;
|
||||
std::string name;
|
||||
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (fHelp || params.size() != 5 && params.size() != 6)
|
||||
throw runtime_error("heirfundtokens fee funds heirname heirpubkey inactivitytime [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");
|
||||
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
txfee = atoll((char*)params[0].get_str().c_str());
|
||||
amount = atoll((char*)params[1].get_str().c_str());
|
||||
name = params[2].get_str();
|
||||
pubkey = ParseHex(params[3].get_str().c_str());
|
||||
if( !pubkey2pk(pubkey).IsValid() )
|
||||
throw runtime_error("incorrect pubkey\n");
|
||||
|
||||
inactivitytime = atof((char*)params[4].get_str().c_str());
|
||||
if (params.size() == 6) {
|
||||
tokenid = Parseuint256((char*)params[5].get_str().c_str());
|
||||
if(tokenid == zeroid)
|
||||
throw runtime_error("incorrect tokenid\n");
|
||||
}
|
||||
|
||||
if( tokenid == zeroid )
|
||||
result = HeirFundCoinCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, zeroid);
|
||||
else
|
||||
result = HeirFundTokenCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, tokenid);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue heiradd(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result;
|
||||
uint256 fundingtxid;
|
||||
uint64_t txfee;
|
||||
int64_t amount;
|
||||
int64_t inactivitytime;
|
||||
std::string hex;
|
||||
std::vector<unsigned char> pubkey;
|
||||
std::string name;
|
||||
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (fHelp || params.size() != 3)
|
||||
throw runtime_error("heiraddtokens fee funds 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");
|
||||
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
txfee = atoll((char*)params[0].get_str().c_str());
|
||||
amount = atoll((char*)params[1].get_str().c_str());
|
||||
fundingtxid = Parseuint256((char*)params[2].get_str().c_str());
|
||||
|
||||
result = HeirAddCaller(fundingtxid, txfee, amount);
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue heirclaim(const UniValue& params, bool fHelp)
|
||||
{
|
||||
UniValue result; // result(UniValue::VOBJ);
|
||||
uint256 fundingtxid;
|
||||
int64_t txfee;
|
||||
int64_t amount;
|
||||
int64_t inactivitytime;
|
||||
std::string hex;
|
||||
std::vector<unsigned char> pubkey;
|
||||
std::string name;
|
||||
|
||||
// do we need this?
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (fHelp || params.size() != 3)
|
||||
throw runtime_error("heirclaimtokens fee funds 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");
|
||||
|
||||
const CKeyStore& keystore = *pwalletMain;
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
txfee = atoll((char*)params[0].get_str().c_str());
|
||||
amount = atoll((char*)params[1].get_str().c_str());
|
||||
fundingtxid = Parseuint256((char*)params[2].get_str().c_str());
|
||||
|
||||
result = HeirClaimCaller(fundingtxid, txfee, amount);
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue heirinfo(const UniValue& params, bool fHelp)
|
||||
{
|
||||
uint256 fundingtxid;
|
||||
if (fHelp || params.size() != 1) // or 0?
|
||||
throw runtime_error("heirinfo 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 (HeirInfo(fundingtxid));
|
||||
}
|
||||
|
||||
UniValue heirlist(const UniValue& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() != 0) // or 0?
|
||||
throw runtime_error("heirlist\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 (HeirList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
|
||||
extern UniValue importprivkey(const UniValue& params, bool fHelp);
|
||||
extern UniValue importaddress(const UniValue& params, bool fHelp);
|
||||
|
||||
@@ -1180,7 +1180,7 @@ bool DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t n
|
||||
assert((nWitnessCacheSize - 1) >= nd->witnesses.size());
|
||||
}
|
||||
}
|
||||
assert(KOMODO_REWIND != 0 || nWitnessCacheSize > 0);
|
||||
assert(KOMODO_REWIND != 0 || nWitnessCacheSize > 0 || WITNESS_CACHE_SIZE != _COINBASE_MATURITY+10);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
using namespace std;
|
||||
|
||||
static uint64_t nAccountingEntryNumber = 0;
|
||||
static list<uint256> deadTxns;
|
||||
|
||||
//
|
||||
// CWalletDB
|
||||
@@ -484,8 +485,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
CValidationState state;
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
if (!(CheckTransaction(0,wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid()))
|
||||
{
|
||||
fprintf(stderr, "Removing corrupt tx from wallet.%s\n", hash.ToString().c_str());
|
||||
deadTxns.push_back(hash);
|
||||
return false;
|
||||
|
||||
}
|
||||
// Undo serialize changes in 31600
|
||||
if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
|
||||
{
|
||||
@@ -933,9 +937,6 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||
{
|
||||
// Leave other errors alone, if we try to fix them we might make things worse.
|
||||
fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
|
||||
if (strType == "tx")
|
||||
// Rescan if there is a bad transaction record:
|
||||
SoftSetBoolArg("-rescan", true);
|
||||
}
|
||||
}
|
||||
if (!strErr.empty())
|
||||
@@ -950,6 +951,24 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||
result = DB_CORRUPT;
|
||||
}
|
||||
|
||||
if (!deadTxns.empty())
|
||||
{
|
||||
int32_t reAdded = 0;
|
||||
BOOST_FOREACH (uint256& hash, deadTxns) {
|
||||
if (!EraseTx(hash))
|
||||
fprintf(stderr, "could not delete tx.%s\n",hash.ToString().c_str());
|
||||
uint256 blockhash; CTransaction tx;
|
||||
if (GetTransaction(hash,tx,blockhash,true))
|
||||
{
|
||||
CWalletTx wtx(pwallet,tx);
|
||||
pwallet->AddToWallet(wtx, true, NULL);
|
||||
reAdded++;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Cleared %lu corrupted transactions from wallet. Readded %i known transactions.\n",deadTxns.size(),reAdded);
|
||||
deadTxns.clear();
|
||||
}
|
||||
|
||||
if (fNoncriticalErrors && result == DB_LOAD_OK)
|
||||
result = DB_NONCRITICAL_ERROR;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user