Asset contract modified to support the Tokens contract

This commit is contained in:
dimxy
2019-01-07 23:24:13 +05:00
parent be71d108b2
commit 675787d676
11 changed files with 303 additions and 135 deletions

View File

@@ -239,25 +239,28 @@ CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,st
}
*/
CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey)
CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector<CPubKey> voutPubkeys, std::vector<uint8_t> origpubkey)
{
CScript opret;
uint8_t evalcode = EVAL_ASSETS;
uint8_t funcId = (uint8_t)'t';
uint8_t ccType = 0;
if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2)
ccType = voutPubkeys.size();
tokenid = revuint256(tokenid);
switch ( assetFuncId )
{
//case 't': this cannot be here
case 'x': case 'o':
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << assetFuncId);
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << ccType; if(ccType >= 1) ss << voutPubkeys[0]; if(ccType == 2) ss << voutPubkeys[1]; ss << assetFuncId);
break;
case 's': case 'b': case 'S': case 'B':
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << assetFuncId << price << origpubkey);
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << ccType; if(ccType >= 1) ss << voutPubkeys[0]; if(ccType == 2) ss << voutPubkeys[1]; ss << assetFuncId << price << origpubkey);
break;
case 'E': case 'e':
assetid2 = revuint256(assetid2);
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << assetFuncId << assetid2 << price << origpubkey);
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << ccType; if(ccType >= 1) ss << voutPubkeys[0]; if(ccType == 2) ss << voutPubkeys[1]; ss << assetFuncId << assetid2 << price << origpubkey);
break;
default:
fprintf(stderr,"EncodeAssetOpRet: illegal funcid.%02x\n", assetFuncId);
@@ -283,33 +286,38 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &o
uint8_t DecodeAssetOpRet(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 *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyFuncId;
std::vector<uint8_t> vopretExtra;
uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyAssetFuncId;
uint256 dummyTokenid;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if (script == 0) {
std::cerr << "DecodeAssetOpRet() script is empty" << std::endl;
return (uint8_t)0;
}
std::vector<CPubKey> voutPubkeysDummy;
tokenid = zeroid;
assetid2 = zeroid;
price = 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());
// First - decode token opret:
funcId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra);
if (!result && isEof) { // NOTE: 'result==false' means 'parse error' OR 'not eof state'. Consequently, 'result==false' but 'isEof==true' means just 'parse error'
std::cerr << "DecodeAssetOpRet() incorrect opret or no asset's payload" << std::endl;
/*GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if (script == 0) {
std::cerr << "DecodeAssetOpRet() script is empty" << std::endl;
return (uint8_t)0;
}*/
//bool isEof = true; // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set!
//bool result = E_UNMARSHAL(vopret, ss >> evalCodeInOpret; ss >> funcId; ss >> tokenid; ss >> assetFuncId; isEof = ss.eof());
if (funcId == 0 || vopretExtra.size() == 0) {
std::cerr << "DecodeAssetOpRet() incorrect opret or no asset's payload" << " funcId=" << (int)funcId << " vopretExtra.size()=" << vopretExtra.size() << std::endl;
return (uint8_t)0;
}
tokenid = revuint256(tokenid);
////tokenid = revuint256(tokenid); already done in DecodeToken!
std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl;
assetFuncId = vopretExtra.begin()[0];
//std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl;
if(evalCodeInOpret == EVAL_ASSETS)
{
@@ -328,20 +336,20 @@ uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret,
break; */
case 'x': case 'o':
if (isEof) // no data after 'assetFuncId' allowed
if (vopretExtra.size() == 1) // no data after 'assetFuncId' allowed
{
return(assetFuncId);
}
break;
case 's': case 'b': case 'S': case 'B':
if (E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> dummyTokenid; ss >> dummyFuncId; ss >> price; ss >> origpubkey) != 0)
if (E_UNMARSHAL(vopretExtra, ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0)
{
//fprintf(stderr,"got price %llu\n",(long long)price);
return(assetFuncId);
}
break;
case 'E': case 'e':
if ( E_UNMARSHAL(vopret,ss >> dummyEvalCode; ss >> dummyFuncId; ss >> dummyTokenid; ss >> dummyFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 )
if ( E_UNMARSHAL(vopretExtra, ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 )
{
//fprintf(stderr,"got price %llu\n",(long long)price);
assetid2 = revuint256(assetid2);
@@ -349,34 +357,37 @@ uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret,
}
break;
default:
fprintf(stderr,"DecodeAssetOpRet: illegal funcid.%02x\n", funcId);
funcId = 0;
fprintf(stderr,"DecodeAssetOpRet: illegal assetFuncId.%02x\n", assetFuncId);
//funcId = 0;
break;
}
}
return(funcId);
return (uint8_t)0;
}
bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx)
{
uint256 assetid,assetid2;
uint8_t evalCode;
if ( tx.vout.size() > 0 && DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey) != 0 )
if ( tx.vout.size() > 0 && DecodeAssetOpRet(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)
{
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, evalCode,assetid,assetid2,price,origpubkey)) == 0 )
return(false);
if ( GetCCaddress(cp,CCaddr,pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr,CScript() << origpubkey << OP_CHECKSIG) != 0 )
if ( GetCCaddress(cp, CCaddr, pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG) != 0 )
return(true);
else return(false);
else
return(false);
}
@@ -398,7 +409,7 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch
}
else if ( Getscriptaddress(destaddr,vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || strcmp(destaddr,(char *)cp->unspendableCCaddr) != 0 )
{
fprintf(stderr,"%s vs %s\n",destaddr,(char *)cp->unspendableCCaddr);
fprintf(stderr,"AssetValidateCCvin cc addr %s is not evalcode 0x%02x unspendable %s\n", destaddr, (int)cp->evalcode, (char *)cp->unspendableCCaddr);
return eval->Invalid("invalid vin AssetsCCaddr");
}
//else if ( vinTx.vout[0].nValue < 10000 )
@@ -415,6 +426,8 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr
{
CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid, evalCode;
CCaddr[0] = origaddr[0] = 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 )
@@ -441,7 +454,8 @@ int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpp
return(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);
}
@@ -475,9 +489,8 @@ bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &pr
return(true);
}
} */
// TODO: hope this was unneeded!!! (dimxy)
else if ((funcid == 'b' || funcid == 'B') && v == 0) // critical! 'b'/'B' vout0 is NOT asset
return(false);
//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)
@@ -542,8 +555,8 @@ bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_
cpTokens = CCinit(&C, EVAL_TOKENS);
for (int32_t i = 0; i<numvins; i++)
{ // check for additional contracts which may send tokens to the Assets contract
if ((*cpAssets->ismyvin)(tx.vin[i].scriptSig) || (*cpTokens->ismyvin)(tx.vin[i].scriptSig)) // || IsVinAllowed(tx.vin[i].scriptSig) != 0)
{ // 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
@@ -555,7 +568,10 @@ bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_
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);
//assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, vinTx, tx.vin[i].prevout.n, assetid);
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> vinPubkeysEmpty;
assetoshis = IsTokensvout(false, false, cpTokens, NULL, vopretExtra, vinTx, tx.vin[i].prevout.n, assetid, vinPubkeysEmpty);
if (assetoshis != 0)
{
std::cerr << "AssetExactAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl;
@@ -585,9 +601,11 @@ bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_
}
}
//std::cerr << "AssetExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
std::cerr << "AssetExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
/* if (inputs != outputs) {
/* we do not verify inputs == outputs here,
it's done in Tokens:
if (inputs != outputs) {
if (tx.GetHash() != assetid) {
std::cerr << "AssetExactAmounts() unequal inputs=" << inputs << " vs outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
return (!eval) ? false : eval->Invalid("assets cc inputs != cc outputs");

View File

@@ -145,11 +145,11 @@ UniValue AssetOrders(uint256 refassetid)
char numstr[32], funcidstr[16], origaddr[64], assetidstr[65];
txid = it->first.txhash;
//std::cerr << "addOrders txid" << txid.GetHex() << std::endl;
//std::cerr << "addOrders() txid=" << txid.GetHex() << std::endl;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
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 : ' ') << std::endl;
//std::cerr << "addOrders() vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl;
if (vintx.vout.size() > 0 && (funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0)
{
if (refassetid != zero && assetid != refassetid)
@@ -163,6 +163,8 @@ UniValue AssetOrders(uint256 refassetid)
//fprintf(stderr," refassetid\n");
return;
}
//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;
@@ -213,7 +215,7 @@ 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);
}
}
};
@@ -378,8 +380,12 @@ std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, in
return ("");
}
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, GetUnspendable(cpAssets,0)));
return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', assetid, zeroid, pricetotal, Mypubkey())));
CPubKey unspendablePubkey = GetUnspendable(cpAssets, 0);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, unspendablePubkey));
std::vector<CPubKey> voutTokenPubkeys; // should be empty - no token vouts
return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey())));
}
CCerror = strprintf("no coins found to make buy offer");
return("");
@@ -420,13 +426,17 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
return ("");
}
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,askamount, GetUnspendable(cpTokens,0)));
CPubKey unspendablePubkey = GetUnspendable(cpTokens, 0);
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, unspendablePubkey));
if (inputs > askamount)
CCchange = (inputs - askamount);
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk));
opret = EncodeAssetOpRet('s',assetid, zeroid, pricetotal, Mypubkey());
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(unspendablePubkey);
opret = EncodeAssetOpRet('s',assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey());
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,opret));
}
else {
@@ -474,18 +484,22 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
return ("");
}
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, askamount, GetUnspendable(cp, 0)));
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());
std::vector<CPubKey> voutTokenPubkeys; // should be empty - no token vouts
if (assetid2 == zeroid) {
opret = EncodeAssetOpRet('s', assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey());
}
else {
opret = EncodeAssetOpRet('e', assetid, assetid2, pricetotal, voutTokenPubkeys, Mypubkey());
}
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
}
@@ -524,9 +538,12 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
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
mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('o', assetid, zeroid, 0, Mypubkey())));
std::vector<CPubKey> voutTokenPubkeys; // should be empty, no tokens vout
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('o', assetid, zeroid, 0, voutTokenPubkeys, Mypubkey())));
}
}
return("");
@@ -554,7 +571,11 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
askamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(asktxid, 0, CScript()));
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk));
return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, Mypubkey())));
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(mypk);
return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, voutTokenPubkeys, Mypubkey())));
}
}
return("");
@@ -595,7 +616,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
bidamount = vintx.vout[bidvout].nValue;
SetAssetOrigpubkey(origpubkey, origprice, vintx);
mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript()));
mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript())); // Coins on Assets unspendable
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, fillamount, 60)) > 0)
{
@@ -610,25 +631,30 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
if (inputs > fillamount)
CCchange = (inputs - fillamount);
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, bidamount - paid_amount, GetUnspendable(cpTokens, NULL))); // tokens
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, fillamount, pubkey2pk(origpubkey))); // coins on assets
CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL);
uint8_t unspendableAssetsPrivkey[32];
CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // 0 coins remainder
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // 1 coins to normal
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // 2 tokens paid
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins on assets
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // 3 change in tokens
fprintf(stderr,"remaining %llu -> origpubkey\n", (long long)remaining_required);
// add additional unspendable addr from Assets:
char unspendableAssetsAddr[64];
uint8_t unspendableAssetsPrivkey[32];
CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey);
GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk);
// add additional unspendable addr from Assets:
CCaddr2set(cpTokens, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, origpubkey)));
} else return("dont have any assets to fill bid\n");
// token vout verification pubkeys:
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(unspendableTokensPk);
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, voutTokenPubkeys, origpubkey)));
} else return("dont have any assets to fill bid");
}
}
return("no normal coins left");
@@ -683,7 +709,7 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt
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(cpTokens, mtx, mypk, assetid2, paid_nValue, 60);
inputs = AddAssetInputs(cpTokens, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet
else
{
inputs = AddNormalinputs(mtx, mypk, paid_nValue, 60);
@@ -698,25 +724,36 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt
}
if (assetid2 != zeroid)
SetSwapFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue);
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(cpAssets, NULL))); // coins in Assets cc addr
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); // tokens
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, orig_assetoshis - received_assetoshis, GetUnspendable(cpTokens, NULL))); // 0 tokens cc addr - ask remainder
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //1 tokens to self
if (assetid2 != zeroid)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); // tokens... (swap is not implemented yet)
else
mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); // coins normal
if (assetid2 != zeroid) {
std::cerr << "FillSell() WARNING: asset swap not implemented yet! (paid_nValue)" << std::endl;
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //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)); //2 coins normal to whom who asked token
}
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins in Assets cc addr
// not implemented
if (CCchange != 0) {
std::cerr << "FillSell() WARNING: asset swap not implemented yet! (CCchange)" << std::endl;
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //3 coins in Assets cc addr
}
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid, assetid2, remaining_nValue, origpubkey)));
// vout verification pubkeys:
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(mypk);
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid, assetid2, remaining_nValue, voutTokenPubkeys, origpubkey)));
} else {
CCerror = strprintf("filltx not enough utxos");
fprintf(stderr,"%s\n", CCerror.c_str());

View File

@@ -151,13 +151,15 @@ uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk);
//int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs);
int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector<CPubKey> vinPubkeys);
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector<CPubKey> voutPubkeys, 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 &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
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<uint8_t> &vopretExtra);
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopretExtra);
//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector<uint8_t> &origpubkey);
uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data);

View File

@@ -76,11 +76,12 @@ uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t>
return (uint8_t)0;
}
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector<uint8_t> &vopretExtra)
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, e, dummyFuncId;
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();
@@ -88,28 +89,45 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256
if (script != 0 /*enable all evals: && script[0] == EVAL_TOKENS*/)
{
// 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];
funcid = script[1];
//fprintf(stderr,"decode.[%c]\n",funcid);
switch ( funcid )
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':
if (E_UNMARSHAL(vopret, ss >> e; ss >> dummyFuncId; ss >> tokenid; isEof = ss.eof(); vopretExtra = std::vector<uint8_t>(ss.begin(), ss.end())) || !isEof)
// 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 << 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);
return(funcId);
}
std::cerr << "DecodeTokenOpRet() isEof=" << isEof << std::endl;
fprintf(stderr, "DecodeTokenOpRet() bad opret format\n"); // this may be just check, no error logging
std::cerr << "DecodeTokenOpRet() warning: bad opret format, isEof=" << isEof << " ccType=" << ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl;
return (uint8_t)0;
default:
fprintf(stderr, "DecodeTokenOpRet() illegal funcid.%02x\n", funcid);
std::cerr << "DecodeTokenOpRet() illegal funcid=" << (int)funcId << std::endl;
return (uint8_t)0;
}
}
@@ -124,16 +142,18 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &
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> origpubkey, tmporigpubkey, ignorepubkey;
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;
numvins = tx.vin.size();
numvouts = tx.vout.size();
outputs = inputs = 0;
preventCCvins = preventCCvouts = -1;
if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, origpubkey)) == 0)
if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, vopretExtra)) == 0)
return eval->Invalid("TokenValidate: invalid opreturn payload");
fprintf(stderr, "TokensValidate (%c)\n", funcid);
@@ -206,7 +226,7 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &
thread_local uint32_t tokenValIndentSize = 0;
// validates opret for token tx:
bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector<uint8_t> &vopretExtra) {
bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopretExtra) {
uint256 tokenidOpret, tokenidOpret2;
uint8_t funcid, evalCode;
@@ -216,7 +236,7 @@ bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector
int32_t n = tx.vout.size();
if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, tokenidOpret, vopretExtra)) == 0)
if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, tokenidOpret, voutPubkeys, vopretExtra)) == 0)
{
std::cerr << indentStr << "ValidateTokenOpret() DecodeOpret returned null for n-1=" << n - 1 << " txid=" << tx.GetHash().GetHex() << std::endl;
return(false);
@@ -241,18 +261,20 @@ bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector
}
// Checks if the vout is a really Tokens 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 IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, std::vector<uint8_t> &vopretExtra, const CTransaction& tx, int32_t v, uint256 reftokenid)
int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector<uint8_t> &vopretExtra, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector<CPubKey> vinPubkeys)
{
// 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() != 0) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here
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:
@@ -261,7 +283,7 @@ int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval,
return(0);
}
if (compareTotals) {
if (goDeeper) {
//std::cerr << indentStr << "IsTokensvout() maxTokenExactAmountDepth=" << maxTokenExactAmountDepth << std::endl;
//validate all tx
int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0;
@@ -282,11 +304,41 @@ int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval,
}
// moved opret checking to this new reusable func (dimxy):
const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, vopretExtra);
std::vector<CPubKey> voutPubkeys;
const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra);
//std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
if (valOpret) {
//std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned true, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
return tx.vout[v].nValue;
//std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned true" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
if (checkPubkeys) {
// verify that the vout is within EVAL_TOKENS:
if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) {
CTxOut testVout;
if (voutPubkeys.size() == 1)
testVout = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]);
else // voutPubkeys.size() == 2
testVout = MakeCC1of2vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]);
if (tx.vout[v].scriptPubKey == testVout.scriptPubKey) {
std::cerr << indentStr << "IsTokensvout() vout is EVAL_TOKENS, 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 change?
for(std::vector<CPubKey>::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) {
CTxOut testVout = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it);
if (tx.vout[v].scriptPubKey == testVout.scriptPubKey) {
std::cerr << indentStr << "IsTokensvout() vout is EVAL_TOKENS change, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
return tx.vout[v].nValue;
}
}
}
else {
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());
@@ -296,9 +348,12 @@ int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval,
}
// compares cc inputs vs cc outputs (to prevent feeding vouts from normal inputs)
bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid)
bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid)
{
CTransaction vinTx; uint256 hashBlock, id, id2; int32_t flag; int64_t tokenoshis; std::vector<uint8_t> tmporigpubkey; int64_t tmpprice;
std::vector<CPubKey> vinPubkeys, vinPubkeysEmpty;
CPubKey pubkey;
int32_t numvins = tx.vin.size();
int32_t numvouts = tx.vout.size();
inputs = outputs = 0;
@@ -310,6 +365,33 @@ bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, in
{ // 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*/)
{
// extract my vins pubkeys:
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);
}
//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)))
@@ -322,7 +404,7 @@ bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, in
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(compareTotals, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid);
tokenoshis = IsTokensvout(goDeeper, false/*<--do not have pubkeys*/, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid, vinPubkeysEmpty);
tokenValIndentSize--;
if (tokenoshis != 0)
{
@@ -339,7 +421,7 @@ bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, in
tokenValIndentSize++;
// Note: we pass in here 'false' because we don't need to call TokenExactAmounts() recursively from IsTokenvout
// indeed, in this case we'll be checking this tx again
tokenoshis = IsTokensvout(false, cpTokens, eval, tmporigpubkey, tx, i, tokenid);
tokenoshis = IsTokensvout(false, true /*<--exclude non-tokens vouts*/, cpTokens, eval, tmporigpubkey, tx, i, tokenid, vinPubkeys);
tokenValIndentSize--;
if (tokenoshis != 0)
@@ -393,7 +475,9 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C
if (strcmp(destaddr, coinaddr) != 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);
if ((nValue = IsTokensvout(true, cp, NULL, vopretExtra, vintx, vout, tokenid)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0)
std::vector<CPubKey> vinPubkeysEmpty;
if ((nValue = IsTokensvout(true, false, cp, NULL, vopretExtra, vintx, vout, tokenid, vinPubkeysEmpty)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0)
{
if (total != 0 && maxinputs != 0)
mtx.vin.push_back(CTxIn(txid, vout, CScript()));

View File

@@ -27,8 +27,8 @@
// CCcustom
bool TokensValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid);
int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid);
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);

View File

@@ -333,7 +333,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 ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, vopretExtra) != 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;
}

View File

@@ -307,17 +307,17 @@ 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 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 addr %s vs %s\n", cmpaddr!=0?cmpaddr:"", destaddr!=0?destaddr:"");
return(false);
}
else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || (

View File

@@ -140,12 +140,16 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
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],CCaddr[64];
char destaddr[64], origaddr[64], assetsCCaddr[64], tokensCCaddr[64];
// we need this for validating tokens' vins/vous:
struct CCcontract_info *cpTokens, tokensC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
//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;
@@ -154,6 +158,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
if((funcid = DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 )
return eval->Invalid("AssetValidate: invalid opreturn payload");
// find token user cc addr
GetCCaddress(cpTokens, tokensCCaddr, pubkey2pk(origpubkey));
fprintf(stderr,"AssetValidate (%c)\n",funcid);
if( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid, createTx, hashBlock) == 0 )
@@ -162,8 +169,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("cant find asset2 create txid");
else if( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("illegal asset vin0");
else if( numvouts < 1 )
return eval->Invalid("no vouts");
else if( 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' )
@@ -223,7 +230,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey]
//vout.1: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['o']
if( (nValue= AssetValidateBuyvin(cpAssets, 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 )
return eval->Invalid("invalid refund for cancelbuy");
@@ -243,7 +250,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//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(cpAssets, 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 )
return eval->Invalid("not enough vouts for fillbuy");
@@ -255,12 +263,12 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("locked value doesnt match vout0+1 fillbuy");
else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if( ConstrainVout(tx.vout[2], 1, CCaddr, 0) == 0 )
if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, 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 )
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, tokensCCaddr, 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 )
return eval->Invalid("vout1 is CC for fillbuy");
@@ -268,7 +276,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("mismatched remainder for fillbuy");
else if( remaining_price != 0 )
{
if( ConstrainVout(tx.vout[0], 1, cpAssets->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");
}
}
@@ -287,16 +295,16 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
preventCCvouts = 1;
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 ) // is cc change present?
{
preventCCvouts++;
if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 )
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer");
if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // check also vout[0]
return eval->Invalid("mismatched vout0 TokensCCaddr 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 *)cpAssets->unspendableCCaddr, inputs) == 0 )
return eval->Invalid("mismatched vout0 AssetsCCaddr 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;
@@ -306,9 +314,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
//vout.1: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
if( (assetoshis= AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 )
if( (assetoshis= AssetValidateSellvin(cpTokens, eval, tmpprice, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 )
return(false);
else if( ConstrainVout(tx.vout[0], 1, CCaddr, assetoshis) == 0 )
else if( ConstrainVout(tx.vout[0], 1, tokensCCaddr, assetoshis) == 0 )
return eval->Invalid("invalid vout for cancel");
preventCCvins = 2;
preventCCvouts = 1;
@@ -323,7 +331,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//'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(cpTokens, eval, totalunits, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 )
if( (assetoshis = AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 )
return(false);
else if( numvouts < 3 )
return eval->Invalid("not enough vouts for fillask");
@@ -341,8 +349,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("normal vout1 for fillask");
else if( remaining_price != 0 )
{
if ( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr,0) == 0 )
return eval->Invalid("mismatched vout0 AssetsCCaddr for fill");
if ( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr,0) == 0 )
return eval->Invalid("mismatched vout0 TokenCCaddr for fill");
}
}
fprintf(stderr,"fill validated\n");
@@ -363,7 +371,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//if ( AssetExactAmounts(false, cp,inputs,outputs,eval,tx,assetid2) == false )
// eval->Invalid("asset2 inputs != outputs");
if( (assetoshis= AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 )
if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 )
return(false);
else if( numvouts < 3 )
return eval->Invalid("not enough vouts for fillex");
@@ -375,7 +383,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("locked value doesnt match vout0+1 fillex");
else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if( ConstrainVout(tx.vout[2], 1, CCaddr, 0) == 0 )
if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, 0) == 0 )
return eval->Invalid("vout2 doesnt go to origpubkey fillex");
else if( inputs != tx.vout[2].nValue + tx.vout[3].nValue )
{
@@ -383,7 +391,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("asset inputs doesnt match vout2+3 fillex");
}
}
else if( ConstrainVout(tx.vout[2], 1, CCaddr, inputs) == 0 )
else if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, inputs) == 0 )
return eval->Invalid("vout2 doesnt match inputs fillex");
else if( ConstrainVout(tx.vout[1], 0, 0, 0) == 0 )
return eval->Invalid("vout1 is CC for fillex");
@@ -394,7 +402,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("normal vout1 for fillex");
else if( remaining_price != 0 )
{
if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->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");
}
}

View File

@@ -326,7 +326,9 @@ 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,EncodeAssetOpRet('t',bettoken,zeroid,0, voutTokenPubkeysEmpty, Mypubkey())));
}
else
{

View File

@@ -407,6 +407,20 @@ bool CScript::MayAcceptCryptoCondition() const
cc_free(cond);
return out;
}
struct CC *CScript::GetCryptoCondition() const
{
// Get the type mask of the condition
const_iterator pc = this->begin();
vector<unsigned char> data;
opcodetype opcode;
if (!this->GetOp(pc, opcode, data)) return NULL;
if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) return NULL;
struct CC *cond = cc_readConditionBinary(data.data(), data.size());
if (!cond) return NULL;
//bool out = IsSupportedCryptoCondition(cond);
//cc_free(cond);
return cond;
}
bool CScript::IsCoinImport() const
{

View File

@@ -601,6 +601,8 @@ public:
bool IsPayToCryptoCondition() const;
bool IsCoinImport() const;
bool MayAcceptCryptoCondition() const;
struct CC *GetCryptoCondition() const;
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
bool IsPushOnly() const;