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; CScript opret;
uint8_t evalcode = EVAL_ASSETS; uint8_t evalcode = EVAL_ASSETS;
uint8_t funcId = (uint8_t)'t'; uint8_t funcId = (uint8_t)'t';
uint8_t ccType = 0;
if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2)
ccType = voutPubkeys.size();
tokenid = revuint256(tokenid); tokenid = revuint256(tokenid);
switch ( assetFuncId ) switch ( assetFuncId )
{ {
//case 't': this cannot be here //case 't': this cannot be here
case 'x': case 'o': 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; break;
case 's': case 'b': case 'S': case 'B': 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; break;
case 'E': case 'e': case 'E': case 'e':
assetid2 = revuint256(assetid2); 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; break;
default: default:
fprintf(stderr,"EncodeAssetOpRet: illegal funcid.%02x\n", assetFuncId); 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) 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; std::vector<uint8_t> vopretExtra;
uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyFuncId; uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyAssetFuncId;
uint256 dummyTokenid; uint256 dummyTokenid;
std::vector<CPubKey> voutPubkeysDummy;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if (script == 0) {
std::cerr << "DecodeAssetOpRet() script is empty" << std::endl;
return (uint8_t)0;
}
tokenid = zeroid; tokenid = zeroid;
assetid2 = zeroid; assetid2 = zeroid;
price = 0; 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! // First - decode token opret:
bool result = E_UNMARSHAL(vopret, ss >> evalCodeInOpret; ss >> funcId; ss >> tokenid; ss >> assetFuncId; isEof = ss.eof()); 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; 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) if(evalCodeInOpret == EVAL_ASSETS)
{ {
@@ -328,20 +336,20 @@ uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret,
break; */ break; */
case 'x': case 'o': case 'x': case 'o':
if (isEof) // no data after 'assetFuncId' allowed if (vopretExtra.size() == 1) // no data after 'assetFuncId' allowed
{ {
return(assetFuncId); return(assetFuncId);
} }
break; break;
case 's': case 'b': case 'S': case 'B': 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); //fprintf(stderr,"got price %llu\n",(long long)price);
return(assetFuncId); return(assetFuncId);
} }
break; break;
case 'E': case 'e': 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); //fprintf(stderr,"got price %llu\n",(long long)price);
assetid2 = revuint256(assetid2); assetid2 = revuint256(assetid2);
@@ -349,34 +357,37 @@ uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret,
} }
break; break;
default: default:
fprintf(stderr,"DecodeAssetOpRet: illegal funcid.%02x\n", funcId); fprintf(stderr,"DecodeAssetOpRet: illegal assetFuncId.%02x\n", assetFuncId);
funcId = 0; //funcId = 0;
break; break;
} }
} }
return(funcId); return (uint8_t)0;
} }
bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx) bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx)
{ {
uint256 assetid,assetid2; uint256 assetid,assetid2;
uint8_t evalCode; 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); return(true);
else return(false); else
return(false);
} }
bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,const CTransaction& tx) 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; uint8_t evalCode;
n = tx.vout.size(); n = tx.vout.size();
if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey)) == 0 ) if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey)) == 0 )
return(false); 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); 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 ) 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"); return eval->Invalid("invalid vin AssetsCCaddr");
} }
//else if ( vinTx.vout[0].nValue < 10000 ) //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; CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid, evalCode;
CCaddr[0] = origaddr[0] = 0; CCaddr[0] = origaddr[0] = 0;
// validate locked coins on Assets vin[1]
if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 ) if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 )
return(0); return(0);
else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 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); return(0);
if ( (assetoshis= IsAssetvout(cp, 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"); 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); return(true);
} }
} */ } */
// TODO: hope this was unneeded!!! (dimxy) //else if ((funcid == 'b' || funcid == 'B') && v == 0) // critical! 'b'/'B' vout0 is NOT asset
else if ((funcid == 'b' || funcid == 'B') && v == 0) // critical! 'b'/'B' vout0 is NOT asset // return(false);
return(false);
else if (funcid != 'E') else if (funcid != 'E')
{ {
if (assetid != zeroid && assetidOpret == assetid) if (assetid != zeroid && assetidOpret == assetid)
@@ -542,8 +555,8 @@ bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_
cpTokens = CCinit(&C, EVAL_TOKENS); cpTokens = CCinit(&C, EVAL_TOKENS);
for (int32_t i = 0; i<numvins; i++) for (int32_t i = 0; i<numvins; i++)
{ // check for additional contracts which may send tokens to the Assets contract { // only tokens are relevant!!
if ((*cpAssets->ismyvin)(tx.vin[i].scriptSig) || (*cpTokens->ismyvin)(tx.vin[i].scriptSig)) // || IsVinAllowed(tx.vin[i].scriptSig) != 0) 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; //std::cerr << indentStr << "AssetExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl;
// we are not inside the validation code -- dimxy // we are not inside the validation code -- dimxy
@@ -555,7 +568,10 @@ bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_
else { else {
// validate vouts of vintx // validate vouts of vintx
//std::cerr << indentStr << "AssetExactAmounts() check vin i=" << i << " nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl; //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) if (assetoshis != 0)
{ {
std::cerr << "AssetExactAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl; 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) { if (tx.GetHash() != assetid) {
std::cerr << "AssetExactAmounts() unequal inputs=" << inputs << " vs outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl; 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"); 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]; char numstr[32], funcidstr[16], origaddr[64], assetidstr[65];
txid = it->first.txhash; 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 ) if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{ {
funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey); 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 (vintx.vout.size() > 0 && (funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0)
{ {
if (refassetid != zero && assetid != refassetid) if (refassetid != zero && assetid != refassetid)
@@ -163,6 +163,8 @@ UniValue AssetOrders(uint256 refassetid)
//fprintf(stderr," refassetid\n"); //fprintf(stderr," refassetid\n");
return; 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) if (vintx.vout[it->first.index].nValue == 0)
return; return;
@@ -213,7 +215,7 @@ UniValue AssetOrders(uint256 refassetid)
} }
} }
result.push_back(item); 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 (""); return ("");
} }
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, GetUnspendable(cpAssets,0))); CPubKey unspendablePubkey = GetUnspendable(cpAssets, 0);
return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', assetid, zeroid, pricetotal, Mypubkey()))); 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"); CCerror = strprintf("no coins found to make buy offer");
return(""); return("");
@@ -420,13 +426,17 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
return (""); 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) if (inputs > askamount)
CCchange = (inputs - askamount); CCchange = (inputs - askamount);
if (CCchange != 0) if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); 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)); return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,opret));
} }
else { else {
@@ -474,18 +484,22 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
return (""); 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) if (inputs > askamount)
CCchange = (inputs - askamount); CCchange = (inputs - askamount);
if (CCchange != 0) if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk));
if (assetid2 == zeroid)
opret = EncodeAssetOpRet('s', assetid, zeroid, pricetotal, Mypubkey()); std::vector<CPubKey> voutTokenPubkeys; // should be empty - no token vouts
else
{ if (assetid2 == zeroid) {
opret = EncodeAssetOpRet('e', assetid, assetid2, pricetotal, Mypubkey()); 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)); 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) if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0)
{ {
bidamount = vintx.vout[0].nValue; 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)); 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(""); return("");
@@ -554,7 +571,11 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
askamount = vintx.vout[0].nValue; askamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(asktxid, 0, CScript())); mtx.vin.push_back(CTxIn(asktxid, 0, CScript()));
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); 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(""); return("");
@@ -595,7 +616,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
bidamount = vintx.vout[bidvout].nValue; bidamount = vintx.vout[bidvout].nValue;
SetAssetOrigpubkey(origpubkey, origprice, vintx); 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) 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) if (inputs > fillamount)
CCchange = (inputs - fillamount); CCchange = (inputs - fillamount);
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, bidamount - paid_amount, GetUnspendable(cpTokens, NULL))); // tokens CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL);
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); uint8_t unspendableAssetsPrivkey[32];
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, fillamount, pubkey2pk(origpubkey))); // coins on assets 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) 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); fprintf(stderr,"remaining %llu -> origpubkey\n", (long long)remaining_required);
// add additional unspendable addr from Assets:
char unspendableAssetsAddr[64]; char unspendableAssetsAddr[64];
uint8_t unspendableAssetsPrivkey[32];
CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey);
GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk); GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk);
// add additional unspendable addr from Assets:
CCaddr2set(cpTokens, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr); CCaddr2set(cpTokens, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, origpubkey))); // token vout verification pubkeys:
} else return("dont have any assets to fill bid\n"); 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"); 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! mtx.vin.push_back(CTxIn(asktxid, askvout, CScript())); // NOTE: this is the reference to tokens -> send cpTokens for signing into FinalizeCCTx!
if (assetid2 != zeroid) 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 else
{ {
inputs = AddNormalinputs(mtx, mypk, paid_nValue, 60); 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) 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 else
SetAskFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); SetAskFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue);
if (assetid2 != zeroid && inputs > paid_nValue) if (assetid2 != zeroid && inputs > paid_nValue)
CCchange = (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, orig_assetoshis - received_assetoshis, GetUnspendable(cpTokens, NULL))); // 0 tokens cc addr - ask remainder
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); // tokens mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //1 tokens to self
if (assetid2 != zeroid) if (assetid2 != zeroid) {
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); // tokens... (swap is not implemented yet) std::cerr << "FillSell() WARNING: asset swap not implemented yet! (paid_nValue)" << std::endl;
else mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //2 tokens... (swap is not implemented yet)
mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); // coins normal }
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) // not implemented
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins in Assets cc addr 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 { } else {
CCerror = strprintf("filltx not enough utxos"); CCerror = strprintf("filltx not enough utxos");
fprintf(stderr,"%s\n", CCerror.c_str()); 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 AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs);
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); 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); 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 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 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 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); 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; 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; 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; std::string dummyName; std::string dummyDescription;
CPubKey voutPubkey1, voutPubkey2;
GetOpReturnData(scriptPubKey, vopret); GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data(); 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*/) 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; bool isEof = true;
evalCode = script[0]; evalCode = script[0];
funcid = script[1]; funcId = script[1];
//fprintf(stderr,"decode.[%c]\n",funcid); //fprintf(stderr,"decode.[%c]\n",funcId);
switch ( funcid )
switch ( funcId )
{ {
case 'c': case 'c':
return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription); return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription);
//break; //break;
case 't': case 't':
//not used yet: case 'l': //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); tokenid = revuint256(tokenid);
return(funcid); return(funcId);
} }
std::cerr << "DecodeTokenOpRet() isEof=" << isEof << std::endl; std::cerr << "DecodeTokenOpRet() warning: bad opret format, isEof=" << isEof << " ccType=" << ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl;
fprintf(stderr, "DecodeTokenOpRet() bad opret format\n"); // this may be just check, no error logging
return (uint8_t)0; return (uint8_t)0;
default: default:
fprintf(stderr, "DecodeTokenOpRet() illegal funcid.%02x\n", funcid); std::cerr << "DecodeTokenOpRet() illegal funcid=" << (int)funcId << std::endl;
return (uint8_t)0; return (uint8_t)0;
} }
} }
@@ -124,16 +142,18 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &
static uint256 zero; static uint256 zero;
CTxDestination address; CTransaction vinTx, createTx; uint256 hashBlock, tokenid, tokenid2; CTxDestination address; CTransaction vinTx, createTx; uint256 hashBlock, tokenid, tokenid2;
int32_t i, starti, numvins, numvouts, preventCCvins, preventCCvouts; 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; uint8_t funcid, evalCodeInOpret;
char destaddr[64], origaddr[64], CCaddr[64]; char destaddr[64], origaddr[64], CCaddr[64];
std::vector<CPubKey> voutTokenPubkeys;
numvins = tx.vin.size(); numvins = tx.vin.size();
numvouts = tx.vout.size(); numvouts = tx.vout.size();
outputs = inputs = 0; outputs = inputs = 0;
preventCCvins = preventCCvouts = -1; 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"); return eval->Invalid("TokenValidate: invalid opreturn payload");
fprintf(stderr, "TokensValidate (%c)\n", funcid); 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; thread_local uint32_t tokenValIndentSize = 0;
// validates opret for token tx: // 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; uint256 tokenidOpret, tokenidOpret2;
uint8_t funcid, evalCode; 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(); 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; std::cerr << indentStr << "ValidateTokenOpret() DecodeOpret returned null for n-1=" << n - 1 << " txid=" << tx.GetHash().GetHex() << std::endl;
return(false); 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 // Checks if the vout is a really Tokens CC vout
// compareTotals == true, the func also validates the passed transaction itself: // 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 // 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: // this is just for log messages indentation fur debugging recursive calls:
std::string indentStr = std::string().append(tokenValIndentSize, '.'); 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; //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! //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(); int32_t n = tx.vout.size();
// just check boundaries: // just check boundaries:
@@ -261,7 +283,7 @@ int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval,
return(0); return(0);
} }
if (compareTotals) { if (goDeeper) {
//std::cerr << indentStr << "IsTokensvout() maxTokenExactAmountDepth=" << maxTokenExactAmountDepth << std::endl; //std::cerr << indentStr << "IsTokensvout() maxTokenExactAmountDepth=" << maxTokenExactAmountDepth << std::endl;
//validate all tx //validate all tx
int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0; 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): // 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; //std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
if (valOpret) { 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; //std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned true" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
return tx.vout[v].nValue;
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()); //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) // 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; 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 numvins = tx.vin.size();
int32_t numvouts = tx.vout.size(); int32_t numvouts = tx.vout.size();
inputs = outputs = 0; 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 { // 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*/) 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; //std::cerr << indentStr << "TokensExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl;
// we are not inside the validation code -- dimxy // 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))) 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++; tokenValIndentSize++;
// validate vouts of vintx // validate vouts of vintx
//std::cerr << indentStr << "TokenExactAmounts() check vin i=" << i << " nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl; //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--; tokenValIndentSize--;
if (tokenoshis != 0) if (tokenoshis != 0)
{ {
@@ -339,7 +421,7 @@ bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, in
tokenValIndentSize++; tokenValIndentSize++;
// Note: we pass in here 'false' because we don't need to call TokenExactAmounts() recursively from IsTokenvout // 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 // 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--; tokenValIndentSize--;
if (tokenoshis != 0) 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) if (strcmp(destaddr, coinaddr) != 0 && strcmp(destaddr, cp->unspendableCCaddr) != 0 && strcmp(destaddr, cp->unspendableaddr2) != 0)
continue; continue;
fprintf(stderr, "AddTokenCCInputs() check destaddress=%s vout amount=%.8f\n", destaddr, (double)vintx.vout[vout].nValue / COIN); 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) if (total != 0 && maxinputs != 0)
mtx.vin.push_back(CTxIn(txid, vout, CScript())); mtx.vin.push_back(CTxIn(txid, vout, CScript()));

View File

@@ -27,8 +27,8 @@
// CCcustom // CCcustom
bool TokensValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); 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); 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 compareTotals, struct CCcontract_info *cp, Eval* eval, std::vector<uint8_t> &origpubkey, 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> &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector<CPubKey> vinPubkeys);
std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description); std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description);
std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector<uint8_t> destpubkey, int64_t total); 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 ) 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); 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; 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); 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]; char destaddr[64];
if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag ) 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); 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); return(false);
} }
else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || ( 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; 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; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector<uint8_t> origpubkey,tmporigpubkey,ignorepubkey;
uint8_t funcid, evalCodeInOpret; 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: // we need this for validating tokens' vins/vous:
struct CCcontract_info *cpTokens, tokensC; struct CCcontract_info *cpTokens, tokensC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS); cpTokens = CCinit(&tokensC, EVAL_TOKENS);
//CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL);
//CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, NULL);
//GetCCaddress(cpTokens, tokensUnspendableCCaddr, unspendableTokensPk);
numvins = tx.vin.size(); numvins = tx.vin.size();
numvouts = tx.vout.size(); numvouts = tx.vout.size();
outputs = inputs = 0; 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 ) if((funcid = DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 )
return eval->Invalid("AssetValidate: invalid opreturn payload"); return eval->Invalid("AssetValidate: invalid opreturn payload");
// find token user cc addr
GetCCaddress(cpTokens, tokensCCaddr, pubkey2pk(origpubkey));
fprintf(stderr,"AssetValidate (%c)\n",funcid); fprintf(stderr,"AssetValidate (%c)\n",funcid);
if( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid, createTx, hashBlock) == 0 ) 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"); 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"); return eval->Invalid("illegal asset vin0");
else if( numvouts < 1 ) else if( numvouts < 2 )
return eval->Invalid("no vouts"); return eval->Invalid("too few vouts"); // it was if(numvouts < 1) but it refers at least to vout[1] below
else if( funcid != 'c' ) else if( funcid != 'c' )
{ {
/* if( funcid == 't' ) /* 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.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey]
//vout.1: normal output for change (if any) //vout.1: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['o'] //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); 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"); 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.4: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey] //vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey]
preventCCvouts = 4; 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); return(false);
else if( numvouts < 3 ) else if( numvouts < 3 )
return eval->Invalid("not enough vouts for fillbuy"); 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"); 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, tokensCCaddr, 0) == 0 ) // tokens on user cc addr
return eval->Invalid("vout2 doesnt go to origpubkey fillbuy"); 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"); 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"); 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"); 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"); return eval->Invalid("mismatched remainder for fillbuy");
else if( remaining_price != 0 ) 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"); return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy");
} }
} }
@@ -287,16 +295,16 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
preventCCvouts = 1; preventCCvouts = 1;
if( remaining_price == 0 ) if( remaining_price == 0 )
return eval->Invalid("illegal null remaining_price for selloffer"); 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++; preventCCvouts++;
if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // check also vout[0]
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer"); return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
else if( tx.vout[0].nValue + tx.vout[1].nValue != inputs ) else if( tx.vout[0].nValue + tx.vout[1].nValue != inputs )
return eval->Invalid("mismatched vout0+vout1 total for selloffer"); return eval->Invalid("mismatched vout0+vout1 total for selloffer");
} }
else if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, inputs) == 0 ) else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // no cc change, just vout[0]
return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer"); return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
//fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price); //fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price);
break; 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.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey]
//vout.1: normal output for change (if any) //vout.1: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] //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); 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"); return eval->Invalid("invalid vout for cancel");
preventCCvins = 2; preventCCvins = 2;
preventCCvouts = 1; 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] //'S'.vout.2: vin.2 value to original pubkey [origpubkey]
//vout.3: normal output for change (if any) //vout.3: normal output for change (if any)
//'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] //'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); return(false);
else if( numvouts < 3 ) else if( numvouts < 3 )
return eval->Invalid("not enough vouts for fillask"); 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"); return eval->Invalid("normal vout1 for fillask");
else if( remaining_price != 0 ) else if( remaining_price != 0 )
{ {
if ( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr,0) == 0 ) if ( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr,0) == 0 )
return eval->Invalid("mismatched vout0 AssetsCCaddr for fill"); return eval->Invalid("mismatched vout0 TokenCCaddr for fill");
} }
} }
fprintf(stderr,"fill validated\n"); 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 ) //if ( AssetExactAmounts(false, cp,inputs,outputs,eval,tx,assetid2) == false )
// eval->Invalid("asset2 inputs != outputs"); // 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); return(false);
else if( numvouts < 3 ) else if( numvouts < 3 )
return eval->Invalid("not enough vouts for fillex"); 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"); 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 )
{ {
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"); 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 )
{ {
@@ -383,7 +391,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("asset inputs doesnt match vout2+3 fillex"); 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"); 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"); 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"); return eval->Invalid("normal vout1 for fillex");
else if( remaining_price != 0 ) 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"); 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); CCchange = (inputs - amount);
mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk)); mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk));
// add addr2 // 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 else
{ {

View File

@@ -407,6 +407,20 @@ bool CScript::MayAcceptCryptoCondition() const
cc_free(cond); cc_free(cond);
return out; 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 bool CScript::IsCoinImport() const
{ {

View File

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