diff --git a/src/cc/CCcustom.cpp b/src/cc/CCcustom.cpp index a8e9dc0a6..23213c430 100644 --- a/src/cc/CCcustom.cpp +++ b/src/cc/CCcustom.cpp @@ -232,7 +232,7 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) strcpy(cp->normaladdr,AssetsNormaladdr); strcpy(cp->CChexstr,AssetsCChexstr); memcpy(cp->CCpriv,AssetsCCpriv,32); - cp->validate = AssetsValidate; + cp->validate = CoinbaseGuardValidate; cp->ismyvin = IsAssetsInput; break; diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index d76a881fd..2c96907bb 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -196,7 +196,7 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey) strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str()); return(true); } - fprintf(stderr,"Solver for scriptPubKey failed\n%s\n", scriptPubKey.ToString()); + fprintf(stderr,"Solver for scriptPubKey failed\n%s\n", scriptPubKey.ToString().c_str()); return(false); } @@ -206,7 +206,7 @@ bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn, uint256 blockHash; bool isValid = false; - if (myGetTransaction(tx.vin[nIn].prevout.hash, txOut, blockHash)) + if (myGetTransaction(tx.vin[nIn].prevout.hash, txOut, blockHash) && txOut.vout.size() > nIn) { CBlockIndex index; if (eval->GetBlock(blockHash, index)) @@ -218,7 +218,10 @@ bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn, { // read any available parameters in the output transaction params.clear(); - tx.vout[tx.vout.size() - 1].scriptPubKey.GetOpretData(params); + if (tx.vout.size() > 0 && tx.vout[tx.vout.size() - 1].scriptPubKey.IsOpReturn()) + { + tx.vout[tx.vout.size() - 1].scriptPubKey.GetOpretData(params); + } isValid = true; } } @@ -388,8 +391,8 @@ bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector param cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0; if ( paramsNull.size() != 0 ) // Don't expect params return eval->Invalid("Cannot have params"); - else if ( ctx.vout.size() == 0 ) - return eval->Invalid("no-vouts"); + //else if ( ctx.vout.size() == 0 ) // spend can go to z-addresses + // return eval->Invalid("no-vouts"); else if ( (*cp->validate)(cp,eval,ctx,nIn) != 0 ) { //fprintf(stderr,"done CC %02x\n",cp->evalcode); diff --git a/src/cc/CoinbaseGuard.cpp b/src/cc/CoinbaseGuard.cpp index cd56987ce..7227207ae 100644 --- a/src/cc/CoinbaseGuard.cpp +++ b/src/cc/CoinbaseGuard.cpp @@ -168,8 +168,7 @@ bool ValidateStakeTransaction(const CTransaction &stakeTx, CStakeParams &stakePa if (!validateSig || VerifyScript(stakeTx.vin[0].scriptSig, srcTx.vout[stakeTx.vin[0].prevout.n].scriptPubKey, MANDATORY_SCRIPT_VERIFY_FLAGS, - TransactionSignatureChecker(&stakeTx, 0, srcTx.vout[stakeTx.vin[0].prevout.n].nValue, - PrecomputedTransactionData(stakeTx)), + ServerTransactionSignatureChecker(&stakeTx, (uint32_t)0, srcTx.vout[stakeTx.vin[0].prevout.n].nValue, false), consensusBranchId)) { return true; @@ -305,6 +304,34 @@ bool MakeCheatEvidence(CMutableTransaction &mtx, const CTransaction &ccTx, uint3 } } +typedef struct ccFulfillmentCheck { + int32_t childCount; + uint64_t fulfillmentMask; +} ccFulfillmentCheck; + +int IsCCFulfilled(CC *cc, ccFulfillmentCheck *ctx); + +// to figure out which node is signed +int CCFulfillmentVisitor(CC *cc, struct CCVisitor visitor) +{ + ccFulfillmentCheck *pfc = (ccFulfillmentCheck *)(visitor.context); + int fulfilled = cc_isFulfilled(cc); + pfc->fulfillmentMask |= (fulfilled == 0) ? 0 : ((uint64_t)1) << (uint64_t)pfc->childCount; + printf("fullfilled: %x, pfc->fulfillmentMask: %x, pfc->childCount: %d\n", fulfilled, pfc->fulfillmentMask, pfc->childCount); + pfc->childCount++; + return fulfilled; +} + +int IsCCFulfilled(CC *cc, ccFulfillmentCheck *ctx) +{ + int fulfilled = cc_isFulfilled(cc); + // printf("Root IsFulfilled: %x\n", fulfilled); + + struct CCVisitor visitor = {&CCFulfillmentVisitor, NULL, 0, (void *)ctx}; + cc_visit(cc, visitor); + return fulfilled; +} + bool CoinbaseGuardValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn) { // This also supports a variable blockstomaturity option for backward feature compatibility @@ -321,15 +348,19 @@ bool CoinbaseGuardValidate(struct CCcontract_info *cp, Eval* eval, const CTransa std::vector> params = std::vector>(); CTransaction txOut; - CC *cc = GetCryptoCondition(tx.vin[nIn].scriptSig); - - // this should reflect the truth of whether the first key did sign the fulfillment - bool signedByFirstKey = true; + bool signedByFirstKey = false; bool validCheat = false; + CC *cc = GetCryptoCondition(tx.vin[nIn].scriptSig); + if (cc) { - printf("CryptoCondition code %x\n", *cc->code); + ccFulfillmentCheck fc = {0, 0}; + IsCCFulfilled(cc, &fc); + + // this should reflect the truth of whether the first key did sign the fulfillment + signedByFirstKey = ((fc.fulfillmentMask & (uint64_t)4) != 0); + validCheat = false; // tx is the spending tx, the cc transaction comes back in txOut if (GetCCParams(eval, tx, nIn, txOut, preConditions, params)) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b4b5ed45a..13428915b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -266,12 +266,11 @@ void *chainparams_commandline(void *ptr) mainParams.consensus.nLwmaPOSAjustedWeight = 46531; } - mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = ASSETCHAINS_SAPLING; - mainParams.consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = ASSETCHAINS_OVERWINTER; - // only require coinbase protection on Verus from the Komodo family of coins if (strcmp(ASSETCHAINS_SYMBOL,"VRSC") == 0) { + mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = 227520; + mainParams.consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = 227520 - 120; mainParams.consensus.fCoinbaseMustBeProtected = true; checkpointData = //(Checkpoints::CCheckpointData) { @@ -291,6 +290,8 @@ void *chainparams_commandline(void *ptr) } else { + mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = ASSETCHAINS_SAPLING; + mainParams.consensus.vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = ASSETCHAINS_OVERWINTER; checkpointData = //(Checkpoints::CCheckpointData) { boost::assign::map_list_of diff --git a/src/cryptoconditions/Makefile.am b/src/cryptoconditions/Makefile.am index 787b11ac6..84945266a 100644 --- a/src/cryptoconditions/Makefile.am +++ b/src/cryptoconditions/Makefile.am @@ -9,7 +9,7 @@ include_HEADERS = include/cryptoconditions.h libcryptoconditions_la_SOURCES = include/cryptoconditions.h libcryptoconditions_la_LIBADD = $(CRYPTOCONDITIONS_CORE) $(LIBSECP256K1) -AM_CFLAGS = -I$(top_srcdir)/src/asn -I$(top_srcdir)/include -I$(top_srcdir)/src/include \ +AM_CFLAGS = -I$(top_srcdir)/src/asn -I./cryptoconditions/src/asn -I$(top_srcdir)/include -I$(top_srcdir)/src/include \ -Wall -Wno-pointer-sign -Wno-discarded-qualifiers LIBSECP256K1=src/include/secp256k1/libsecp256k1.la diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index 08f00a2ca..71f9cb460 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -56,8 +56,6 @@ typedef struct CC { }; } CC; - - /* * Crypto Condition Visitor */ @@ -87,6 +85,7 @@ struct CC* cc_conditionFromJSON(cJSON *params, char *err); struct CC* cc_conditionFromJSONString(const char *json, char *err); struct CC* cc_readConditionBinary(const uint8_t *cond_bin, size_t cond_bin_len); struct CC* cc_readFulfillmentBinary(const uint8_t *ffill_bin, size_t ffill_bin_len); +int cc_readFulfillmentBinaryExt(const unsigned char *ffill_bin, size_t ffill_bin_len, CC **ppcc); struct CC* cc_new(int typeId); struct cJSON* cc_conditionToJSON(const CC *cond); char* cc_conditionToJSONString(const CC *cond); diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c index 8c2b9cea6..f3214995b 100644 --- a/src/cryptoconditions/src/anon.c +++ b/src/cryptoconditions/src/anon.c @@ -55,7 +55,7 @@ static void anonToJSON(const CC *cond, cJSON *params) { static unsigned char *anonFingerprint(const CC *cond) { unsigned char *out = calloc(1, 32); - fprintf(stderr,"anon fingerprint %p %p\n",out,cond->fingerprint); + //fprintf(stderr,"anon fingerprint %p %p\n",out,cond->fingerprint); memcpy(out, cond->fingerprint, 32); return out; } diff --git a/src/cryptoconditions/src/asn/constraints.h b/src/cryptoconditions/src/asn/constraints.h index 48d49e246..a38e586c8 100644 --- a/src/cryptoconditions/src/asn/constraints.h +++ b/src/cryptoconditions/src/asn/constraints.h @@ -5,7 +5,7 @@ #ifndef ASN1_CONSTRAINTS_VALIDATOR_H #define ASN1_CONSTRAINTS_VALIDATOR_H -#include /* Platform-dependent types */ +#include "asn_system.h" /* Platform-dependent types */ #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/asn/per_support.h b/src/cryptoconditions/src/asn/per_support.h index a75ac94fc..cc470ce2f 100644 --- a/src/cryptoconditions/src/asn/per_support.h +++ b/src/cryptoconditions/src/asn/per_support.h @@ -6,7 +6,7 @@ #ifndef _PER_SUPPORT_H_ #define _PER_SUPPORT_H_ -#include /* Platform-specific types */ +#include "asn_system.h" /* Platform-specific types */ #ifdef __cplusplus extern "C" { diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index b9b08af20..11410a3ec 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -216,6 +216,35 @@ end: return cond; } +int cc_readFulfillmentBinaryExt(const unsigned char *ffill_bin, size_t ffill_bin_len, CC **ppcc) { + + int error = 0; + unsigned char *buf = calloc(1,ffill_bin_len); + Fulfillment_t *ffill = 0; + asn_dec_rval_t rval = ber_decode(0, &asn_DEF_Fulfillment, (void **)&ffill, ffill_bin, ffill_bin_len); + if (rval.code != RC_OK) { + error = rval.code; + goto end; + } + // Do malleability check + asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Fulfillment, ffill, buf, ffill_bin_len); + if (rc.encoded == -1) { + fprintf(stderr, "FULFILLMENT NOT ENCODED\n"); + error = -1; + goto end; + } + if (rc.encoded != ffill_bin_len || 0 != memcmp(ffill_bin, buf, rc.encoded)) { + error = (rc.encoded == ffill_bin_len) ? -3 : -2; + goto end; + } + + *ppcc = fulfillmentToCC(ffill); +end: + free(buf); + if (ffill) ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill); + return error; +} + int cc_visit(CC *cond, CCVisitor visitor) { int out = visitor.visit(cond, visitor); @@ -225,7 +254,6 @@ int cc_visit(CC *cond, CCVisitor visitor) { return out; } - int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength, int doHashMsg, const unsigned char *condBin, size_t condBinLength, VerifyEval verifyEval, void *evalContext) { diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 587eac221..23110724f 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1502,9 +1502,12 @@ bool verusCheckPOSBlock(int32_t slowflag, CBlock *pblock, int32_t height) { if (pblock->GetRawVerusPOSHash(rawHash, height)) { - posHash = UintToArith256(rawHash) / value; - printf("PoS block\nblkHash: %s\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n", - pblock->GetHash().GetHex().c_str(), pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value); + if (posHash > target) + { + posHash = UintToArith256(rawHash) / value; + printf("PoS block\nblkHash: %s\nnNonce: %s\nrawHash: %s\nposHash: %s\nvalue: %lu\n", + pblock->GetHash().GetHex().c_str(), pblock->nNonce.GetHex().c_str(), rawHash.GetHex().c_str(), posHash.GetHex().c_str(), value); + } } else { diff --git a/src/komodo_utils.h b/src/komodo_utils.h index afc7650d3..c80c6d4ba 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1765,8 +1765,15 @@ void komodo_args(char *argv0) if ( (ASSETCHAINS_LWMAPOS = GetArg("-ac_veruspos",0)) != 0 ) ASSETCHAINS_LWMAPOS = 50; - ASSETCHAINS_SAPLING = GetArg("-ac_sapling", 227520); - ASSETCHAINS_OVERWINTER = GetArg("-ac_overwinter", (ASSETCHAINS_SAPLING - 120) > 1 ? (ASSETCHAINS_SAPLING - 120) : 1); + ASSETCHAINS_SAPLING = GetArg("-ac_sapling", -1); + if (ASSETCHAINS_SAPLING == -1) + { + ASSETCHAINS_OVERWINTER = GetArg("-ac_overwinter", -1); + } + else + { + ASSETCHAINS_OVERWINTER = GetArg("-ac_overwinter", (ASSETCHAINS_SAPLING - 120) > 1 ? (ASSETCHAINS_SAPLING - 120) : 1); + } if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 && ASSETCHAINS_COMMISSION > 0 && ASSETCHAINS_COMMISSION <= 100000000 ) decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str()); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index c6afe15cc..b66c07771 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1354,8 +1354,9 @@ int TransactionSignatureChecker::CheckCryptoCondition( if (ffillBin.empty()) return false; - CC *cond = cc_readFulfillmentBinary((unsigned char*)ffillBin.data(), ffillBin.size()-1); - if (!cond) return -1; + CC *cond; + int error = cc_readFulfillmentBinaryExt((unsigned char*)ffillBin.data(), ffillBin.size()-1, &cond); + if (error || !cond) return -1; if (!IsSupportedCryptoCondition(cond)) return 0; if (!IsSignedCryptoCondition(cond)) return 0; @@ -1363,7 +1364,7 @@ int TransactionSignatureChecker::CheckCryptoCondition( uint256 sighash; int nHashType = ffillBin.back(); try { - sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata); + sighash = SignatureHash(CCPubKey(cond), *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata); } catch (logic_error ex) { return 0; } @@ -1391,8 +1392,8 @@ int TransactionSignatureChecker::CheckCryptoCondition( int TransactionSignatureChecker::CheckEvalCondition(const CC *cond) const { - fprintf(stderr, "Cannot check crypto-condition Eval outside of server\n"); - return 0; + //fprintf(stderr, "Cannot check crypto-condition Eval outside of server, returning true in pre-checks\n"); + return true; } diff --git a/src/script/script.cpp b/src/script/script.cpp index 891efb8b2..f3fc8311f 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -301,7 +301,7 @@ bool CScript::GetOpretData(std::vector>& vData) const { vector data; opcodetype opcode; - const_iterator pc = begin(); + CScript::const_iterator pc = this->begin(); std::vector vch1 = std::vector(1); vData.clear(); diff --git a/src/script/serverchecker.h b/src/script/serverchecker.h index 107586689..6e5bffe55 100644 --- a/src/script/serverchecker.h +++ b/src/script/serverchecker.h @@ -18,7 +18,8 @@ private: bool store; public: - ServerTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nIn, amount, txdataIn), store(storeIn) {} + ServerTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nIn, const CAmount& amount, bool storeIn, const PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nIn, amount, txdataIn), store(storeIn) {} + ServerTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nIn, const CAmount& amount, bool storeIn) : TransactionSignatureChecker(txToIn, nIn, amount), store(storeIn) {} bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; int CheckEvalCondition(const CC *cond) const; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index ffa971f82..d28e16ea6 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -43,6 +43,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, if (!cc || cc_signTreeSecp256k1Msg32(cc, key.begin(), hash.begin()) == 0) return false; vchSig = CCSigVec(cc); + return true; } else { @@ -95,20 +96,81 @@ CC *CCcond1(uint8_t evalcode,CPubKey pk) return CCNewThreshold(2, {condCC, Sig}); } +std::vector &GetCryptoConditions() +{ + static bool initialized = false; + static std::vector vCC = std::vector(); + CCcontract_info C; + + if (!initialized) + { + C.evalcode = EVAL_COINBASEGUARD; + uint8_t privKey[32] = { 0x9b, 0x17, 0x66, 0xe5, 0x82, 0x66, 0xac, 0xb6, 0xba, 0x43, 0x83, 0x74, 0xf7, 0x63, 0x11, 0x3b, 0xf0, 0xf3, 0x50, 0x6f, 0xd9, 0x6b, 0x67, 0x85, 0xf9, 0x7a, 0xf0, 0x54, 0x4d, 0xb1, 0x30, 0x77 }; + strcpy(C.unspendableCCaddr,"RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6"); + strcpy(C.normaladdr,"RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u"); + strcpy(C.CChexstr,"02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702"); + memcpy(C.CCpriv, privKey, 32); + vCC.push_back(C); + + initialized = true; + } + return vCC; +} + +bool GetCCByUnspendableAddress(struct CCcontract_info *cp, char *addrstr) +{ + std::vector &vCC = GetCryptoConditions(); + bool found = false; + + for (int i = 0; i < vCC.size(); i++) + { + if (strcmp(addrstr, vCC[i].unspendableCCaddr) == 0) + { + found = true; + *cp = vCC[i]; + break; + } + } + return found; +} + bool CCinitLite(struct CCcontract_info *cp, uint8_t evalcode) { - cp->evalcode = evalcode; - switch ( evalcode ) + std::vector &vCC = GetCryptoConditions(); + bool found = false; + + for (int i = 0; i < vCC.size(); i++) { - case EVAL_COINBASEGUARD: - uint8_t privKey[32] = { 0x9b, 0x17, 0x66, 0xe5, 0x82, 0x66, 0xac, 0xb6, 0xba, 0x43, 0x83, 0x74, 0xf7, 0x63, 0x11, 0x3b, 0xf0, 0xf3, 0x50, 0x6f, 0xd9, 0x6b, 0x67, 0x85, 0xf9, 0x7a, 0xf0, 0x54, 0x4d, 0xb1, 0x30, 0x77 }; - strcpy(cp->unspendableCCaddr,"RGKRjeTBw4LYFotSDLT6RWzMHbhXri6BG6"); - strcpy(cp->normaladdr,"RFYE2yL3KknWdHK6uNhvWacYsCUtwzjY3u"); - strcpy(cp->CChexstr,"02adf84e0e075cf90868bd4e3d34a03420e034719649c41f371fc70d8e33aa2702"); - memcpy(cp->CCpriv, privKey,32); - return true; + if (vCC[i].evalcode == evalcode) + { + found = true; + *cp = vCC[i]; + break; + } } - return false; + return found; +} + +bool _Getscriptaddress(char *destaddr, const CScript &scriptPubKey) +{ + CTxDestination address; + txnouttype whichType; + std::vector> vvch = std::vector>(); + if (Solver(scriptPubKey, whichType, vvch) && vvch[0].size() == 20) + { + address = CKeyID(uint160(vvch[0])); + strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str()); + return(true); + } + fprintf(stderr,"Solver for scriptPubKey failed\n%s\n", scriptPubKey.ToString().c_str()); + return(false); +} + +CScript _CCPubKey(const CC *cond) +{ + unsigned char buf[1000]; + size_t len = cc_conditionBinary(cond, buf); + return CScript() << std::vector(buf, buf+len) << OP_CHECKCRYPTOCONDITION; } static bool SignStepCC(const BaseSignatureCreator& creator, const CScript& scriptPubKey, vector &vSolutions, @@ -116,150 +178,101 @@ static bool SignStepCC(const BaseSignatureCreator& creator, const CScript& scrip { CScript subScript; vector vPK; - vector vKeyID = vector(); vector vParams = vector(); COptCCParams p; + // get information to sign with + CCcontract_info C; + scriptPubKey.IsPayToCryptoCondition(&subScript, vParams); - if (vParams.size() > 1 && (p = COptCCParams(vParams[0])).IsValid()) + if (vParams.empty()) + { + // get the keyID address of the cc and if it is an unspendable cc address, use its pubkey + // we have nothing else + char addr[64]; + if (_Getscriptaddress(addr, subScript) && GetCCByUnspendableAddress(&C, addr)) + { + vPK.push_back(CPubKey(ParseHex(C.CChexstr))); + p = COptCCParams(p.VERSION, C.evalcode, 1, 1, vPK, vParams); + } + } + else + { + p = COptCCParams(vParams[0]); + } + + if (p.IsValid() && p.vKeys.size() >= p.n) { bool is1of2 = (p.m == 1 && p.n == 2); - uint32_t extraAddrs = p.n; CKey privKey; - // get information to sign with - CCcontract_info C; - // must be a valid cc eval code if (CCinitLite(&C, p.evalCode)) { // pay to cc address is a valid tx if (!is1of2) { - try - { - if (!extraAddrs) - { - vKeyID.push_back(CKeyID(uint160(vSolutions[0]))); - // if this isn't our main CC address, we can't do anything with it - if (strcmp(C.unspendableCCaddr, CBitcoinAddress(CTxDestination(vKeyID[0])).ToString().c_str()) != 0) - return false; - - // otherwise, push back the corresponding pub key - vPK.push_back(CPubKey(ParseHex(C.CChexstr))); - } - else if (vParams.size() > extraAddrs) - { - bool havePriv; - vKeyID.push_back(CKeyID(uint160(vParams[1]))); - // if this isn't the normal CC address and we also don't have it in our keystore, fail - CBitcoinAddress addr = CBitcoinAddress(CTxDestination(vKeyID[0])); - if (strcmp(C.normaladdr, addr.ToString().c_str()) == 0 && - !(havePriv = creator.KeyStore().GetKey(vKeyID[0], privKey))) - return false; + bool havePriv = creator.KeyStore().GetKey(p.vKeys[0].GetID(), privKey); - vPK.push_back(CPubKey()); - - // if we don't have the private key, it is the unspendable address - if (!havePriv) - { - vPK[0] = CPubKey(ParseHex(C.CChexstr)); - privKey = CKey(); - CPrivKey vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv)); - privKey.SetPrivKey(vch, false); - } - else if (!creator.KeyStore().GetPubKey(vKeyID[0], vPK[0])) - return false; - } - } catch (...) + // if we don't have the private key, it must be the unspendable address + if (!havePriv && (p.vKeys[0] == CPubKey(ParseHex(C.CChexstr)))) { - fprintf(stderr,"exception calculating 1of1 spend\n"); - return false; + privKey = CKey(); + CPrivKey vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv)); + privKey.SetPrivKey(vch, false); } + else return false; - CC *cc = CCcond1(p.evalCode, vPK[0]); + CC *cc = CCcond1(p.evalCode, p.vKeys[0]); if (cc) { vector vch; - if (creator.CreateSig(vch, vKeyID[0], scriptPubKey, consensusBranchId, &privKey, (void *)cc)) + if (creator.CreateSig(vch, p.vKeys[0].GetID(), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc)) { ret.push_back(vch); } else { - fprintf(stderr,"vin has 1of1 CC signing error with address.(%s)\n", vKeyID[0].ToString().c_str()); + fprintf(stderr,"vin has 1of1 CC signing error with address.(%s)\n", p.vKeys[0].GetID().ToString().c_str()); } cc_free(cc); return ret.size() != 0; } } - else if (extraAddrs > 1 && vParams.size() > extraAddrs) + else { - // we need to get 2 addresses, and we will need the private key for one - // to spend - bool pkValid = false; - for (int i = 0; i < extraAddrs; i++) + // first of priv key in our key store or contract address is what we sign with + for (auto pk : p.vKeys) { - // loop through in order and choose the first key we have a priv key to for signing - try + if (creator.KeyStore().GetKey(p.vKeys[0].GetID(), privKey) && privKey.IsValid()) + break; + + if (p.vKeys[0] == CPubKey(ParseHex(C.CChexstr))) { - bool isCCAddr = false; - CPubKey pk; - vKeyID.push_back(CKeyID(uint160(vParams[i + 1]))); - - // if this isn't the CC address and we also don't have the pubkey in our keystore, fail, because we won't - // be able to make the condition to fulfill - if (!(isCCAddr = (strcmp(C.normaladdr, CBitcoinAddress(CTxDestination(vKeyID[0])).ToString().c_str()) == 0)) && - !creator.KeyStore().GetPubKey(vKeyID[0], pk)) - return false; - - if (isCCAddr) - { - pk = CPubKey(ParseHex(C.CChexstr)); - // only set the private key to this address if we don't have one yet - if (!pkValid) - { - privKey = CKey(); - CPrivKey vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv)); - privKey.SetPrivKey(vch, false); - pkValid = true; - } - } - else - { - if (!pkValid) - { - if (creator.KeyStore().GetKey(vKeyID[0], privKey)) - pkValid = true; - } - } - - vPK.push_back(pk); - - } catch (...) - { - fprintf(stderr,"exception calculating 1of2 spend\n"); - return false; + privKey = CKey(); + CPrivKey vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv)); + privKey.SetPrivKey(vch, false); + break; } } - if (!pkValid) + if (!privKey.IsValid()) return false; - CC *cc = CCcond1of2(p.evalCode, vPK[0], vPK[1]); + CC *cc = CCcond1of2(p.evalCode, p.vKeys[0], p.vKeys[1]); if (cc) { vector vch; - if (creator.CreateSig(vch, vKeyID[0], scriptPubKey, consensusBranchId, &privKey, (void *)cc)) + if (creator.CreateSig(vch, p.vKeys[0].GetID(), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc)) { ret.push_back(vch); } else { - fprintf(stderr,"vin has 1of2 CC signing error with address.(%s)\n", vKeyID[0].ToString().c_str()); + fprintf(stderr,"vin has 1of2 CC signing error with addresses.(%s)\n(%s)\n", p.vKeys[0].GetID().ToString().c_str(), p.vKeys[1].GetID().ToString().c_str()); } cc_free(cc); @@ -524,6 +537,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature return sigs2; case TX_PUBKEY: case TX_PUBKEYHASH: + case TX_CRYPTOCONDITION: // Signatures are bigger than placeholders or empty scripts: if (sigs1.script.empty() || sigs1.script[0].empty()) return sigs2;