Files
hush3/src/cc/CCtokensOpRet.cpp
2019-02-28 00:07:08 +05:00

266 lines
10 KiB
C++

// encode decode tokens opret
// (moved to a separate file to enable linking lib common.so with importcoin.cpp)
#include "CCtokens.h"
// NOTE: this inital tx won't be used by other contract
// for tokens to be used there should be at least one 't' tx with other contract's custom opret
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, vscript_t vopretNonfungible)
{
/* CScript opret;
uint8_t evalcode = EVAL_TOKENS;
funcid = 'c'; // override the param
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description; \
if (!vopretNonfungible.empty()) {
ss << (uint8_t)OPRETID_NONFUNGIBLEDATA;
ss << vopretNonfungible;
}); */
std::vector<std::pair<uint8_t, vscript_t>> oprets;
oprets.push_back(std::make_pair(OPRETID_NONFUNGIBLEDATA, vopretNonfungible));
return EncodeTokenCreateOpRet(funcid, origpubkey, name, description, oprets);
}
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, std::vector<std::pair<uint8_t, vscript_t>> oprets)
{
CScript opret;
uint8_t evalcode = EVAL_TOKENS;
funcid = 'c'; // override the param
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description;
for (auto o : oprets) {
if (o.first != 0) {
ss << (uint8_t)o.first;
ss << o.second;
}
});
return(opret);
}
// opret 'i' for imported tokens
CScript EncodeTokenImportOpRet(std::vector<uint8_t> origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector<std::pair<uint8_t, vscript_t>> oprets)
{
CScript opret;
uint8_t evalcode = EVAL_TOKENS;
uint8_t funcid = 'i';
srctokenid = revuint256(srctokenid); // do not forget this
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description << srctokenid;
for (auto o : oprets) {
if (o.first != 0) {
ss << (uint8_t)o.first;
ss << o.second;
}
});
return(opret);
}
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::pair<uint8_t, vscript_t> opretWithId)
{
std::vector<std::pair<uint8_t, vscript_t>> oprets;
oprets.push_back(opretWithId);
return EncodeTokenOpRet(tokenid, voutPubkeys, oprets);
}
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> oprets)
{
CScript opret;
uint8_t tokenFuncId = 't';
uint8_t evalCodeInOpret = EVAL_TOKENS;
tokenid = revuint256(tokenid);
uint8_t ccType = 0;
if (voutPubkeys.size() >= 0 && voutPubkeys.size() <= 2)
ccType = voutPubkeys.size();
else {
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "EncodeTokenOpRet voutPubkeys.size()=" << voutPubkeys.size() << " not supported" << std::endl);
}
//vopret_t vpayload;
//GetOpReturnData(payload, vpayload);
opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType;
if (ccType >= 1) ss << voutPubkeys[0];
if (ccType == 2) ss << voutPubkeys[1];
for (auto o : oprets) {
if (o.first != 0) {
ss << (uint8_t)o.first;
ss << o.second;
}
});
// bad opret cases (tries to attach payload without re-serialization):
// error "64: scriptpubkey":
// if (payload.size() > 0)
// opret += payload;
// error "64: scriptpubkey":
// CScript opretPayloadNoOpcode(vpayload);
// return opret + opretPayloadNoOpcode;
// error "sig_aborted":
// opret.resize(opret.size() + vpayload.size());
// CScript::iterator it = opret.begin() + opret.size();
// for (int i = 0; i < vpayload.size(); i++, it++)
// *it = vpayload[i];
return opret;
}
// overload for compatibility
//CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload)
//{
// return EncodeTokenOpRet(tokenid, voutPubkeys, payload);
//}
// overload for fungible tokens (no additional data in opret):
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description) {
//vopret_t vopretNonfungibleDummy;
std::vector<std::pair<uint8_t, vscript_t>> opretsDummy;
return DecodeTokenCreateOpRet(scriptPubKey, origpubkey, name, description, opretsDummy);
}
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, std::vector<std::pair<uint8_t, vscript_t>> &oprets)
{
vscript_t vopret, vblob;
uint8_t dummyEvalcode, funcid, opretId = 0;
GetOpReturnData(scriptPubKey, vopret);
oprets.clear();
if (vopret.size() > 2 && vopret.begin()[0] == EVAL_TOKENS && vopret.begin()[1] == 'c')
{
if (E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description;
while (!ss.eof()) {
ss >> opretId;
if (!ss.eof()) {
ss >> vblob;
oprets.push_back(std::make_pair(opretId, vblob));
}
}))
{
return(funcid);
}
}
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenCreateOpRet() incorrect token create opret" << std::endl);
return (uint8_t)0;
}
// for imported tokens
uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector<std::pair<uint8_t, vscript_t>> &oprets)
{
vscript_t vopret, vblob;
uint8_t dummyEvalcode, funcid, opretId = 0;
GetOpReturnData(scriptPubKey, vopret);
oprets.clear();
if (vopret.size() > 2 && vopret.begin()[0] == EVAL_TOKENS && vopret.begin()[1] == 'i')
{
if (E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description; ss >> srctokenid;
while (!ss.eof()) {
ss >> opretId;
if (!ss.eof()) {
ss >> vblob;
oprets.push_back(std::make_pair(opretId, vblob));
}
}))
{
srctokenid = revuint256(srctokenid); // do not forget this
return(funcid);
}
}
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenImportOpRet() incorrect token import opret" << std::endl);
return (uint8_t)0;
}
// decodes token opret:
// for 't' returns all data from opret, vopretExtra contains other contract's data (currently only assets').
// for 'c' and 'i' returns only funcid. NOTE: nonfungible data is not returned
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<std::pair<uint8_t, vscript_t>> &oprets)
{
vscript_t vopret, vblob, dummyPubkey, vnonfungibleDummy;
uint8_t funcId = 0, *script, dummyEvalCode, dummyFuncId, ccType, opretId = 0;
std::string dummyName; std::string dummyDescription;
uint256 dummySrcTokenId;
CPubKey voutPubkey1, voutPubkey2;
GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
tokenid = zeroid;
oprets.clear();
if (script != NULL && vopret.size() > 2)
{
// NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set!
// bool isEof = true;
evalCodeTokens = script[0];
if (evalCodeTokens != EVAL_TOKENS) {
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() incorrect evalcode in tokens opret" << std::endl);
return (uint8_t)0;
}
funcId = script[1];
LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "DecodeTokenOpRet decoded funcId=" << (char)(funcId ? funcId : ' ') << std::endl);
switch (funcId)
{
case 'c':
return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, oprets);
case 'i':
return DecodeTokenImportOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, dummySrcTokenId, oprets);
//break;
case 't':
//not used yet: case 'l':
// NOTE: 'E_UNMARSHAL result==false' means 'parse error' OR 'not eof state'. Consequently, 'result==false' but 'isEof==true' means just 'parse error'
if (E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> tokenid; ss >> ccType;
if (ccType >= 1) ss >> voutPubkey1;
if (ccType == 2) ss >> voutPubkey2;
while (!ss.eof()) {
ss >> opretId;
if (!ss.eof()) {
ss >> vblob;
oprets.push_back(std::make_pair(opretId, vblob));
}
}))
{
if (!(ccType >= 0 && ccType <= 2)) { //incorrect ccType
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() incorrect ccType=" << (int)ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl);
return (uint8_t)0;
}
// add verification pubkeys:
voutPubkeys.clear();
if (voutPubkey1.IsValid())
voutPubkeys.push_back(voutPubkey1);
if (voutPubkey2.IsValid())
voutPubkeys.push_back(voutPubkey2);
tokenid = revuint256(tokenid);
return(funcId);
}
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() bad opret format," << " ccType=" << (int)ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl);
return (uint8_t)0;
default:
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() illegal funcid=" << (int)funcId << std::endl);
return (uint8_t)0;
}
}
else {
LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() empty opret, could not parse" << std::endl);
}
return (uint8_t)0;
}