![dimxy@komodoplatform.com](/assets/img/avatar_default.png)
19 changed files with 608 additions and 400 deletions
@ -0,0 +1,265 @@ |
|||
// 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; |
|||
} |
|||
|
|||
|
|||
|
@ -0,0 +1,105 @@ |
|||
/******************************************************************************
|
|||
* Copyright © 2014-2019 The SuperNET Developers. * |
|||
* * |
|||
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * |
|||
* the top-level directory of this distribution for the individual copyright * |
|||
* holder information and the developer policies on copyright and licensing. * |
|||
* * |
|||
* Unless otherwise agreed in a custom licensing agreement, no part of the * |
|||
* SuperNET software, including this file may be copied, modified, propagated * |
|||
* or distributed except according to the terms contained in the LICENSE file * |
|||
* * |
|||
* Removal or modification of this copyright notice is prohibited. * |
|||
* * |
|||
******************************************************************************/ |
|||
|
|||
/*
|
|||
CCutilbits.cpp has very low level functions that are universally useful for all contracts and have low dependency from other sources |
|||
*/ |
|||
|
|||
#include "CCinclude.h" |
|||
#include "komodo_structs.h" |
|||
|
|||
int32_t unstringbits(char *buf,uint64_t bits) |
|||
{ |
|||
int32_t i; |
|||
for (i=0; i<8; i++,bits>>=8) |
|||
if ( (buf[i]= (char)(bits & 0xff)) == 0 ) |
|||
break; |
|||
buf[i] = 0; |
|||
return(i); |
|||
} |
|||
|
|||
uint64_t stringbits(char *str) |
|||
{ |
|||
uint64_t bits = 0; |
|||
if ( str == 0 ) |
|||
return(0); |
|||
int32_t i,n = (int32_t)strlen(str); |
|||
if ( n > 8 ) |
|||
n = 8; |
|||
for (i=n-1; i>=0; i--) |
|||
bits = (bits << 8) | (str[i] & 0xff); |
|||
//printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits);
|
|||
return(bits); |
|||
} |
|||
|
|||
uint256 revuint256(uint256 txid) |
|||
{ |
|||
uint256 revtxid; int32_t i; |
|||
for (i=31; i>=0; i--) |
|||
((uint8_t *)&revtxid)[31-i] = ((uint8_t *)&txid)[i]; |
|||
return(revtxid); |
|||
} |
|||
|
|||
char *uint256_str(char *dest,uint256 txid) |
|||
{ |
|||
int32_t i,j=0; |
|||
for (i=31; i>=0; i--) |
|||
sprintf(&dest[j++ * 2],"%02x",((uint8_t *)&txid)[i]); |
|||
dest[64] = 0; |
|||
return(dest); |
|||
} |
|||
|
|||
char *pubkey33_str(char *dest,uint8_t *pubkey33) |
|||
{ |
|||
int32_t i; |
|||
if ( pubkey33 != 0 ) |
|||
{ |
|||
for (i=0; i<33; i++) |
|||
sprintf(&dest[i * 2],"%02x",pubkey33[i]); |
|||
} else dest[0] = 0; |
|||
return(dest); |
|||
} |
|||
|
|||
uint256 Parseuint256(const char *hexstr) |
|||
{ |
|||
uint256 txid; int32_t i; std::vector<unsigned char> txidbytes(ParseHex(hexstr)); |
|||
memset(&txid,0,sizeof(txid)); |
|||
if ( strlen(hexstr) == 64 ) |
|||
{ |
|||
for (i=31; i>=0; i--) |
|||
((uint8_t *)&txid)[31-i] = ((uint8_t *)txidbytes.data())[i]; |
|||
} |
|||
return(txid); |
|||
} |
|||
|
|||
CPubKey buf2pk(uint8_t *buf33) |
|||
{ |
|||
CPubKey pk; int32_t i; uint8_t *dest; |
|||
dest = (uint8_t *)pk.begin(); |
|||
for (i=0; i<33; i++) |
|||
dest[i] = buf33[i]; |
|||
return(pk); |
|||
} |
|||
|
|||
CPubKey pubkey2pk(std::vector<uint8_t> pubkey) |
|||
{ |
|||
CPubKey pk; int32_t i,n; uint8_t *dest,*pubkey33; |
|||
n = pubkey.size(); |
|||
dest = (uint8_t *)pk.begin(); |
|||
pubkey33 = (uint8_t *)pubkey.data(); |
|||
for (i=0; i<n; i++) |
|||
dest[i] = pubkey33[i]; |
|||
return(pk); |
|||
} |
Loading…
Reference in new issue