heir modified for two eval Tokens

changed to new 2-opret format
This commit is contained in:
dimxy
2019-01-11 23:02:37 +05:00
parent 6d509d5293
commit c4c58b484a
6 changed files with 342 additions and 159 deletions

View File

@@ -191,6 +191,8 @@ CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubK
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk);
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2);
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk);
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk);
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2);
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr);

View File

@@ -201,10 +201,10 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &
//vout.0: issuance tokenoshis to CC
//vout.1: normal output for change (if any)
//vout.n-1: opreturn EVAL_TOKENS 'c' <tokenname> <description>
if (evalCodeInOpret != EVAL_TOKENS)
return eval->Invalid("unexpected TokenValidate for createtoken");
else
return true;
//if (evalCodeInOpret != EVAL_TOKENS)
// return eval->Invalid("unexpected TokenValidate for createtoken");
//else
return true;
case 't': // transfer
//vin.0: normal input
@@ -225,15 +225,15 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &
// forward validation if evalcode in opret is not EVAL_TOKENS
// init for forwarding validation call
if (evalCodeInOpret != EVAL_TOKENS) { // TODO: should we check also only allowed for tokens evalcodes, like EVAL_ASSETS, EVAL_GATEWAYS?
struct CCcontract_info *cpOther = NULL, C;
//if (evalCodeInOpret != EVAL_TOKENS) { // TODO: should we check also only allowed for tokens evalcodes, like EVAL_ASSETS, EVAL_GATEWAYS?
// struct CCcontract_info *cpOther = NULL, C;
cpOther = CCinit(&C, evalCodeInOpret);
if (cpOther)
return cpOther->validate(cpOther, eval, tx, nIn);
else
return eval->Invalid("unsupported evalcode in opret");
}
// cpOther = CCinit(&C, evalCodeInOpret);
// if (cpOther)
// return cpOther->validate(cpOther, eval, tx, nIn);
// else
// return eval->Invalid("unsupported evalcode in opret");
//}
return true;
// what does this do?
// return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
@@ -285,17 +285,18 @@ bool ExtractVinPubkeys(struct CCcontract_info *cp, CTransaction tx, std::vector<
thread_local uint32_t tokenValIndentSize = 0;
// validates opret for token tx:
bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, uint8_t &evalCodeInOpret, std::vector<CPubKey> &voutPubkeys, 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;
uint8_t dummyEvalCode;
// this is just for log messages indentation fur debugging recursive calls:
std::string indentStr = std::string().append(tokenValIndentSize, '.');
int32_t n = tx.vout.size();
if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCodeInOpret, tokenidOpret, voutPubkeys, vopretExtra)) == 0)
if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, dummyEvalCode, tokenidOpret, voutPubkeys, vopretExtra)) == 0)
{
std::cerr << indentStr << "ValidateTokenOpret() DecodeTokenOpret could not parse opret for txid=" << tx.GetHash().GetHex() << std::endl;
return(false);
@@ -364,14 +365,24 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c
// moved opret checking to this new reusable func (dimxy):
std::vector<CPubKey> voutPubkeys;
uint8_t evalCodeInOpret = 0;
const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, evalCodeInOpret, voutPubkeys, vopretExtra);
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" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl;
if (checkPubkeys) { // verify that the vout is within EVAL_TOKENS:
CScript contractScript = CScript(vopretExtra);
std::vector<uint8_t> vcontractOpret;
GetOpReturnData(contractScript, vcontractOpret);
if (vcontractOpret.size() == 0) {
std::cerr << "IsTokensvout() empty contract opret" << std::endl;
return 0;
}
uint8_t evalCodeInOpret = vcontractOpret.begin()[0];
if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) {
CTxOut testVout;
if (voutPubkeys.size() == 1)

View File

@@ -43,9 +43,9 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0;
int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0;
int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64];
int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64],mytokensaddr[64];
uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0;
CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond;
CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL;
CPubKey unspendablepk;
n = mtx.vout.size();
@@ -61,11 +61,17 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
return("0");
}
Myprivkey(myprivkey);
unspendablepk = GetUnspendable(cp,unspendablepriv);
GetCCaddress(cp,myaddr,mypk);
mycond = MakeCCcond1(cp->evalcode,mypk);
GetTokensCCaddress(cp, myaddr, mypk);
mytokenscond = MakeTokensCCcond1(cp->evalcode, mypk);
unspendablepk = GetUnspendable(cp,unspendablepriv);
GetCCaddress(cp,unspendable,unspendablepk);
othercond = MakeCCcond1(cp->evalcode,unspendablepk);
othercond = MakeCCcond1(cp->evalcode,unspendablepk);
//Reorder vins so that for multiple normal vins all other except vin0 goes to the end
//This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation.
for (i=0; i<n; i++)
@@ -137,6 +143,12 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
privkey = myprivkey;
cond = mycond;
}
if (strcmp(destaddr, mytokensaddr) == 0) // if this is TokensCC1vout
{
privkey = myprivkey;
cond = mytokenscond;
//fprintf(stderr,"FinalizeCCTx() matched TokensCC1vout CC addr.(%s)\n",mytokensaddr);
}
else if ( strcmp(destaddr,unspendable) == 0 )
{
privkey = unspendablepriv;
@@ -162,7 +174,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
cond = othercond3;
}
// check if this is spending from 1of2 cc coins addr:
else if (strcmp(cp->coins1of2addr, destaddr) == 0)
else if (strcmp(cp->coins1of2addr, destaddr) == 0)
{
fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr);
privkey = myprivkey;

View File

@@ -94,8 +94,8 @@ CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk)
{
std::vector<CC*> pks;
pks.push_back(CCNewSecp256k1(pk));
CC *condEvalCC = CCNewEval(E_MARSHAL(ss << evalcode));
CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // this is eval token cc
CC *condEvalCC = CCNewEval(E_MARSHAL(ss << evalcode)); // add eval cc
CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // add also eval token cc
CC *Sig = CCNewThreshold(1, pks);
return CCNewThreshold(3, { condEvalCC, condEvalTokensCC, Sig });
}
@@ -345,6 +345,27 @@ bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
return(_GetCCaddress(destaddr,cp->evalcode,pk));
}
bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, CPubKey pk)
{
CC *payoutCond;
destaddr[0] = 0;
if ((payoutCond = MakeTokensCCcond1(evalcode, pk)) != 0)
{
Getscriptaddress(destaddr, CCPubKey(payoutCond));
cc_free(payoutCond);
}
return(destaddr[0] != 0);
}
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk)
{
destaddr[0] = 0;
if (pk.size() == 0)
pk = GetUnspendable(cp, 0);
return(_GetTokensCCaddress(destaddr, cp->evalcode, pk));
}
bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2)
{
CC *payoutCond;

View File

@@ -122,23 +122,27 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction
//if (chainActive.Height() < 741)
// return true;
uint8_t funcId;
uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, dummyTokenid, tokenid = zeroid;
CScript fundingTxOpRetScript;
uint8_t hasHeirSpendingBegun = 0, dummyHasHeirSpendingBegun;
int32_t heirType = NOT_HEIR;
funcId = DecodeHeirOpRet<CoinHelper>(tx.vout[numvouts - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, true);
if(funcId != 0)
heirType = HEIR_COINS;
else {
funcId = DecodeHeirOpRet<TokenHelper>(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, false);
if (funcId != 0)
heirType = HEIR_TOKENS;
uint8_t evalCodeTokens = 0;
std::vector<CPubKey> voutPubkeys;
std::vector<uint8_t> vopretExtra;
CScript heirScript = tx.vout[tx.vout.size() - 1].scriptPubKey;
int32_t heirType = HEIR_COINS;
uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra);
if (funcId != 0) {
heirScript = CScript(vopretExtra);
heirType = HEIR_TOKENS;
}
funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyHasHeirSpendingBegun, true);
if (heirType == NOT_HEIR)
if (funcId == 0)
return eval->Invalid("invalid opreturn format");
if (funcId != 'F') {
@@ -248,11 +252,11 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction
* Checks if vout is to cryptocondition address
* @return vout value in satoshis
*/
int64_t IsHeirFundingVout(struct CCcontract_info* cp, const CTransaction& tx, int32_t voutIndex, CPubKey ownerPubkey, CPubKey heirPubkey)
template <class Helper> int64_t IsHeirFundingVout(struct CCcontract_info* cp, const CTransaction& tx, int32_t voutIndex, CPubKey ownerPubkey, CPubKey heirPubkey)
{
char destaddr[65], heirFundingAddr[65];
GetTokensCCaddress1of2(cp, heirFundingAddr, ownerPubkey, heirPubkey);
Helper::GetCoinsOrTokensCCaddress1of2(cp, heirFundingAddr, ownerPubkey, heirPubkey);
if (tx.vout[voutIndex].scriptPubKey.IsPayToCryptoCondition() != 0) {
// NOTE: dimxy it was unsafe 'Getscriptaddress(destaddr,tx.vout[voutIndex].scriptPubKey) > 0' here:
if (Getscriptaddress(destaddr, tx.vout[voutIndex].scriptPubKey) && strcmp(destaddr, heirFundingAddr) == 0)
@@ -317,6 +321,8 @@ CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpe
fundingtxid = revuint256(fundingtxid);
return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << fundingtxid << hasHeirSpendingBegun);
}
/*
// makes opret for tokens while they are inside Heir contract address space - initial funding
CScript EncodeHeirTokensCreateOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName)
{
@@ -348,10 +354,11 @@ CScript EncodeHeirTokensOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector<C
if (ccType == 2) ss << voutPubkeys[1]; \
ss << heirFuncId << fundingtxid << hasHeirSpendingBegun);
}
*/
// helper for decode heir opret payload
// NOTE: Heir for coins has the same opret as Heir for tokens
uint8_t _UnmarshalOpret(std::vector<uint8_t> vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun) {
/*uint8_t _UnmarshalOpret(std::vector<uint8_t> vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun) {
uint8_t heirFuncId = 0;
hasHeirSpendingBegun = 0;
@@ -363,70 +370,66 @@ uint8_t _UnmarshalOpret(std::vector<uint8_t> vopretExtra, CPubKey& ownerPubkey,
} \
});
if (!result /*|| assetFuncId != 't' -- any tx is ok*/)
if (!result )// || assetFuncId != 't' -- any tx is ok)
return (uint8_t)0;
return heirFuncId;
}
}*/
/**
* decode opret vout for Heir contract
*/
template <class Helper> uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
uint8_t _DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
{
std::vector<uint8_t> vopretExtra;
std::vector<uint8_t> vopret;
uint8_t evalCodeInOpret = 0;
uint256 dummyTokenid;
std::vector<CPubKey> voutPubkeysDummy;
uint8_t heirFuncId = 0;
fundingTxidInOpret = zeroid; //to init
tokenid = zeroid;
if (typeid(Helper) == typeid(TokenHelper)) { // if caller thinks it is a token
// First - decode token opret:
uint8_t tokenFuncId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra);
if (tokenFuncId == 0) {
if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: not heir token opret, tokenFuncId=" << (int)tokenFuncId << std::endl;
return (uint8_t)0;
}
GetOpReturnData(scriptPubKey, vopret);
if (vopret.size() == 0) {
if (!noLogging) std::cerr << "_DecodeHeirOpRet() warning: empty opret" << std::endl;
return (uint8_t)0;
}
else {
std::vector<uint8_t> vopret;
GetOpReturnData(scriptPubKey, vopret);
if (vopret.size() == 0) {
if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl;
return (uint8_t)0;
}
evalCodeInOpret = vopret.begin()[0];
vopretExtra = std::vector<uint8_t>( vopret.begin()+1, vopret.end() ); // vopretExtra = vopret + 1, get it for futher parsing
}
if (vopretExtra.size() > 1 && evalCodeInOpret == EVAL_HEIR) {
evalCodeInOpret = vopret.begin()[0];
if (vopret.size() > 1 && evalCodeInOpret == EVAL_HEIR) {
// NOTE: it unmarshals for all F, A and C
uint8_t heirFuncId = _UnmarshalOpret(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, hasHeirSpendingBegun);
/*std::cerr << "DecodeHeirOpRet()"
uint8_t heirFuncId = 0;
hasHeirSpendingBegun = 0;
bool result = E_UNMARSHAL(vopret, { ss >> evalCodeInOpret; ss >> heirFuncId; \
if (heirFuncId == 'F') { \
ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; \
} \
else { \
ss >> fundingTxidInOpret >> hasHeirSpendingBegun; \
} \
});
if (!result) {
if (!noLogging) std::cerr << "_DecodeHeirOpRet() could not unmarshal opret, evalCode=" << (int)evalCodeInOpret << std::endl;
return (uint8_t)0;
}
/* std::cerr << "DecodeHeirOpRet()"
<< " heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ')
<< " ownerPubkey=" << HexStr(ownerPubkey)
<< " heirPubkey=" << HexStr(heirPubkey)
<< " heirName=" << heirName << " inactivityTime=" << inactivityTime
<< " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << std::endl;*/
<< " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << std::endl; */
//if (e == EVAL_HEIR && IS_CHARINSTR(funcId, "FAC"))
if (Helper::isMyFuncId(heirFuncId)) {
if (isMyFuncId(heirFuncId)) {
fundingTxidInOpret = revuint256(fundingTxidInOpret);
return heirFuncId;
}
else {
if(!noLogging) std::cerr << "DecodeHeirOpRet() error: unexpected opret, heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') << std::endl;
if(!noLogging) std::cerr << "_DecodeHeirOpRet() unexpected opret type, heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') << std::endl;
}
}
else {
if (!noLogging) std::cerr << "DecodeHeirOpRet() error: not a heir opret, vopretExtra.size() == 0 or not EVAL_HEIR evalcode=" << (int)evalCodeInOpret << std::endl;
if (!noLogging) std::cerr << "_DecodeHeirOpRet() not a heir opret, vopretExtra.size() == 0 or not EVAL_HEIR evalcode=" << (int)evalCodeInOpret << std::endl;
}
return (uint8_t)0;
}
@@ -434,24 +437,24 @@ template <class Helper> uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 &
/**
* overload for 'F' opret
*/
template <class Helper> uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging)
uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging)
{
uint256 dummytxid;
uint8_t dummyHasHeirSpendingBegun;
return _DecodeHeirOpRet<Helper>(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging);
return _DecodeHeirOpRet(scriptPubKey, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging);
}
/**
* overload for A, C oprets and AddHeirContractInputs
*/
template <class Helper> uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
{
CPubKey dummyOwnerPubkey, dummyHeirPubkey;
int64_t dummyInactivityTime;
std::string dummyHeirName;
return _DecodeHeirOpRet<Helper>(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging);
return _DecodeHeirOpRet(scriptPubKey, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging);
}
@@ -476,9 +479,22 @@ template <class Helper> uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_
// get initial funding tx and set it as initial lasttx:
if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) {
uint256 dummytxid;
uint8_t evalCodeTokens = 0;
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> dummyVoutPubkeys;
// set ownerPubkey and heirPubkey:
if ((funcId = DecodeHeirOpRet<Helper>(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) != 0) {
CScript heirScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey;
if (typeid(Helper) == typeid(TokenHelper)) {
if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) {
heirScript = CScript(vopretExtra);
}
else {
std::cerr << "FindLatestFundingTx() could not decode token opreturn for fundingtxid=" << fundingtxid.GetHex() << '\n';
return zeroid;
}
}
funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName);
if (funcId != 0) {
// found at least funding tx!
//std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n';
fundingOpretScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey;
@@ -493,7 +509,7 @@ template <class Helper> uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>> unspentOutputs;
struct CCcontract_info *cp, C;
cp = CCinit(&C, Helper::getMyEval());
cp = CCinit(&C, EVAL_HEIR);
char coinaddr[64];
GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys'
@@ -531,9 +547,23 @@ template <class Helper> uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_
uint8_t tmpFuncId;
uint8_t tmphasHeirSpendingBegun;
if (regtx.vout.size() > 0 &&
(tmpFuncId = DecodeHeirOpRet<Helper>(regtx.vout[regtx.vout.size() - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, tmphasHeirSpendingBegun, true)) != 0 &&
fundingtxid == fundingTxidInOpret) {
uint8_t evalCodeTokens = 0;
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> dummyVoutPubkeys;
CScript heirScript = regtx.vout[regtx.vout.size() - 1].scriptPubKey;
if (typeid(Helper) == typeid(TokenHelper)) {
if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) {
heirScript = CScript(vopretExtra);
}
else {
std::cerr << "FindLatestFundingTx() could not decode token opreturn for fundingtxid=" << fundingtxid.GetHex() << '\n';
return zeroid;
}
}
tmpFuncId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, tmphasHeirSpendingBegun, true);
if (regtx.vout.size() > 0 && tmpFuncId != 0 && fundingtxid == fundingTxidInOpret) {
if (blockHeight > maxBlockHeight) {
maxBlockHeight = blockHeight;
@@ -581,12 +611,13 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>> unspentOutputs;
char coinaddr[64];
GetTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 pubkey of 2 pubkeys'
Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 of 2 pubkeys'
SetCCunspents(unspentOutputs, coinaddr);
// char markeraddr[64];
// CCtxidaddr(markeraddr, fundingtxid);
// SetCCunspents(unspentOutputs, markeraddr);
std::cerr << "Add1of2AddressInputs() using 1of2addr=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << std::endl;
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) {
@@ -602,13 +633,22 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
uint256 tokenid;
uint256 fundingTxidInOpret;
uint8_t dummyHasHeirSpendingBegun;
uint8_t evalCodeTokens = 0;
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> voutPubkeys;
uint8_t funcId = DecodeHeirOpRet<Helper>(heirtx.vout[heirtx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, true);
CScript heirScript = heirtx.vout[heirtx.vout.size() - 1].scriptPubKey;
uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra);
if (funcId != 0) {
heirScript = CScript(vopretExtra);
}
funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyHasHeirSpendingBegun, true);
if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) &&
funcId != 0 &&
Helper::isMyFuncId(funcId) &&
isMyFuncId(funcId) &&
// (typeid(Helper) == typeid(TokenHelper) && IsHeirvout(true, cp, nullptr, tokenid, vintx, voutIndex) > 0) && // deep validation for tokens - not used anymore
(voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 &&
(voutValue = IsHeirFundingVout<Helper>(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 &&
!myIsutxo_spentinmempool(txid, voutIndex))
{
std::cerr << "Add1of2AddressInputs() voutValue=" << voutValue << " satoshis=" << it->second.satoshis << '\n';
@@ -631,7 +671,7 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info* cp, uint256 fundingtxid, CPubKey ownerPubkey, CPubKey heirPubkey)
{
char coinaddr[64];
GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys'
Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys'
std::vector<std::pair<CAddressIndexKey, CAmount>> addressIndexes;
SetCCtxids(addressIndexes, coinaddr);
@@ -644,17 +684,24 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
CTransaction tx;
if (GetTransaction(txid, tx, hashBlock, false) && tx.vout.size() > 0) {
uint8_t funcId;
uint8_t evalCodeTokens = 0;
uint256 tokenid;
uint256 fundingTxidInOpret;
const int32_t ivout = 0;
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> voutPubkeys;
uint8_t dummyHasHeirSpendingBegun;
funcId = DecodeHeirOpRet<Helper>(tx.vout[tx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, true);
const int32_t ivout = 0;
CScript heirScript = tx.vout[tx.vout.size() - 1].scriptPubKey;
uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra);
if (funcId != 0) {
heirScript = CScript(vopretExtra);
}
funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyHasHeirSpendingBegun, true);
//std::cerr << "LifetimeHeirContractFunds() found tx=" << txid.GetHex() << " vout[0].nValue=" << subtx.vout[ccVoutIdx].nValue << " opreturn=" << (char)funcId << '\n';
if (funcId != 0 && (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && Helper::isMyFuncId(funcId) && !Helper::isSpendingTx(funcId)
if (funcId != 0 && (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && isMyFuncId(funcId) && !isSpendingTx(funcId)
/* && !myIsutxo_spentinmempool(txid, ccVoutIdx) */) // include also tx in mempool
{
total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change)
@@ -678,7 +725,7 @@ template <typename Helper> std::string HeirFund(uint64_t txfee, int64_t amount,
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
struct CCcontract_info *cp, C;
cp = CCinit(&C, Helper::getMyEval());
cp = CCinit(&C, EVAL_HEIR);
if (txfee == 0)
txfee = 10000;
@@ -719,7 +766,6 @@ template <typename Helper> std::string HeirFund(uint64_t txfee, int64_t amount,
// add change for txfee and opreturn vouts and sign tx:
return (FinalizeCCTx(0, cp, mtx, myPubkey, txfee,
// CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'F' << myPubkey << heirPubkey << inactivityTimeSec << heirName)));
Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName)));
}
else // TODO: need result return unification with heiradd and claim
@@ -759,7 +805,7 @@ template <class Helper> UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in
uint8_t funcId;
uint8_t hasHeirSpendingBegun = 0;
cp = CCinit(&C, Helper::getMyEval());
cp = CCinit(&C, EVAL_HEIR);
if (txfee == 0)
txfee = 10000;
@@ -790,7 +836,7 @@ template <class Helper> UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in
std::cerr << "HeirAdd() adding markeraddr=" << markeraddr << '\n'; */
// add cryptocondition to spend this funded amount for either pk
mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), amount, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up!
mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up!
if (inputs > amount)
change = (inputs - amount); // -txfee <-- txfee pays user
@@ -801,7 +847,7 @@ template <class Helper> UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in
mtx.vout.push_back(Helper::makeUserVout(change, myPubkey));
}
// add 1of2 vout validation pubkeys:
// add 1of2 vout validation pubkeys - needed only for tokens:
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(ownerPubkey);
voutTokenPubkeys.push_back(heirPubkey);
@@ -863,8 +909,6 @@ template <typename Helper>UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee
std::string heirName;
uint8_t hasHeirSpendingBegun = 0;
//cp = CCinit(&C, Helper::getMyEval());
cp = CCinit(&C, EVAL_HEIR);
if (txfee == 0)
txfee = 10000;
@@ -924,7 +968,7 @@ template <typename Helper>UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee
// change to 1of2 funding addr:
if (change != 0) { // vout[1]
mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), change, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up!
mtx.vout.push_back(Helper::make1of2Vout(change, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up!
}
// add marker vout:
@@ -937,7 +981,7 @@ template <typename Helper>UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee
uint8_t myprivkey[32];
char coinaddr[64];
// set priv key addresses in CC structure:
GetTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey);
Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey);
Myprivkey(myprivkey);
////fprintf(stderr,"HeirClaim() before setting unspendable CC addr2= (%s) addr3= (%s)\n", cp->unspendableaddr2, cp->unspendableaddr3);
@@ -945,9 +989,9 @@ template <typename Helper>UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee
//CCaddr3set(cp, Helper::getMyEval(), heirPubkey, myprivkey, coinaddr);
////fprintf(stderr, "HeirClaim() after setting unspendable CC addr2=(%s) addr3=(%s)\n", cp->unspendableaddr2, cp->unspendableaddr3);
CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr);
Helper::CCaddrCoinsOrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr);
// add 1of2 vout validation pubkeys:
// add 1of2 vout validation pubkeys (this is for tokens):
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(ownerPubkey);
voutTokenPubkeys.push_back(heirPubkey);
@@ -1017,15 +1061,22 @@ UniValue HeirInfo(uint256 fundingtxid)
// get initial funding tx and set it as initial lasttx:
if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) {
int32_t heirType = NOT_HEIR;
const bool noLogging = true;
uint8_t evalCodeTokens = 0;
std::vector<CPubKey> voutPubkeys;
std::vector<uint8_t> vopretExtra;
if (DecodeHeirOpRet<CoinHelper>(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging) == 'F')
heirType = HEIR_COINS;
else if (DecodeHeirOpRet<TokenHelper>(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging) == 'F')
CScript heirScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey;
int32_t heirType = HEIR_COINS;
uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra);
if (funcId != 0) {
heirScript = CScript(vopretExtra);
heirType = HEIR_TOKENS;
else
{
}
funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging);
if( funcId == 0 ) {
std::cerr << "HeirInfo() initial tx F not found for this fundingtx" << std::endl;
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "initial tx F not found"));
@@ -1033,10 +1084,7 @@ UniValue HeirInfo(uint256 fundingtxid)
}
struct CCcontract_info *cp, C;
if (heirType == HEIR_COINS)
cp = CCinit(&C, CoinHelper::getMyEval());
else
cp = CCinit(&C, TokenHelper::getMyEval());
cp = CCinit(&C, EVAL_HEIR);
uint8_t hasHeirSpendingBegun = 0;
@@ -1174,14 +1222,24 @@ template <typename Helper>void _HeirList(struct CCcontract_info *cp, UniValue &r
//std::cerr << "HeirList() checking txid=" << txid.GetHex() << " vout=" << vout << '\n';
CTransaction inittx;
if (GetTransaction(txid, inittx, hashBlock, false) != 0 && (inittx.vout.size() - 1) > 0) {
CTransaction fundingtx;
if (GetTransaction(txid, fundingtx, hashBlock, false) != 0 && (fundingtx.vout.size() - 1) > 0) {
CPubKey ownerPubkey, heirPubkey;
std::string heirName;
int64_t inactivityTimeSec;
const bool noLogging = true;
uint8_t funcId = DecodeHeirOpRet<Helper>(inittx.vout[inittx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging);
uint8_t evalCodeTokens = 0;
uint256 tokenid;
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> voutPubkeys;
CScript heirScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey;
uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra);
if (funcId != 0) {
heirScript = CScript(vopretExtra);
}
funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging);
// note: if it is not Heir token funcId would be equal to 0
if (funcId == 'F') {

View File

@@ -14,19 +14,21 @@
CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName);
CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan);
// makes token opret
CScript EncodeHeirTokensCreateOpRet(uint8_t funcid, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName);
CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector<CPubKey> voutPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan);
//CScript EncodeHeirTokensCreateOpRet(uint8_t funcid, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName);
//CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector<CPubKey> voutPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan);
template <class Helper> uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan);
template <class Helper> uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false);
template <class Helper> uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false);
uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false);
uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false);
inline static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); }
inline static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); }
// helper class to allow polymorphic behaviour for HeirXXX() functions in case of coins
class CoinHelper {
public:
static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); }
static uint8_t getMyEval() { return EVAL_HEIR; }
static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 dummyid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) {
return AddNormalinputs(mtx, ownerPubkey, total, maxinputs);
}
@@ -40,43 +42,58 @@ public:
static CScript makeClaimOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
return EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan);
}
static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); }
static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) {
return MakeCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey);
}
static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) {
return CTxOut(amount, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG);
}
static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) {
return CTxOut(amount, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG);
}
static bool GetCoinsOrTokensCCaddress1of2(struct CCcontract_info* cp, char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) {
return GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey);
}
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info* cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) {
CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr);
}
};
// helper class to allow polymorphic behaviour for HeirXXX() functions in case of tokens
class TokenHelper {
public:
static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); }
static uint8_t getMyEval() { return EVAL_TOKENS; }
static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) {
return AddTokenCCInputs(cp, mtx, ownerPubkey, tokenid, total, maxinputs);
}
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) {
return EncodeHeirTokensCreateOpRet((uint8_t)'F', tokenid, voutTokenPubkeys, ownerPubkey, heirPubkey, inactivityTimeSec, heirName);
return EncodeTokenOpRet((uint8_t)'t', EVAL_TOKENS, tokenid, voutTokenPubkeys,
EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName));
}
static CScript makeAddOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
return EncodeHeirTokensOpRet((uint8_t)'A', tokenid, voutTokenPubkeys, fundingtxid, isHeirSpendingBegan);
return EncodeTokenOpRet((uint8_t)'t', EVAL_TOKENS, tokenid, voutTokenPubkeys,
EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan));
}
static CScript makeClaimOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
return EncodeHeirTokensOpRet((uint8_t)'C', tokenid, voutTokenPubkeys, fundingtxid, isHeirSpendingBegan);
return EncodeTokenOpRet((uint8_t)'t', EVAL_TOKENS, tokenid, voutTokenPubkeys,
EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan));
}
static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); }
static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) {
return MakeTokensCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey);
}
static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) {
return MakeCC1vout(EVAL_TOKENS, amount, myPubkey);
return MakeTokensCC1vout(EVAL_HEIR, amount, myPubkey);
}
static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) {
return MakeCC1vout(EVAL_TOKENS, amount, myPubkey);
return MakeTokensCC1vout(EVAL_HEIR, amount, myPubkey);
}
static bool GetCoinsOrTokensCCaddress1of2(struct CCcontract_info* cp, char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) {
return GetTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey);
}
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info* cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) {
CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr);
}
};
@@ -307,11 +324,8 @@ public:
return eval->Invalid(stream.str().c_str()); // ... if not, return 'invalid'
}
}
ival++; // advance to the next vout
}
//std::cerr << "COutputValidationPlan::validate() returns with true" << std::endl;
return true;
}
@@ -350,14 +364,12 @@ private:
return true; // validation OK
}
private:
//std::map<int32_t, ValidatorsRow> m_mapValidators;
std::vector< std::pair<int32_t, ValidatorsRow> > m_arrayValidators;
};
class CNormalInputIdentifier : CInputIdentifierBase {
public:
CNormalInputIdentifier(CCcontract_info* cp) : CInputIdentifierBase(cp) {}
@@ -390,13 +402,28 @@ public:
virtual bool validateVout(CTxOut vout, std::string& message) const
{
//std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl;
uint8_t funcId;
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTime;
std::string heirName;
uint256 tokenid;
uint8_t evalCodeTokens = 0;
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> dummyVoutPubkeys;
if ((funcId = DecodeHeirOpRet<Helper>(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) == 0) {
CScript heirScript = m_fundingOpretScript;
if (typeid(Helper) == typeid(TokenHelper)) {
if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) {
heirScript = CScript(vopretExtra);
}
else {
message = m_customMessage + std::string(" invalid token opreturn format");
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
return false;
}
}
uint8_t funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, false);
if (funcId == 0) {
message = m_customMessage + std::string(" invalid opreturn format");
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
return false;
@@ -443,21 +470,35 @@ public:
{
//std::cerr << "CMyPubkeyVoutValidator::validateVout() entered" << std::endl;
uint8_t funcId;
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTime;
std::string heirName;
uint256 tokenid;
///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl;
uint8_t evalCodeTokens = 0;
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> dummyVoutPubkeys;
CScript ownerScript;
CScript heirScript = m_fundingOpretScript;
if (typeid(Helper) == typeid(TokenHelper)) {
if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) {
heirScript = CScript(vopretExtra);
}
else {
message = std::string("invalid token opreturn format");
return false;
}
}
// get both pubkeys:
if ((funcId = DecodeHeirOpRet<Helper>(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) == 0) {
uint8_t funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, false);
if (funcId == 0) {
message = std::string("invalid opreturn format");
return false;
}
CScript ownerScript;
CScript heirScript;
if (m_checkNormals) {
ownerScript = CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey;
heirScript = CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey;
@@ -474,7 +515,6 @@ public:
// this is vout to owner or heir addr:
//std::cerr << "CMyPubkeyVoutValidator::validateVout() exits with true" << std::endl;
return true;
}
std::cerr << "CMyPubkeyVoutValidator::validateVout() exits with false (not the owner's or heir's addresses)" << std::endl;
@@ -503,15 +543,28 @@ public:
{
//std::cerr << "CHeirSpendValidator::validateVout() entered" << std::endl;
uint8_t funcId;
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTime;
std::string heirName;
uint256 tokenid;
uint8_t evalCodeTokens = 0;
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> dummyVoutPubkeys;
CScript heirScript = m_fundingOpretScript;
if (typeid(Helper) == typeid(TokenHelper)) {
if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) {
heirScript = CScript(vopretExtra);
} else {
message = std::string("invalid token opreturn format");
return false;
}
}
// get heir pubkey:
if ((funcId = DecodeHeirOpRet<Helper>(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, false)) == 0) {
uint8_t funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, false);
if (funcId == 0) {
message = std::string("invalid opreturn format");
return false;
}
@@ -560,28 +613,54 @@ public:
{
//std::cerr << "COpRetValidator::validateVout() entered" << std::endl;
uint8_t funcId, initialFuncId; // do not check heir name
uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid, initialTokenid;
uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid;
uint8_t dummyIsHeirSpendingBegan;
if ((funcId = DecodeHeirOpRet<Helper>(vout.scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan)) == 0) {
uint8_t evalCodeTokens = 0;
std::vector<uint8_t> vopretExtra;
std::vector<CPubKey> dummyVoutPubkeys;
CScript heirScript = vout.scriptPubKey;
if (typeid(Helper) == typeid(TokenHelper)) {
if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) {
heirScript = CScript(vopretExtra);
} else {
message = std::string("invalid token opreturn format");
return false;
}
}
uint8_t funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyIsHeirSpendingBegan);
if (funcId == 0) {
message = std::string("invalid opreturn format");
return false;
}
if ((initialFuncId = DecodeHeirOpRet<Helper>(m_fundingOpretScript, initialTokenid, dummyTxid, dummyIsHeirSpendingBegan)) == 0) {
heirScript = m_fundingOpretScript;
if (typeid(Helper) == typeid(TokenHelper)) {
if (DecodeTokenOpRet(heirScript, evalCodeTokens, initialTokenid, dummyVoutPubkeys, vopretExtra) != 0) {
heirScript = CScript(vopretExtra);
} else {
message = std::string("invalid initial token opreturn format");
return false;
}
}
uint8_t initialFuncId = DecodeHeirOpRet(heirScript, dummyTxid, dummyIsHeirSpendingBegan);
if (initialFuncId == 0) {
message = std::string("invalid initial tx opreturn format");
return false;
}
// validation rules:
if (!Helper::isMyFuncId(funcId)) {
if (!isMyFuncId(funcId)) {
message = std::string("invalid funcid in opret");
return false;
}
if(tokenid != initialTokenid ) {
message = std::string("invalid tokenid in opret");
return false;
if (typeid(Helper) == typeid(TokenHelper)) {
if (tokenid != initialTokenid) {
message = std::string("invalid tokenid in opret");
return false;
}
}
std::cerr << "COpRetValidator::validateVout() exits with true" << std::endl;