Merge pull request #1196 from dimxy/heir-fix-donations

Heir fix donations
This commit is contained in:
jl777
2019-01-22 07:42:17 -11:00
committed by GitHub
6 changed files with 336 additions and 85 deletions

View File

@@ -27,10 +27,10 @@ bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,
class CoinHelper;
class TokenHelper;
UniValue HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirClaimCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount);
UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount);
UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
UniValue HeirInfo(uint256 fundingtxid);
UniValue HeirList();

View File

@@ -56,13 +56,14 @@ template <typename Helper> bool RunValidationPlans(uint8_t funcId, struct CCcont
// only for tokens:
CMyPubkeyVoutValidator<TokenHelper> ownerCCaddrValidator(cp, fundingOpretScript, false); // check if this correct owner's cc user addr corresponding to opret
COpRetValidator<Helper> opRetValidator(cp, fundingOpretScript); // compare opRets in this and last tx
CMarkerValidator<Helper> markerValidator(cp); // initial tx marker spending protection
CNullValidator<Helper> nullValidator(cp);
switch (funcId) {
case 'F': // fund tokens
case 'F': // fund tokens (only for tokens)
// vin validation plan:
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &markerValidator, &ownerCCaddrValidator); // check cc owner addr
// vout validation plan:
voutPlan.pushValidators<CValidatorBase>(0, &cc1of2ValidatorThis); // check 1of2 addr funding
@@ -70,10 +71,10 @@ template <typename Helper> bool RunValidationPlans(uint8_t funcId, struct CCcont
// no checking for opret yet
break;
case 'A': // add tokens
case 'A': // add tokens (only for tokens)
// vin validation plan:
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &markerValidator, &ownerCCaddrValidator); // check cc owner addr
// vout validation plan:
voutPlan.pushValidators<CValidatorBase>(0, &cc1of2ValidatorThis); // check 1of2 addr funding
@@ -81,10 +82,10 @@ template <typename Helper> bool RunValidationPlans(uint8_t funcId, struct CCcont
voutPlan.pushValidators<CValidatorBase>(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A:
break;
case 'C':
case 'C': // spend coins or tokens
// vin validation plan:
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &cc1of2ValidatorThis); // cc1of2 funding addr
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &markerValidator, &cc1of2ValidatorThis); // cc1of2 funding addr
// vout validation plan:
voutPlan.pushValidators<CValidatorBase>(0, &heirSpendValidator); // check if heir is allowed to spend
@@ -400,6 +401,23 @@ uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &f
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
}
// check if pubkey is in vins
void CheckVinPubkey(std::vector<CTxIn> vins, CPubKey pubkey, bool &hasPubkey, bool &hasOtherPubkey) {
hasPubkey = false;
hasOtherPubkey = false;
for (auto vin : vins) {
CPubKey vinPubkey = check_signing_pubkey(vin.scriptSig);
if (vinPubkey.IsValid()) {
if (vinPubkey == pubkey)
hasPubkey = true;
if (vinPubkey != pubkey)
hasOtherPubkey = true;
}
}
}
/**
* find the latest funding tx: it may be the first F tx or one of A or C tx's
* Note: this function is also called from validation code (use non-locking calls)
@@ -471,10 +489,20 @@ uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &toke
if (tmpFuncId != 0 && fundingtxid == fundingTxidInOpret && (tokenid == zeroid || tokenid == tokenidInOpret)) { // check tokenid also
if (blockHeight > maxBlockHeight) {
maxBlockHeight = blockHeight;
latesttxid = txid;
funcId = tmpFuncId;
hasHeirSpendingBegun = hasHeirSpendingBegunInOpret;
// check owner pubkey in vins
bool isOwner = false;
bool isNonOwner = false;
CheckVinPubkey(regtx.vin, ownerPubkey, isOwner, isNonOwner);
// we ignore 'donations' tx (with non-owner inputs) for calculating if heir is allowed to spend:
if (isOwner && !isNonOwner) {
hasHeirSpendingBegun = hasHeirSpendingBegunInOpret;
maxBlockHeight = blockHeight;
latesttxid = txid;
funcId = tmpFuncId;
}
//std::cerr << "FindLatestFundingTx() txid=" << latesttxid.GetHex() << " at blockHeight=" << maxBlockHeight
// << " opreturn type=" << (char)(funcId ? funcId : ' ') << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << " - set as current lasttxid" << '\n';
@@ -615,7 +643,7 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
* and also for setting spending plan for the funds' owner and heir
* @return fundingtxid handle for subsequent references to this heir funding plan
*/
template <typename Helper> UniValue HeirFund(uint64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid)
template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid)
{
UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -624,27 +652,33 @@ template <typename Helper> UniValue HeirFund(uint64_t txfee, int64_t amount, std
cp = CCinit(&C, Helper::getMyEval());
if (txfee == 0)
txfee = 10000;
int64_t markerfee = 10000;
//std::cerr << "HeirFund() amount=" << amount << " txfee=" << txfee << " heirPubkey IsValid()=" << heirPubkey.IsValid() << " inactivityTime(sec)=" << inactivityTimeSec << " tokenid=" << tokenid.GetHex() << std::endl;
if (!heirPubkey.IsValid()) {
std::cerr << "HeirFund() heirPubkey is not valid!" << std::endl;
return std::string("");
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid heir pubkey"));
}
CPubKey myPubkey = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { // txfee for miners
if (AddNormalinputs(mtx, myPubkey, markerfee, 3) > 0) {
int64_t inputs, change;
if ((inputs=Helper::addOwnerInputs(tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) { // 2 x txfee: 1st for marker vout, 2nd to miners
//mtx.vout.push_back(MakeTokensCC1of2vout(/*Helper::getMyEval()*/EVAL_HEIR, amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk
mtx.vout.push_back(Helper::make1of2Vout(amount, myPubkey, heirPubkey));
if ((inputs=Helper::addOwnerInputs(tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) {
mtx.vout.push_back(Helper::make1of2Vout(amount, myPubkey, heirPubkey));
// add a marker for finding all plans in HeirList()
// TODO: change marker either to cc or normal txidaddr unspendable
CPubKey heirUnspendablePubKey = GetUnspendable(cp, 0);
mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(heirUnspendablePubKey)) << OP_CHECKSIG)); // TODO: do we need this marker?
struct CCcontract_info *cpHeir, heirC;
cpHeir = CCinit(&heirC, EVAL_HEIR);
CPubKey heirUnspendablePubKey = GetUnspendable(cpHeir, 0);
// mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(heirUnspendablePubKey)) << OP_CHECKSIG)); <-- bad marker cause it was spendable by anyone
mtx.vout.push_back(MakeCC1vout(EVAL_HEIR, markerfee, heirUnspendablePubKey)); // this marker spending is disabled in the validation code
// calc and add change vout:
if (inputs > amount)
@@ -655,7 +689,20 @@ template <typename Helper> UniValue HeirFund(uint64_t txfee, int64_t amount, std
if (change != 0) { // vout[1]
mtx.vout.push_back(Helper::makeUserVout(change, myPubkey));
}
// check owner pubkey in vins
bool hasMypubkey = false;
bool hasNotMypubkey = false;
CheckVinPubkey(mtx.vin, myPubkey, hasMypubkey, hasNotMypubkey);
// for initial funding do not allow to sign by non-owner key:
if (hasNotMypubkey) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "using non-owner inputs not allowed"));
return result;
}
// add 1of2 vout validation pubkeys:
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(myPubkey);
@@ -689,12 +736,12 @@ template <typename Helper> UniValue HeirFund(uint64_t txfee, int64_t amount, std
}
// if no these callers - it could not link
UniValue HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){
return HeirFund<CoinHelper>(txfee, funds, heirName, heirPubkey, inactivityTimeSec, tokenid);
UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){
return _HeirFund<CoinHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid);
}
UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) {
return HeirFund<TokenHelper>(txfee, funds, heirName, heirPubkey, inactivityTimeSec, tokenid);
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) {
return _HeirFund<TokenHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid);
}
/**
@@ -702,7 +749,7 @@ UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName
* creates tx to add more funds to cryptocondition address for spending by either funds' owner or heir
* @return result object with raw tx or error text
*/
template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
{
UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -715,6 +762,8 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
if (txfee == 0)
txfee = 10000;
int64_t markerfee = 10000;
CPubKey myPubkey = pubkey2pk(Mypubkey());
// check if it is the owner
@@ -724,7 +773,7 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
return result;
}
if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { // txfee for miners
if (AddNormalinputs(mtx, myPubkey, markerfee, 3) > 0) { // some for marker
int64_t inputs, change;
@@ -739,7 +788,11 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
// add cryptocondition to spend this funded amount for either pk
mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey));
char markeraddr[64];
CPubKey markerPubkey = CCtxidaddr(markeraddr, fundingtxid);
mtx.vout.push_back(CTxOut(markerfee, CScript() << ParseHex(HexStr(markerPubkey)) << OP_CHECKSIG)); // marker to prevent archiving of the funds add vouts
if (inputs > amount)
change = (inputs - amount); // -txfee <-- txfee pays user
@@ -748,7 +801,29 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
if (change != 0) { // vout[1]
mtx.vout.push_back(Helper::makeUserVout(change, myPubkey));
}
// check owner pubkey in vins
bool hasMypubkey = false;
bool hasNotMypubkey = false;
CheckVinPubkey(mtx.vin, myPubkey, hasMypubkey, hasNotMypubkey);
// for additional funding do not allow to sign by both owner and non-owner keys (is this a donation or not?):
if (hasMypubkey && hasNotMypubkey) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "using both owner and non-owner inputs is not allowed"));
return result;
}
// warn the user he's making a donation if this is all non-owner keys:
if (hasNotMypubkey) {
result.push_back(Pair("result", "warning"));
result.push_back(Pair("warning", "you are about to make a donation to heir fund"));
}
else {
result.push_back(Pair("result", "success"));
}
// add 1of2 vout validation pubkeys - needed only for tokens:
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(ownerPubkey);
@@ -759,11 +834,11 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun)));
if (!rawhextx.empty()) {
result.push_back(Pair("result", "success"));
result.push_back(Pair("hextx", rawhextx));
}
else {
std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl;
result.clear();
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "sign error"));
}
@@ -781,13 +856,11 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
result.push_back(Pair("error", "can't find normal inputs for tx fee"));
}
return result;
}
UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) {
UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount) {
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTimeSec;
@@ -798,10 +871,27 @@ UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) {
uint8_t hasHeirSpendingBegun = 0;
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) {
if (tokenid == zeroid)
return _HeirAdd<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
else
return _HeirAdd<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
if (tokenid == zeroid) {
int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN);
if (amount <= 0) {
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirAdd<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
}
else {
int64_t amount = atoll(strAmount.c_str());
if (amount <= 0) {
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirAdd<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
}
}
else {
UniValue result(UniValue::VOBJ);
@@ -819,7 +909,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) {
* creates tx to spend funds from cryptocondition address by either funds' owner or heir
* @return result object with raw tx or error text
*/
template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, uint64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
{
UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -940,7 +1030,7 @@ template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, uint64_t txfe
return result;
}
UniValue HeirClaimCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) {
UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount) {
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTimeSec;
@@ -951,10 +1041,26 @@ UniValue HeirClaimCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) {
uint8_t hasHeirSpendingBegun = 0;
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) {
if( tokenid == zeroid )
return _HeirClaim<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
else
return _HeirClaim<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
if (tokenid == zeroid) {
int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN);
if (amount < 0) {
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirClaim<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
}
else {
int64_t amount = atoll(strAmount.c_str());
if (amount <= 0) {
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirClaim<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
}
}
else {
@@ -1022,6 +1128,8 @@ UniValue HeirInfo(uint256 fundingtxid)
std::ostringstream stream;
std::string msg;
//sleep(10);
result.push_back(Pair("fundingtxid", fundingtxid.GetHex()));
result.push_back(Pair("name", heirName.c_str()));
@@ -1090,19 +1198,27 @@ UniValue HeirInfo(uint256 fundingtxid)
}
stream << inactivityTimeSec;
result.push_back(Pair("inactivity time setting", stream.str().c_str()));
result.push_back(Pair("inactivity time setting, sec", stream.str().c_str()));
stream.str("");
stream.clear();
if (!hasHeirSpendingBegun) { // we do not need find duration if the spending already has begun
durationSec = CCduration(numblocks, latestFundingTxid);
std::cerr << "HeirInfo() duration=" << durationSec << " inactivityTime=" << inactivityTimeSec << " numblocks=" << numblocks << '\n';
std::cerr << "HeirInfo() duration (sec)=" << durationSec << " inactivityTime (sec)=" << inactivityTimeSec << " numblocks=" << numblocks << '\n';
}
stream << std::boolalpha << (hasHeirSpendingBegun || durationSec > inactivityTimeSec);
result.push_back(Pair("spending allowed for the heir", stream.str().c_str()));
stream.str("");
stream.clear();
// adding owner current inactivity time:
if (!hasHeirSpendingBegun && durationSec <= inactivityTimeSec) {
stream << durationSec;
result.push_back(Pair("owner inactivity time, sec", stream.str().c_str()));
stream.str("");
stream.clear();
}
result.push_back(Pair("result", "success"));
}
@@ -1123,15 +1239,15 @@ UniValue HeirInfo(uint256 fundingtxid)
* @return list of heir plan handles (fundingtxid)
*/
template <typename Helper>void _HeirList(struct CCcontract_info *cp, UniValue &result)
void _HeirList(struct CCcontract_info *cp, UniValue &result)
{
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>> unspentOutputs;
char coinaddr[64];
CPubKey ccPubKeyEmpty;
GetCCaddress(cp, coinaddr, ccPubKeyEmpty);
SetCCunspents(unspentOutputs, cp->normaladdr);
char markeraddr[64];
GetCCaddress(cp, markeraddr, GetUnspendable(cp, NULL));
SetCCunspents(unspentOutputs, markeraddr);
//std::cerr << "HeirList() finding heir marker from Heir contract addr=" << cp->normaladdr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n';
//std::cerr << "HeirList() finding heir marker from unspendable addr=" << markeraddr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n';
// TODO: move marker to special cc addr to prevent checking all tokens
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) {
@@ -1177,10 +1293,10 @@ UniValue HeirList()
struct CCcontract_info *cpHeir, *cpTokens, heirC, tokenC; // NOTE we must use a separate 'C' structure for each CCinit!
cpHeir = CCinit(&heirC, EVAL_HEIR);
cpTokens = CCinit(&tokenC, EVAL_TOKENS);
//cpTokens = CCinit(&tokenC, EVAL_TOKENS);
_HeirList<CoinHelper>(cpHeir, result);
_HeirList<TokenHelper>(cpTokens, result);
_HeirList(cpHeir, result);
//_HeirList<TokenHelper>(cpTokens, result); not used anymore
return result;
}

View File

@@ -125,8 +125,8 @@ class CValidatorBase
public:
CValidatorBase(CCcontract_info* cp) : m_cp(cp) {}
virtual bool isVinValidator() const = 0;
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const = 0;
virtual bool validateVout(CTxOut vout, std::string& message) const = 0;
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const = 0;
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const = 0;
protected:
CCcontract_info * m_cp;
@@ -258,10 +258,10 @@ private:
if (v->isVinValidator())
// validate this vin and previous vout:
result = v->validateVin(pTx->vin[iv], pPrevTx->vout[pTx->vin[iv].prevout.n], refMessage);
result = v->validateVin(pTx->vin[iv], pPrevTx->vout, pTx->vin[iv].prevout.n, refMessage);
else
// if it is vout validator pass the previous tx vout:
result = v->validateVout( pPrevTx->vout[pTx->vin[iv].prevout.n], refMessage);
result = v->validateVout( pPrevTx->vout[pTx->vin[iv].prevout.n], pTx->vin[iv].prevout.n, refMessage);
if (!result) {
return result;
}
@@ -359,7 +359,7 @@ private:
if (!v->isVinValidator()) {
// if this is a 'in' validation plan then pass the previous tx vout:
bool result = v->validateVout(pTx->vout[iv], refMessage);
bool result = v->validateVout(pTx->vout[iv], iv, refMessage);
if (!result)
return result;
}
@@ -402,7 +402,7 @@ public:
m_fundingOpretScript(opRetScript), m_customMessage(customMessage), CValidatorBase(cp) {}
virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
{
//std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl;
CPubKey ownerPubkey, heirPubkey;
@@ -438,7 +438,7 @@ public:
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
return false;
}
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return false; }
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return false; }
private:
CScript m_fundingOpretScript;
@@ -456,7 +456,7 @@ public:
: m_fundingOpretScript(opRetScript), m_checkNormals(checkNormals), CValidatorBase(cp) { }
virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
{
//std::cerr << "CMyPubkeyVoutValidator::validateVout() entered" << std::endl;
@@ -498,7 +498,7 @@ public:
message = std::string("invalid pubkey");
return false;
}
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; }
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
private:
CScript m_fundingOpretScript;
@@ -516,7 +516,7 @@ public:
: m_fundingOpretScript(opRetScript), m_latesttxid(latesttxid), m_isHeirSpendingBegan(isHeirSpendingBegan), CValidatorBase(cp) {}
virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
{
//std::cerr << "CHeirSpendValidator::validateVout() entered" << std::endl;
@@ -554,7 +554,7 @@ public:
// this is not heir:
return true;
}
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; }
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
private:
CScript m_fundingOpretScript;
@@ -572,7 +572,7 @@ public:
: m_fundingOpretScript(opret), CValidatorBase(cp) {}
virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
{
//std::cerr << "COpRetValidator::validateVout() entered" << std::endl;
@@ -607,12 +607,48 @@ public:
//std::cerr << "COpRetValidator::validateVout() exits with true" << std::endl;
return true;
}
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; }
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
private:
CScript m_fundingOpretScript;
};
/**
* marker spending prevention validator,
* returns false if for tx with funcid=F vout.1 is being tried to spend
*/
template <class Helper> class CMarkerValidator : CValidatorBase
{
public:
CMarkerValidator(CCcontract_info* cp)
: CValidatorBase(cp) { }
virtual bool isVinValidator() const { return true; } // this is vin validator
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const { return true; }
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const {
uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid;
uint8_t dummyIsHeirSpendingBegan;
//std::cerr << "CMarkerValidator::validateVin() prevVout.size()=" << prevVout.size() << " prevN=" << prevN << std::endl;
if (prevVout.size() > 0) {
// get funcId for prev tx:
uint8_t funcId = DecodeHeirEitherOpRet(prevVout[prevVout.size()-1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true);
//std::cerr << "CMarkerValidator::validateVin() funcId=" << (funcId?funcId:' ') << std::endl;
if (funcId == 'F' && prevN == 1) { // do not allow to spend 'F' marker's vout
message = std::string("spending marker not allowed");
return false;
}
}
//std::cerr << "CMarkerValidator::validateVin() exits with true" << std::endl;
return true;
}
};
/**
* empty validator always returns true
*/
@@ -623,8 +659,8 @@ public:
: CValidatorBase(cp) { }
virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const { return true; }
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; }
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const { return true; }
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
};

View File

@@ -537,6 +537,9 @@ static const CRPCCommand vRPCCommands[] =
{ "util", "reconsiderblock", &reconsiderblock, true },
/* Not shown in help */
{ "hidden", "setmocktime", &setmocktime, true },
{ "hidden", "test_ac", &test_ac, true },
{ "hidden", "test_heirmarker", &test_heirmarker, true },
#ifdef ENABLE_WALLET
/* Wallet */
{ "wallet", "resendwallettransactions", &resendwallettransactions, true},

View File

@@ -471,4 +471,8 @@ extern UniValue paxprices(const UniValue& params, bool fHelp);
extern UniValue paxdeposit(const UniValue& params, bool fHelp);
extern UniValue paxwithdraw(const UniValue& params, bool fHelp);
// test rpc:
extern UniValue test_ac(const UniValue& params, bool fHelp);
extern UniValue test_heirmarker(const UniValue& params, bool fHelp);
#endif // BITCOIN_RPCSERVER_H

View File

@@ -7362,7 +7362,7 @@ UniValue heirfund(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ);
uint256 tokenid = zeroid;
uint64_t txfee;
int64_t txfee;
int64_t amount;
int64_t inactivitytime;
std::string hex;
@@ -7373,21 +7373,34 @@ UniValue heirfund(const UniValue& params, bool fHelp)
return NullUniValue;
if (fHelp || params.size() != 5 && params.size() != 6)
throw runtime_error("heirfundtokens fee funds heirname heirpubkey inactivitytime [tokenid]\n");
throw runtime_error("heirfund txfee funds heirname heirpubkey inactivitytime [tokenid]\n");
if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txfee = atoll((char*)params[0].get_str().c_str());
amount = atoll((char*)params[1].get_str().c_str());
txfee = atoll(params[0].get_str().c_str());
if (txfee < 0)
throw runtime_error("incorrect txfee param\n");
if(params.size() == 6) // tokens in satoshis:
amount = atoll(params[1].get_str().c_str());
else // coins:
amount = atof(params[1].get_str().c_str()) * COIN;
if( amount <= 0 )
throw runtime_error("incorrect amount\n");
name = params[2].get_str();
pubkey = ParseHex(params[3].get_str().c_str());
if( !pubkey2pk(pubkey).IsValid() )
throw runtime_error("incorrect pubkey\n");
inactivitytime = atof((char*)params[4].get_str().c_str());
inactivitytime = atoll(params[4].get_str().c_str());
if (inactivitytime <= 0)
throw runtime_error("incorrect inactivity time param\n");
if (params.size() == 6) {
tokenid = Parseuint256((char*)params[5].get_str().c_str());
if(tokenid == zeroid)
@@ -7406,7 +7419,7 @@ UniValue heiradd(const UniValue& params, bool fHelp)
{
UniValue result;
uint256 fundingtxid;
uint64_t txfee;
int64_t txfee;
int64_t amount;
int64_t inactivitytime;
std::string hex;
@@ -7417,18 +7430,20 @@ UniValue heiradd(const UniValue& params, bool fHelp)
return NullUniValue;
if (fHelp || params.size() != 3)
throw runtime_error("heiraddtokens fee funds fundingtxid\n");
throw runtime_error("heiradd txfee funds fundingtxid\n");
if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txfee = atoll((char*)params[0].get_str().c_str());
amount = atoll((char*)params[1].get_str().c_str());
txfee = atoll(params[0].get_str().c_str());
if (txfee < 0)
throw runtime_error("incorrect txfee param\n");
fundingtxid = Parseuint256((char*)params[2].get_str().c_str());
result = HeirAddCaller(fundingtxid, txfee, amount);
result = HeirAddCaller(fundingtxid, txfee, params[1].get_str());
return result;
}
@@ -7437,7 +7452,6 @@ UniValue heirclaim(const UniValue& params, bool fHelp)
UniValue result; // result(UniValue::VOBJ);
uint256 fundingtxid;
int64_t txfee;
int64_t amount;
int64_t inactivitytime;
std::string hex;
std::vector<unsigned char> pubkey;
@@ -7448,18 +7462,20 @@ UniValue heirclaim(const UniValue& params, bool fHelp)
return NullUniValue;
if (fHelp || params.size() != 3)
throw runtime_error("heirclaimtokens fee funds fundingtxid\n");
throw runtime_error("heirclaim txfee funds fundingtxid\n");
if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
txfee = atoll((char*)params[0].get_str().c_str());
amount = atoll((char*)params[1].get_str().c_str());
txfee = atoll(params[0].get_str().c_str());
if (txfee < 0)
throw runtime_error("incorrect txfee param\n");
fundingtxid = Parseuint256((char*)params[2].get_str().c_str());
result = HeirClaimCaller(fundingtxid, txfee, amount);
result = HeirClaimCaller(fundingtxid, txfee, params[1].get_str());
return result;
}
@@ -7581,3 +7597,79 @@ void RegisterWalletRPCCommands(CRPCTable &tableRPC)
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
UniValue test_ac(const UniValue& params, bool fHelp)
{
// make fake token tx:
struct CCcontract_info *cp, C;
if (fHelp || (params.size() != 4))
throw runtime_error("incorrect params\n");
if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
std::vector<unsigned char> pubkey1;
std::vector<unsigned char> pubkey2;
pubkey1 = ParseHex(params[0].get_str().c_str());
pubkey2 = ParseHex(params[1].get_str().c_str());
CPubKey pk1 = pubkey2pk(pubkey1);
CPubKey pk2 = pubkey2pk(pubkey2);
if(!pk1.IsValid() || !pk2.IsValid())
throw runtime_error("invalid pubkey\n");
int64_t txfee = 10000;
int64_t amount = atoll(params[2].get_str().c_str()) * COIN;
uint256 fundingtxid = Parseuint256((char *)params[3].get_str().c_str());
CPubKey myPubkey = pubkey2pk(Mypubkey());
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
int64_t normalInputs = AddNormalinputs(mtx, myPubkey, txfee + amount, 60);
if( normalInputs < txfee + amount)
throw runtime_error("not enough normals\n");
mtx.vout.push_back(MakeCC1of2vout(EVAL_HEIR, amount, pk1, pk2));
CScript opret;
fundingtxid = revuint256(fundingtxid);
opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'A' << fundingtxid << (uint8_t)0);
cp = CCinit(&C, EVAL_HEIR);
return(FinalizeCCTx(0, cp, mtx, myPubkey, txfee, opret));
}
UniValue test_heirmarker(const UniValue& params, bool fHelp)
{
// make fake token tx:
struct CCcontract_info *cp, C;
if (fHelp || (params.size() != 1))
throw runtime_error("incorrect params\n");
if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
uint256 fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
CPubKey myPubkey = pubkey2pk(Mypubkey());
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
int64_t normalInputs = AddNormalinputs(mtx, myPubkey, 10000, 60);
if (normalInputs < 10000)
throw runtime_error("not enough normals\n");
mtx.vin.push_back(CTxIn(fundingtxid, 1));
mtx.vout.push_back(MakeCC1vout(EVAL_HEIR, 10000, myPubkey));
CScript opret;
fundingtxid = revuint256(fundingtxid);
opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'C' << fundingtxid << (uint8_t)0);
cp = CCinit(&C, EVAL_HEIR);
return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, opret));
}