Browse Source

Tokenized ID control hardening and improvements

pull/451/head
miketout 2 years ago
parent
commit
94c13ec733
  1. 12
      src/key_io.cpp
  2. 118
      src/pbaas/identity.cpp
  3. 10
      src/pbaas/identity.h
  4. 12
      src/script/sign.cpp

12
src/key_io.cpp

@ -1199,11 +1199,19 @@ CScript CIdentity::IdentityUpdateOutputScript(uint32_t height, const std::vector
if (CConstVerusSolutionVector::GetVersionByHeight(height) >= CActivationHeight::ACTIVATE_VERUSVAULT)
{
std::vector<CTxDestination> dests3({CTxDestination(CIdentityID(recoveryAuthority))});
if (HasTokenizedControl())
{
CCcontract_info CC;
CCcontract_info *cp;
// make a currency definition
cp = CCinit(&CC, EVAL_IDENTITY_RECOVER);
dests3.push_back(CPubKey(ParseHex(CC.CChexstr)).GetID());
}
CConditionObj<CIdentity> recovery(EVAL_IDENTITY_RECOVER, dests3, 1);
if (IsRevoked())
{
std::vector<CTxDestination> dests3({CTxDestination(CIdentityID(recoveryAuthority))});
CConditionObj<CIdentity> recovery(EVAL_IDENTITY_RECOVER, dests3, 1);
ret = MakeMofNCCScript(1, primary, recovery, indexDests);
}
else

118
src/pbaas/identity.cpp

@ -2067,9 +2067,15 @@ bool PrecheckIdentityPrimary(const CTransaction &tx, int32_t outNum, CValidation
{
COptCCParams master;
if (identity.nVersion < identity.VERSION_VAULT)
{
return state.Error("Inadequate identity version for post-Verus Vault activation");
}
if (isPBaaS && identity.nVersion < identity.VERSION_PBAAS)
{
return state.Error("Inadequate identity version for post-PBaaS activation");
}
if (p.vData.size() < 3 ||
!(master = COptCCParams(p.vData.back())).IsValid() ||
master.evalCode != 0 ||
@ -2145,11 +2151,54 @@ bool PrecheckIdentityPrimary(const CTransaction &tx, int32_t outNum, CValidation
if (!recovery)
{
recovery = true;
if (oneP.vKeys.size() == 1 &&
oneP.m == 1 &&
oneP.n == 1 &&
oneP.vKeys[0].which() == COptCCParams::ADDRTYPE_ID &&
identity.recoveryAuthority == GetDestinationID(oneP.vKeys[0]))
// tokenized control must allow one output, in this case the recovery,
// to be fulfilled. that means it must require only one signature to
// fulfill signature requirements. if we only have one signature, and
// it is from the publicly available key, ValidateIdentityRecover will
// consider the signature unfulfilled
if (height > TESTNET_FORK_HEIGHT && identity.HasTokenizedControl())
{
if (!(oneP.m == 1 && oneP.n > 1))
{
std::string errorOut = "Invalid spend condition for tokenized control in: \"" + identity.name + "\"";
return state.Error(errorOut.c_str());
}
// now, make sure that we have both the key for recoveryAuthority
// and the key for tokenized control, which anyone can sign, and which is further
// validated in the ValidateIdentityRecover
bool haveDefaultOutput = false;
CCcontract_info CC;
CCcontract_info *cp;
// make a currency definition
cp = CCinit(&CC, EVAL_IDENTITY_RECOVER);
CTxDestination recoverDest(CPubKey(ParseHex(CC.CChexstr)).GetID());
for (auto &oneKey : oneP.vKeys)
{
if (oneKey.which() == COptCCParams::ADDRTYPE_ID && identity.recoveryAuthority == GetDestinationID(oneKey))
{
recoveryValid = true;
}
else if (oneKey.which() == COptCCParams::ADDRTYPE_PKH &&
GetDestinationID(recoverDest) == GetDestinationID(oneKey))
{
haveDefaultOutput = true;
}
}
if (!(recoveryValid && haveDefaultOutput))
{
std::string errorOut = "Invalid recovery spend condition for tokenized control in: \"" + identity.name + "\"";
return state.Error(errorOut.c_str());
}
}
else if (oneP.vKeys.size() == 1 &&
oneP.m == 1 &&
oneP.n == 1 &&
oneP.vKeys[0].which() == COptCCParams::ADDRTYPE_ID &&
identity.recoveryAuthority == GetDestinationID(oneP.vKeys[0]))
{
recoveryValid = true;
}
@ -2594,23 +2643,60 @@ bool ValidateIdentityRecover(struct CCcontract_info *cp, Eval* eval, const CTran
{
return eval->Error("Missing recovery signature. All authorities must sign for currency or token definition");
}
}
if (oldIdentity.HasTokenizedControl())
if (oldIdentity.HasTokenizedControl())
{
bool fulfilledWithToken = false;
if (spendingTx.vout.size() <= (idIndex + 1) || spendingTx.vin.size() <= (nIn + 1))
{
if (spendingTx.vout.size() <= (idIndex + 1) || spendingTx.vin.size() <= (nIn + 1))
CAmount controlCurrencyVal = spendingTx.vout[idIndex + 1].ReserveOutValue().valueMap[identityID];
CTransaction tokenOutTx;
uint256 hashBlock;
COptCCParams tokenP;
if (controlCurrencyVal > 0 &&
myGetTransaction(spendingTx.vin[nIn + 1].prevout.hash, tokenOutTx, hashBlock) &&
tokenOutTx.vout[spendingTx.vin[nIn + 1].prevout.n].ReserveOutValue().valueMap[identityID] == controlCurrencyVal &&
tokenOutTx.vout[spendingTx.vin[nIn + 1].prevout.n].scriptPubKey == spendingTx.vout[idIndex + 1].scriptPubKey)
{
CAmount controlCurrencyVal = spendingTx.vout[idIndex + 1].ReserveOutValue().valueMap[identityID];
CTransaction tokenOutTx;
uint256 hashBlock;
COptCCParams tokenP;
if (controlCurrencyVal > 0 &&
myGetTransaction(spendingTx.vin[nIn + 1].prevout.hash, tokenOutTx, hashBlock) &&
tokenOutTx.vout[spendingTx.vin[nIn + 1].prevout.n].ReserveOutValue().valueMap[identityID] == controlCurrencyVal &&
tokenOutTx.vout[spendingTx.vin[nIn + 1].prevout.n].scriptPubKey == spendingTx.vout[idIndex + 1].scriptPubKey)
fulfilledWithToken = true;
fulfilled = true;
}
}
// if we are not fulfilled by the token, we should reverse fulfilled state if we are not completely fulfilled by the
// recovery authority
if (!fulfilledWithToken)
{
// get transaction hash and verify signature
auto consensusBranchID = CurrentEpochBranchId(height, Params().GetConsensus());
CSmartTransactionSignatures smartSigs;
bool signedByDefaultKey = false;
std::vector<unsigned char> ffVec = GetFulfillmentVector(spendingTx.vin[nIn].scriptSig);
smartSigs = CSmartTransactionSignatures(std::vector<unsigned char>(ffVec.begin(), ffVec.end()));
CIdentity recoveryIdentity = CIdentity::LookupIdentity(oldIdentity.recoveryAuthority, height);
int sigCount = 0;
if (smartSigs.IsValid() && recoveryIdentity.IsValid())
{
std::set<CTxDestination> sigDests = recoveryIdentity.IdentityPrimaryAddressKeySet();
for (auto &keySig : smartSigs.signatures)
{
fulfilled = true;
CPubKey thisKey;
thisKey.Set(keySig.second.pubKeyData.begin(), keySig.second.pubKeyData.end());
if (sigDests.count(thisKey.GetID()))
{
sigCount++;
}
}
if (sigCount < recoveryIdentity.minSigs)
{
fulfilled = false;
}
}
else
{
fulfilled = false;
}
}
}

10
src/pbaas/identity.h

@ -846,16 +846,14 @@ public:
static uint160 IdentityPrimaryAddressKey(const CTxDestination &dest);
std::vector<uint160> IdentityPrimaryAddressKeys() const
std::set<CTxDestination> IdentityPrimaryAddressKeySet() const
{
uint160 nameSpace;
std::vector<uint160> retVec;
std::set<CTxDestination> retVal;
for (auto &oneDest : primaryAddresses)
{
retVec.push_back(IdentityPrimaryAddressKey(oneDest));
retVal.insert(oneDest);
}
return retVec;
return retVal;
}
static bool GetIdentityOutsByPrimaryAddress(const CTxDestination &address, std::map<uint160, std::pair<std::pair<CAddressIndexKey, CAmount>, CIdentity>> &identities, uint32_t start=0, uint32_t end=0);

12
src/script/sign.cpp

@ -477,6 +477,8 @@ static bool SignStepCC(const BaseSignatureCreator& creator, const CScript& scrip
{
// loop through keys and sign with all that we have
std::map<CKeyID, CKey> privKeys;
std::map<CKeyID, CKey> defaultKeys;
for (auto destPair : destMap)
{
//printf("Checking for private key of destination: %s ", EncodeDestination(destPair.second).c_str());
@ -485,7 +487,7 @@ static bool SignStepCC(const BaseSignatureCreator& creator, const CScript& scrip
auto dit = privKeyMap.find(destPair.first);
if (dit != privKeyMap.end())
{
privKeys[dit->first] = dit->second;
defaultKeys[dit->first] = dit->second;
//printf("...using key for crypto condition\n");
}
else if (creator.IsKeystoreValid() && creator.KeyStore().GetKey(destPair.first, privKey))
@ -494,6 +496,14 @@ static bool SignStepCC(const BaseSignatureCreator& creator, const CScript& scrip
//printf("...using key from wallet\n");
}
}
// to save space, use default only if we don't have all other private keys for signing
if (!(privKeys.size() && (privKeys.size() + defaultKeys.size()) != destMap.size()))
{
for (auto &oneDefaultKey : defaultKeys)
{
privKeys.insert(oneDefaultKey);
}
}
vector<unsigned char> vch = ret.size() ? ret[0] : vector<unsigned char>();
bool error = false;

Loading…
Cancel
Save