// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://www.opensource.org/licenses/mit-license.php .
#include "script/sign.h"
#include "uint256.h"
#include "cc/CCinclude.h"
#include "cc/eval.h"
+#include "key_io.h"
+#include "pbaas/identity.h"
#include <boost/foreach.hpp>
typedef std::vector<unsigned char> valtype;
-TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
+TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const CScript &scriptPubKey, uint32_t spendHeight, int nHashTypeIn)
+ : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn, &scriptPubKey, keystoreIn, spendHeight) {}
-bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId, CKey *pprivKey, void *extraData) const
+TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn)
+ : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
+
+bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char> &vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId, CKey *pprivKey, void *extraData) const
{
CKey key;
if (pprivKey)
return false;
}
- if (scriptCode.IsPayToCryptoCondition())
+ COptCCParams p;
+ if (scriptCode.IsPayToCryptoCondition(p))
{
- CC *cc = (CC *)extraData;
- // assume either 1of1 or 1of2. if the condition created by the
- if (!cc || cc_signTreeSecp256k1Msg32(cc, key.begin(), hash.begin()) == 0)
- return false;
- vchSig = CCSigVec(cc);
+ if (p.IsValid() && p.version >= p.VERSION_V3)
+ {
+ CSmartTransactionSignatures signatures(nHashType, std::map<uint160, CSmartTransactionSignature>());
+ if (vchSig.size())
+ {
+ signatures = CSmartTransactionSignatures(vchSig);
+ if (!signatures.IsValid())
+ {
+ return false;
+ }
+ }
+ unsigned char *onesig;
+ if (!cc_MakeSecp256k1Signature(hash.begin(), key.begin(), &onesig))
+ {
+ return false;
+ }
+ CSmartTransactionSignature signature(CSmartTransactionSignature::SIGTYPE_SECP256K1, key.GetPubKey(), std::vector<unsigned char>(onesig, onesig + CSmartTransactionSignature::SIGTYPE_SECP256K1_LEN));
+ free(onesig);
+ signatures.AddSignature(signature);
+ vchSig = signatures.AsVector();
+
+
+ /*
+ printf("signatures: %s\n", signatures.ToUniValue().write().c_str());
+ CC *cc = (CC *)extraData;
+ if (!cc || cc_signTreeSecp256k1Msg32(cc, key.begin(), hash.begin()) == 0)
+ return false;
+ char *jsonCondStr = cc_conditionToJSONString(cc);
+ if (jsonCondStr)
+ {
+ printf("Signed condition: %s\n", jsonCondStr);
+ cJSON_free(jsonCondStr);
+ }
+ */
+ }
+ else
+ {
+ CC *cc = (CC *)extraData;
+
+ if (!cc || cc_signTreeSecp256k1Msg32(cc, key.begin(), hash.begin()) == 0)
+ return false;
+ vchSig = CCSigVec(cc);
+ }
return true;
}
else
return CCNewThreshold(2, {condCC, Sig});
}
-std::vector<CCcontract_info> &GetCryptoConditions()
+CC *CCcond1(uint8_t evalcode, CTxDestination dest)
{
- static bool initialized = false;
- static std::vector<CCcontract_info> vCC = std::vector<CCcontract_info>();
- CCcontract_info C;
-
- if (!initialized)
+ CPubKey pk = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
+ std::vector<CC*> pks;
+ if (pk.IsValid())
{
- C.evalcode = EVAL_STAKEGUARD;
- 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;
+ pks.push_back(CCNewSecp256k1(pk));
+ }
+ else
+ {
+ pks.push_back(CCNewHashedSecp256k1(CKeyID(GetDestinationID(dest))));
}
- return vCC;
+ CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
+ CC *Sig = CCNewThreshold(1, pks);
+ return CCNewThreshold(2, {condCC, Sig});
}
-bool GetCCByUnspendableAddress(struct CCcontract_info *cp, char *addrstr)
+CC *CCcondAny(uint8_t evalcode, std::vector<CTxDestination> dests)
{
- std::vector<CCcontract_info> &vCC = GetCryptoConditions();
- bool found = false;
+ std::vector<CC*> pks;
+ for (auto dest : dests)
+ {
+ CPubKey pk = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
+ if (pk.IsValid())
+ {
+ pks.push_back(CCNewSecp256k1(pk));
+ }
+ else
+ {
+ pks.push_back(CCNewHashedSecp256k1(CKeyID(GetDestinationID(dest))));
+ }
+ }
+
+ CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
+ CC *Sig = CCNewThreshold(1, pks);
+ return CCNewThreshold(2, {condCC, Sig});
+}
- for (int i = 0; i < vCC.size(); i++)
+CC *MakeCCcondMofN(uint8_t evalcode, const std::vector<CTxDestination> &dests, int M)
+{
+ std::vector<CC*> pks;
+ for (auto dest : dests)
{
- if (strcmp(addrstr, vCC[i].unspendableCCaddr) == 0)
+ CPubKey pk = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
+ if (pk.IsValid())
+ {
+ pks.push_back(CCNewSecp256k1(pk));
+ }
+ else
{
- found = true;
- *cp = vCC[i];
- break;
+ pks.push_back(CCNewHashedSecp256k1(CKeyID(GetDestinationID(dest))));
}
}
- return found;
+
+ if (M > pks.size())
+ {
+ M = pks.size();
+ }
+
+ CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
+ CC *Sig = CCNewThreshold(M, pks);
+ return CCNewThreshold(2, {condCC, Sig});
}
-bool CCinitLite(struct CCcontract_info *cp, uint8_t evalcode)
+CC *MakeCCcondOneSig(const CTxDestination &dest)
{
- std::vector<CCcontract_info> &vCC = GetCryptoConditions();
- bool found = false;
+ //printf("making condition with ID: %s\n", GetDestinationID(dest).GetHex().c_str());
+
+ CPubKey pk = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
+ if (pk.IsValid())
+ {
+ return CCNewSecp256k1(pk);
+ }
+ else
+ {
+ return CCNewHashedSecp256k1(CKeyID(GetDestinationID(dest)));
+ }
+}
- for (int i = 0; i < vCC.size(); i++)
+CC *MakeCCcondMofN(const std::vector<CTxDestination> &dests, int M)
+{
+ std::vector<CC*> pks;
+ for (auto dest : dests)
{
- if (vCC[i].evalcode == evalcode)
+ pks.push_back(MakeCCcondOneSig(dest));
+ if (!pks.back())
{
- found = true;
- *cp = vCC[i];
- break;
+ pks.pop_back();
}
}
- return found;
+
+ if (M > pks.size())
+ {
+ M = pks.size();
+ }
+ return CCNewThreshold(M, pks);
}
-bool _Getscriptaddress(char *destaddr, const CScript &scriptPubKey)
+CC *MakeCCcondMofN(const std::vector<CC*> &conditions, int M)
{
- CTxDestination address;
- txnouttype whichType;
- std::vector<std::vector<unsigned char>> vvch = std::vector<std::vector<unsigned char>>();
- if (Solver(scriptPubKey, whichType, vvch) && vvch[0].size() == 20)
+ if (M > conditions.size())
{
- address = CKeyID(uint160(vvch[0]));
- strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str());
- return(true);
+ M = conditions.size();
}
- fprintf(stderr,"Solver for scriptPubKey failed\n%s\n", scriptPubKey.ToString().c_str());
- return(false);
+
+ return CCNewThreshold(M, conditions);
+}
+
+CC *MakeCCcondMofN(uint8_t evalcode, const std::vector<CC*> &conditions, int M)
+{
+ if (evalcode == EVAL_NONE)
+ {
+ return MakeCCcondMofN(conditions, M);
+ }
+
+ if (M > conditions.size())
+ {
+ M = conditions.size();
+ }
+
+ CC *condCC = CCNewEval(E_MARSHAL(ss << evalcode));
+ CC *Sig = CCNewThreshold(M, conditions);
+ return CCNewThreshold(2, {condCC, Sig});
+}
+
+// TOBJ is CConditionObj of a CC output type
+template <typename TOBJ>
+CC *MakeMofNCC(TOBJ &conditionObj)
+{
+ return MakeCCcondMofN(conditionObj.evalCode, conditionObj.dests, conditionObj.m);
+}
+
+template <typename TOBJ1, typename TOBJ2>
+CC *MakeMofNCC(int M, TOBJ1 &condition1, TOBJ2 &condition2)
+{
+ if (M > 2) M = 2;
+ std::vector<CC*> conditions({MakeCCcondMofN(condition1.evalCode, condition1.dests, condition1.m), MakeCCcondMofN(condition2.evalCode, condition2.dests, condition2.m)});
+ return CCNewThreshold(M, conditions);
+}
+
+template <typename TOBJ1, typename TOBJ2, typename TOBJ3>
+CC *MakeMofNCC(int M, TOBJ1 &condition1, TOBJ2 &condition2, TOBJ3 &condition3)
+{
+ if (M > 3) M = 3;
+ std::vector<CC*> conditions({MakeCCcondMofN(condition1.evalCode, condition1.dests, condition1.m), MakeCCcondMofN(condition2.evalCode, condition2.dests, condition2.m), MakeCCcondMofN(condition3.evalCode, condition3.dests, condition3.m)});
+ return CCNewThreshold(M, conditions);
+}
+
+template <typename TOBJ1, typename TOBJ2, typename TOBJ3, typename TOBJ4>
+CC *MakeMofNCC(int M, TOBJ1 &condition1, TOBJ2 &condition2, TOBJ3 &condition3, TOBJ4 &condition4)
+{
+ if (M > 4) M = 4;
+ std::vector<CC*> conditions({MakeCCcondMofN(condition1.evalCode, condition1.dests, condition1.m),
+ MakeCCcondMofN(condition2.evalCode, condition2.dests, condition2.m),
+ MakeCCcondMofN(condition3.evalCode, condition3.dests, condition3.m),
+ MakeCCcondMofN(condition4.evalCode, condition4.dests, condition4.m)});
+ return CCNewThreshold(M, conditions);
}
CScript _CCPubKey(const CC *cond)
{
- unsigned char buf[1000];
- size_t len = cc_conditionBinary(cond, buf);
+ unsigned char buf[2000];
+ size_t len = cc_conditionBinary(cond, buf, 2000);
return CScript() << std::vector<unsigned char>(buf, buf+len) << OP_CHECKCRYPTOCONDITION;
}
+CIdentity LookupIdentity(const BaseSignatureCreator& creator, const CIdentityID &idID)
+{
+ std::pair<CIdentityMapKey, CIdentityMapValue> identity;
+ COptCCParams p;
+ //printf("Looking up %s identity\n", EncodeDestination(CTxDestination(idID)).c_str());
+ if (creator.IsKeystoreValid() &&
+ creator.KeyStore().GetIdentity(idID, identity) &&
+ identity.second.IsValidUnrevoked())
+ {
+ return identity.second;
+ }
+ return CIdentity();
+}
+
static bool SignStepCC(const BaseSignatureCreator& creator, const CScript& scriptPubKey, vector<valtype> &vSolutions,
vector<valtype>& ret, uint32_t consensusBranchId)
{
CScript subScript;
- vector<CPubKey> vPK;
- vector<valtype> vParams = vector<valtype>();
+ std::vector<CTxDestination> vPK;
+ std::vector<valtype> vParams = std::vector<valtype>();
COptCCParams p;
// get information to sign with
CCcontract_info C;
- scriptPubKey.IsPayToCryptoCondition(&subScript, vParams);
- if (vParams.empty())
+ if (scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid() && p.n >= 1 && p.vKeys.size() >= p.n)
{
- // 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))
+ if (p.version >= p.VERSION_V3 && p.vData.size())
{
- vPK.push_back(CPubKey(ParseHex(C.CChexstr)));
- p = COptCCParams(p.VERSION, C.evalcode, 1, 1, vPK, vParams);
- }
- }
- else
- {
- p = COptCCParams(vParams[0]);
- }
+ // decode the entire crypto-condition
+ COptCCParams master = COptCCParams(p.vData.back());
+ bool ccValid = master.IsValid();
+ std::vector<CConditionObj<COptCCParams>> conditions;
+ std::map<uint160, CTxDestination> destMap; // all destinations
+ std::map<uint160, CKey> privKeyMap; // private keys located for each id
+ std::vector<CC*> ccs;
+
+ CIdentity identity;
+ bool identitySpend = false;
+ uint160 idID;
+ if (p.evalCode == EVAL_IDENTITY_PRIMARY)
+ {
+ identity = CIdentity(p.vData[0]);
+ identitySpend = identity.IsValid();
+ idID = identity.GetID();
+ }
- if (p.IsValid() && p.vKeys.size() >= p.n)
- {
- bool is1of2 = (p.m == 1 && p.n == 2);
- CKey privKey;
+ // if we are sign-only, "p" will have no data object of its own, so we do not have to subtract 1
+ int loopMax = p.evalCode ? p.vData.size() - 1 : p.vData.size();
- // must be a valid cc eval code
- if (CCinitLite(&C, p.evalCode))
- {
- // pay to cc address is a valid tx
- if (!is1of2)
+ for (int i = 0; ccValid && i < loopMax; i++)
{
- bool havePriv = creator.KeyStore().GetKey(p.vKeys[0].GetID(), privKey);
-
- // if we don't have the private key, it must be the unspendable address
- if (!havePriv && (p.vKeys[0] == CPubKey(ParseHex(C.CChexstr))))
+ // "p", our first COptCCParams object will be considered first, then nested objects after
+ COptCCParams oneP = i ? COptCCParams(p.vData[i]) : p;
+ ccValid = oneP.IsValid();
+ std::vector<CC*> vCC;
+ if (ccValid)
{
- privKey = CKey();
- std::vector<unsigned char> vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv));
- privKey.Set(vch.begin(), vch.end(), false);
+ conditions.push_back(CConditionObj<COptCCParams>(oneP.evalCode, oneP.vKeys, oneP.m));
+
+ CCcontract_info C;
+ if (p.evalCode && CCinit(&C, p.evalCode))
+ {
+ CPubKey evalPK(ParseHex(C.CChexstr));
+ CKey priv;
+ std::vector<unsigned char> vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv));
+ priv.Set(vch.begin(), vch.end(), true);
+ privKeyMap[evalPK.GetID()] = priv;
+ }
+ else
+ {
+ if (p.evalCode)
+ {
+ return false;
+ }
+ }
+
+ for (auto &dest : oneP.vKeys)
+ {
+ uint160 destId = GetDestinationID(dest);
+ if (dest.which() == COptCCParams::ADDRTYPE_ID)
+ {
+ // lookup identity, we must have all registered target identity scripts in our keystore, or we try as if they are a keyID, which will be the same
+ // if revoked or undefined
+ CIdentity id;
+
+ // if this is an identity self spend, we always use the absolute latest version to control it ,mcf
+ if (destId == idID)
+ {
+ id = identity;
+ }
+
+ if ((!id.IsValid() && !(id = LookupIdentity(creator, CIdentityID(destId))).IsValid()) || id.IsRevoked())
+ {
+ destMap[destId] = dest;
+ vCC.push_back(MakeCCcondOneSig(CKeyID(GetDestinationID(dest))));
+ }
+ else
+ {
+ for (auto oneKey : id.primaryAddresses)
+ {
+ destMap[GetDestinationID(oneKey)] = oneKey;
+ }
+ if (id.primaryAddresses.size() == 1)
+ {
+ vCC.push_back(MakeCCcondOneSig(CKeyID(GetDestinationID(id.primaryAddresses[0]))));
+ }
+ else
+ {
+ vCC.push_back(MakeCCcondMofN(id.primaryAddresses, id.minSigs));
+ }
+ }
+ }
+ else
+ {
+ destMap[destId] = dest;
+ vCC.push_back(MakeCCcondOneSig(dest));
+ }
+ }
+
+ if (oneP.evalCode != EVAL_NONE)
+ {
+ ccs.push_back(MakeCCcondMofN(oneP.evalCode, vCC, oneP.m ? oneP.m : 1));
+ }
+ else
+ {
+ if (vCC.size() == 1)
+ {
+ ccs.push_back(vCC[0]);
+ }
+ else
+ {
+ ccs.push_back(MakeCCcondMofN(vCC, oneP.m));
+ }
+ }
}
+ }
- CC *cc = CCcond1(p.evalCode, p.vKeys[0]);
+ CC *outputCC = nullptr;
- if (cc)
+ if (ccValid)
+ {
+ assert(ccs.size() == conditions.size());
+ if (ccs.size() == 1)
{
- vector<unsigned char> vch;
- if (creator.CreateSig(vch, p.vKeys[0].GetID(), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc))
+ if (master.evalCode)
{
- ret.push_back(vch);
+ outputCC = MakeCCcondMofN(master.evalCode, ccs, master.m);
}
else
{
- fprintf(stderr,"vin has 1of1 CC signing error with address.(%s)\n", p.vKeys[0].GetID().ToString().c_str());
+ outputCC = ccs[0];
+ }
+ }
+ else
+ {
+ if (master.evalCode)
+ {
+ outputCC = MakeCCcondMofN(master.evalCode, ccs, master.m);
}
+ else
+ {
+ outputCC = MakeCCcondMofN(ccs, master.m);
+ }
+ }
+ }
+
+ // loop through all private keys we have and sign with each of them
+ if (outputCC)
+ {
+ // loop through keys and sign with all that we have
+ std::map<CKeyID, CKey> privKeys;
+ for (auto destPair : destMap)
+ {
+ //printf("Checking for private key of destination: %s ", EncodeDestination(destPair.second).c_str());
+
+ CKey privKey;
+ auto dit = privKeyMap.find(destPair.first);
+ if (dit != privKeyMap.end())
+ {
+ privKeys[dit->first] = dit->second;
+ //printf("...using key for crypto condition\n");
+ }
+ else if (creator.IsKeystoreValid() && creator.KeyStore().GetKey(destPair.first, privKey))
+ {
+ privKeys[destPair.first] = privKey;
+ //printf("...using key from wallet\n");
+ }
+ }
- cc_free(cc);
- return ret.size() != 0;
+ vector<unsigned char> vch = ret.size() ? ret[0] : vector<unsigned char>();
+ bool error = false;
+ CScript signScript = _CCPubKey(outputCC);
+ // loop and sign
+ for (auto privKey : privKeys)
+ {
+ // if we have an error or can't sign and it isn't fulfilled, fail, if we have no error, can't sign again, and we have a fulfilled sig, it must be optimized and OK
+ if (error || (!creator.CreateSig(vch, privKey.first, scriptPubKey, consensusBranchId, &privKey.second, (void *)outputCC)))
+ {
+ error = true;
+ //CPubKey errKey = privKey.second.GetPubKey();
+ //fprintf(stderr,"vin has MofN CC signing error with pubkey: %s, ID: %s\n", HexBytes(&(std::vector<unsigned char>(errKey.begin(), errKey.end())[0]), errKey.size()).c_str(), errKey.GetID().GetHex().c_str());
+ }
+ }
+
+ if (!error && vch.size())
+ {
+ ret.push_back(vch);
}
+
+ cc_free(outputCC);
+ return !error && ret.size() != 0;
}
- else
+ }
+ else
+ {
+ bool is0ofAny = (p.m == 0 && p.n >= 1);
+ bool is1ofn = (p.m == 1 && p.n >= 2);
+ CKey privKey;
+
+ // must be a valid cc eval code
+ if (CCinit(&C, p.evalCode))
{
- // first of priv key in our key store or contract address is what we sign with
- for (auto pk : p.vKeys)
+ // pay to cc address is a valid tx
+ if (is0ofAny)
{
- if (creator.KeyStore().GetKey(pk.GetID(), privKey) && privKey.IsValid())
- break;
+ CPubKey pubk = CPubKey(ParseHex(C.CChexstr));
+ CKeyID keyID = pubk.GetID();
+ bool havePriv = false;
- if (pk == CPubKey(ParseHex(C.CChexstr)))
+ // loop through and sign with the first of either the private key or a match on the CCs private key, otherwise, fail
+ for (auto dest : p.vKeys)
+ {
+ uint160 keyID = GetDestinationID(dest);
+ if (creator.IsKeystoreValid() && creator.KeyStore().GetKey(keyID, privKey))
+ {
+ havePriv = true;
+ break;
+ }
+ CPubKey tempPub = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), dest);
+ if ((tempPub.IsValid() && tempPub == pubk) || (keyID == tempPub.GetID()))
+ {
+ // found the pub key for this crypto condition, so use the private key
+ std::vector<unsigned char> vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv));
+ privKey.Set(vch.begin(), vch.end(), true);
+ havePriv = true;
+ break;
+ }
+ }
+
+ if (!havePriv)
+ {
+ fprintf(stderr,"Do not have or cannot locate private key for %s\n", EncodeDestination(p.vKeys[0]).c_str());
+ return false;
+ }
+
+ CC *cc = CCcondAny(p.evalCode, p.vKeys);
+
+ if (cc)
+ {
+ vector<unsigned char> vch;
+ if (creator.CreateSig(vch, GetDestinationID(p.vKeys[0]), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc))
+ {
+ ret.push_back(vch);
+ }
+ else
+ {
+ fprintf(stderr,"vin has 1ofAny CC signing error with address.(%s)\n", EncodeDestination(p.vKeys[0]).c_str());
+ }
+
+ cc_free(cc);
+ return ret.size() != 0;
+ }
+ }
+ else if (!is1ofn)
+ {
+ uint160 keyID = GetDestinationID(p.vKeys[0]);
+ bool havePriv = creator.IsKeystoreValid() && creator.KeyStore().GetKey(keyID, privKey);
+ CPubKey pubk;
+
+ // if we don't have the private key, it must be the unspendable address
+ if (havePriv)
+ {
+ std::vector<unsigned char> vkch = GetDestinationBytes(p.vKeys[0]);
+ if (vkch.size() == 33)
+ {
+ pubk = CPubKey(vkch);
+ }
+ else
+ {
+ creator.KeyStore().GetPubKey(keyID, pubk);
+ }
+ }
+ else
{
privKey = CKey();
std::vector<unsigned char> vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv));
- privKey.Set(vch.begin(), vch.end(), false);
- break;
+
+ privKey.Set(vch.begin(), vch.end(), true);
+ pubk = CPubKey(ParseHex(C.CChexstr));
+ }
+
+ CC *cc = CCcond1(p.evalCode, pubk);
+
+ if (cc)
+ {
+ vector<unsigned char> vch;
+ if (creator.CreateSig(vch, GetDestinationID(p.vKeys[0]), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc))
+ {
+ ret.push_back(vch);
+ }
+ else
+ {
+ fprintf(stderr,"vin has 1of1 CC signing error with address.(%s)\n", keyID.ToString().c_str());
+ }
+
+ cc_free(cc);
+ return ret.size() != 0;
}
}
+ else
+ {
+ // first of priv key in our key store or contract address is what we sign with if we have it
+ std::vector<CPubKey> keys;
+ for (auto pk : p.vKeys)
+ {
+ uint160 keyID = GetDestinationID(pk);
+ CPubKey foundKey;
+ if (!(creator.IsKeystoreValid() && creator.KeyStore().GetPubKey(keyID, foundKey)))
+ {
+ std::vector<unsigned char> vkch = GetDestinationBytes(pk);
+ if (vkch.size() == 33)
+ {
+ foundKey = CPubKey(vkch);
+ }
+ }
+
+ if (foundKey.IsFullyValid())
+ {
+ keys.push_back(foundKey);
+ }
+ }
- if (!privKey.IsValid())
- return false;
+ // if we only have one key, and this is version 2, add the cc pub key
+ if (keys.size() <= 1 && p.version == p.VERSION_V2)
+ {
+ keys.push_back(CPubKey(ParseHex(C.CChexstr)));
+ }
+
+ // we need something to sign with
+ if (!keys.size())
+ {
+ return false;
+ }
- CC *cc = CCcond1of2(p.evalCode, p.vKeys[0], p.vKeys[1]);
+ for (auto pk : keys)
+ {
+ if (creator.IsKeystoreValid() && creator.KeyStore().GetKey(pk.GetID(), privKey) && privKey.IsValid())
+ {
+ break;
+ }
+
+ if (pk == CPubKey(ParseHex(C.CChexstr)))
+ {
+ privKey = CKey();
+ std::vector<unsigned char> vch(&(C.CCpriv[0]), C.CCpriv + sizeof(C.CCpriv));
+ privKey.Set(vch.begin(), vch.end(), true);
+ break;
+ }
+ }
- if (cc)
- {
- vector<unsigned char> vch;
- if (creator.CreateSig(vch, p.vKeys[0].GetID(), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc))
+ if (!privKey.IsValid())
+ return false;
+
+ CC *cc;
+ if (keys.size() > 1)
{
- ret.push_back(vch);
+ cc = CCcond1of2(p.evalCode, keys[0], keys[1]);
}
else
{
- 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 = CCcond1(p.evalCode, keys[0]);
}
- cc_free(cc);
- return ret.size() != 0;
+ if (cc)
+ {
+ vector<unsigned char> vch;
+ if (creator.CreateSig(vch, keys[0].GetID(), _CCPubKey(cc), consensusBranchId, &privKey, (void *)cc))
+ {
+ ret.push_back(vch);
+ }
+ else
+ {
+ fprintf(stderr,"vin has 1ofn CC signing error with addresses.(%s)\n(%s)\n", keys[0].GetID().ToString().c_str(), keys[1].GetID().ToString().c_str());
+ }
+
+ cc_free(cc);
+ return ret.size() != 0;
+ }
}
}
}
return false;
}
+ COptCCParams p;
+ if (scriptPubKey.IsPayToCryptoCondition(p) && p.IsValid())
+ {
+ return SignStepCC(creator, scriptPubKey, vSolutions, ret, consensusBranchId);
+ }
+
CKeyID keyID;
switch (whichTypeRet)
}
return false;
- case TX_CRYPTOCONDITION:
- return SignStepCC(creator, scriptPubKey, vSolutions, ret, consensusBranchId);
-
case TX_MULTISIG:
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
return (SignN(vSolutions, creator, scriptPubKey, ret, consensusBranchId));
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata, uint32_t consensusBranchId)
{
CScript script = fromPubKey;
- bool solved = true;
+ bool solved;
std::vector<valtype> result;
txnouttype whichType;
solved = SignStep(creator, script, result, whichType, consensusBranchId);
{
return true;
}
+
+ int CheckCryptoCondition(
+ const std::vector<unsigned char>& condBin,
+ const std::vector<unsigned char>& ffillBin,
+ const CScript& scriptCode,
+ uint32_t consensusBranchId) const
+ {
+ return true;
+ }
};
const DummySignatureChecker dummyChecker;
}
CKey *key,
void *extraData) const
{
- // Create a dummy signature that is a valid DER-encoding
- vchSig.assign(72, '\000');
- vchSig[0] = 0x30;
- vchSig[1] = 69;
- vchSig[2] = 0x02;
- vchSig[3] = 33;
- vchSig[4] = 0x01;
- vchSig[4 + 33] = 0x02;
- vchSig[5 + 33] = 32;
- vchSig[6 + 33] = 0x01;
- vchSig[6 + 33 + 32] = SIGHASH_ALL;
+ if (scriptCode.IsPayToCryptoCondition())
+ {
+ vchSig = CCPartialSigVec(MakeCCcondOneSig(keyid));
+ }
+ else
+ {
+ // Create a dummy signature that is a valid DER-encoding
+ vchSig.assign(72, '\000');
+ vchSig[0] = 0x30;
+ vchSig[1] = 69;
+ vchSig[2] = 0x02;
+ vchSig[3] = 33;
+ vchSig[4] = 0x01;
+ vchSig[4 + 33] = 0x02;
+ vchSig[5 + 33] = 32;
+ vchSig[6 + 33] = 0x01;
+ vchSig[6 + 33 + 32] = SIGHASH_ALL;
+ }
return true;
}