// Use a local variable for theToken, do NOT allocate it on the heap // unless you are going to delete it yourself. // Repeat: OTPurse is NOT responsible to delete it. We create our OWN internal // variable here, new that, and add it to the stack. We do not add the one passed in. bool OTPurse::Push(const OTPseudonym & theOwner, const OTToken & theToken) { if (theToken.GetAssetID() == m_AssetID) { OTString strToken(theToken); // OTLog::vError("$$$$$$$$$$$$$$$ PUSHING token to Purse:\n---------->%s<-------------\n", strToken.Get()); OTEnvelope theEnvelope; theEnvelope.Seal(theOwner, strToken); OTASCIIArmor * pArmor = new OTASCIIArmor(theEnvelope); // OTLog::vError("$$$$$$$$$$$$$$$ PUSHING token to Purse in armored form:\n---------->%s<-------------\n", // pArmor->Get()); m_dequeTokens.push_front(pArmor); // We keep track of the purse's total value. m_lTotalValue += theToken.GetDenomination(); return true; } else { OTString strPurseAssetType(m_AssetID), strTokenAssetType(theToken.GetAssetID()); OTLog::vError("ERROR: Tried to push token with wrong asset type in OTPurse::Push\nPurse Asset Type:\n%s\n" "Token Asset Type:\n%s\n", strPurseAssetType.Get(), strTokenAssetType.Get()); return false; } }
// Take all the tokens from a purse and add them to this purse. // Don't allow duplicates. // bool OTPurse::Merge(OTPseudonym & theOldNym, OTPseudonym & theNewNym, OTPurse & theNewPurse) { mapOfTokenPointers theMap; while (this->Count() > 0) { OTToken * pToken = this->Pop(theOldNym); OT_ASSERT_MSG(NULL != pToken, "OTPurse::Merge: Assert: NULL != this->Pop(theOldNym) \n"); const OTASCIIArmor & ascTokenID = pToken->GetSpendable(); std::list<mapOfTokenPointers::iterator> listOfTokenMapIterators; // I just popped a Token off of *this. Let's see if it's in my temporary map... // If it's already there, then just delete it (duplicate). // FOR_EACH(mapOfTokenPointers, theMap) { OTToken * pTempToken = (*it).second; OT_ASSERT(NULL != pTempToken); const OTASCIIArmor & ascTempTokenID = pTempToken->GetSpendable(); // -------------------------------- // It's already there. Delete the one that's already there. // (That way we can add it after, whether it was there originally or not.) if (ascTempTokenID == ascTokenID) { listOfTokenMapIterators.push_back(it); // theMap.erase(it); // delete pTempToken; // pTempToken = NULL; //break; // In case there are multiple duplicates, not just one. } } while (listOfTokenMapIterators.size() > 0) { OTToken * pTempToken = (listOfTokenMapIterators.back())->second; theMap.erase(listOfTokenMapIterators.back()); delete pTempToken; pTempToken = NULL; listOfTokenMapIterators.pop_back(); } // Now we know there aren't any duplicates on the temporary map, let's add the token to it. std::string theKey = ascTokenID.Get(); theMap.insert(std::pair<std::string, OTToken*>(theKey, pToken)); }
// Hypocritically (compared to Push) in the case of Pop(), we DO // allocate a OTToken and return the pointer. The caller IS // responsible to delete it when he's done with it. // // The apparent discrepancy is due to the fact that internally, // we aren't storing the token object but an encrypted string of it. // But this is hidden from the user of the purse, who perceives only // that he is passing tokens in and getting them back out again. OTToken * OTPurse::Pop(const OTPseudonym & theOwner) { if (m_dequeTokens.empty()) return NULL; // Grab a copy of the pointer and remove it from the deque OTASCIIArmor * pArmor = m_dequeTokens.front(); m_dequeTokens.pop_front(); // OTLog::vError("$$$$$$$$$$$$$$ ARMORED TEXT in PURSE POP:\n--------->%s<-----------\n", pArmor->Get()); // Copy the token contents into an Envelope, and delete the pointer. OTEnvelope theEnvelope(*pArmor); delete pArmor; pArmor = NULL; // Open the envelope into a string. OTString strToken; theEnvelope.Open(theOwner, strToken); // OTLog::vError("$$$$$$$$$$$$$$$ OPENED ENVELOPE TEXT in PURSE POP:\n--------->%s<-----------\n", strToken.Get()); // Create a new token with the same server and asset IDs as this purse. OTToken * pToken = new OTToken(*this); OT_ASSERT(NULL != pToken); // Load the token from the string we got out of the envelope. pToken->LoadContractFromString(strToken); if (pToken->GetAssetID() != m_AssetID || pToken->GetServerID() != m_ServerID) { delete pToken; pToken = NULL; OTLog::Error("ERROR: Token with wrong asset type in OTPurse::Pop\n"); } else { // We keep track of the purse's total value. m_lTotalValue -= pToken->GetDenomination(); } // CALLER is responsible to delete this token. return pToken; }
// Lucre step 3: the mint signs the token // bool OTMint_Lucre::SignToken(OTPseudonym & theNotary, OTToken & theToken, OTString & theOutput, int32_t nTokenIndex) { bool bReturnValue = false; //OTLog::Error("%s <bank file> <coin request> <coin signature> [<signature repeats>]\n", _OT_Lucre_Dumper setDumper; // OTLog::vError("OTMint::SignToken!!\nnTokenIndex: %d\n Denomination: %lld\n", nTokenIndex, theToken.GetDenomination()); OpenSSL_BIO bioBank = BIO_new(BIO_s_mem()); // input OpenSSL_BIO bioRequest = BIO_new(BIO_s_mem()); // input OpenSSL_BIO bioSignature = BIO_new(BIO_s_mem()); // output OTASCIIArmor thePrivate; GetPrivate(thePrivate, theToken.GetDenomination()); // The Mint private info is encrypted in m_mapPrivates[theToken.GetDenomination()]. // So I need to extract that first before I can use it. OTEnvelope theEnvelope(thePrivate); OTString strContents; // output from opening the envelope. // Decrypt the Envelope into strContents if (!theEnvelope.Open(theNotary, strContents)) return false; // copy strContents to a BIO BIO_puts(bioBank, strContents.Get()); // OTLog::vError("BANK CONTENTS:\n%s--------------------------------------\n", strContents.Get()); // Instantiate the Bank with its private key Bank bank(bioBank); // OTLog::vError("BANK INSTANTIATED.--------------------------------------\n"); // I need the request. the prototoken. OTASCIIArmor ascPrototoken; bool bFoundToken = theToken.GetPrototoken(ascPrototoken, nTokenIndex); if (bFoundToken) { // base64-Decode the prototoken OTString strPrototoken(ascPrototoken); // OTLog::vError("\n--------------------------------------\nDEBUG: PROTOTOKEN CONTENTS:\n" // "-----------------%s---------------------\n", strPrototoken.Get() ); // copy strPrototoken to a BIO BIO_puts(bioRequest, strPrototoken.Get()); // Load up the coin request from the bio (the prototoken) PublicCoinRequest req(bioRequest); // OTLog::Error("PROTOTOKEN INSTANTIATED.--------------------------------------\n"); // Sign it with the bank we previously instantiated. // results will be in bnSignature (BIGNUM) BIGNUM * bnSignature = bank.SignRequest(req); if (NULL == bnSignature) { OTLog::Error("MAJOR ERROR!: Bank.SignRequest failed in OTMint_Lucre::SignToken\n"); } else { // OTLog::Error("BANK.SIGNREQUEST SUCCESSFUL.--------------------------------------\n"); // Write the request contents, followed by the signature contents, // to the Signature bio. Then free the BIGNUM. req.WriteBIO(bioSignature); // the original request contents DumpNumber(bioSignature,"signature=", bnSignature); // the new signature contents BN_free(bnSignature); // Read the signature bio into a C-style buffer... char sig_buf[1024]; // todo stop hardcoding these string lengths // memset(sig_buf, 0, 1024); // zero it out. (I had this commented out, but the size was 2048, so maybe it's safe now at 1024.) int32_t sig_len = BIO_read(bioSignature, sig_buf, 1000); // cutting it a little short on purpose, with the buffer. Just makes me feel more comfortable for some reason. // Add the null terminator by hand (just in case.) sig_buf[sig_len] = '\0'; if (sig_len) { // *********************************************** // OTLog::vError("\n--------------------------------------\n" // "*** Siglen is %d. sig_str_len is %d.\nsig buf:\n------------%s------------\nLAST " // "CHARACTER IS '%c' SECOND TO LAST CHARACTER IS '%c'\n", // sig_len, sig_str_len, sig_buf, sig_buf[sig_str_len-1], sig_buf[sig_str_len-2]); // Copy the original coin request into the spendable field of the token object. // (It won't actually be spendable until the client processes it, though.) theToken.SetSpendable(ascPrototoken); // OTLog::vError("*** SPENDABLE:\n-----------%s---------------------\n", ascPrototoken.Get()); // Base64-encode the signature contents into theToken.m_Signature. OTString strSignature(sig_buf); // strSignature.Set(sig_buf, sig_len-1); // sig_len includes null terminator, whereas Set() adds 1 for it. // OTLog::vError("SIGNATURE:\n--------------------%s" // "------------------\n", strSignature.Get()); // Here we pass the signature back to the caller. // He will probably set it onto the token. theOutput.Set(sig_buf, sig_len); bReturnValue = true; // This is also where we set the expiration date on the token. // The client should have already done this, but we are explicitly // setting the values here to prevent any funny business. theToken.SetSeriesAndExpiration(m_nSeries, m_VALID_FROM, m_VALID_TO); } } } return bReturnValue; }
// Lucre step 4: client unblinds token -- now it's ready for use. bool OTToken::ProcessToken(const OTPseudonym & theNym, OTMint & theMint, OTToken & theRequest) { // OTLog::vError("%s <bank public info> <private coin request> <signed coin request> <coin>\n", bool bReturnValue = false; // When the Mint has signed a token and sent it back to the client, // the client must unblind the token and set it as spendable. Thus, // this function is only performed on tokens in the signedToken state. if (OTToken::signedToken != m_State) { OTLog::Error("Signed token expected in OTToken::ProcessToken\n"); return false; } // Lucre SetDumper(stderr); BIO *bioBank = BIO_new(BIO_s_mem()); // input BIO *bioSignature = BIO_new(BIO_s_mem()); // input BIO *bioPrivateRequest = BIO_new(BIO_s_mem()); // input BIO *bioCoin = BIO_new(BIO_s_mem()); // output // Get the bank's public key (decoded into strPublicMint) // and put it into bioBank so we can use it with Lucre. OTASCIIArmor ascPublicMint; theMint.GetPublic(ascPublicMint, GetDenomination()); OTString strPublicMint(ascPublicMint); BIO_puts(bioBank, strPublicMint.Get()); // Get the existing signature into a bio. // OTLog::vError("DEBUGGING, m_Signature: -------------%s--------------\n", m_Signature.Get()); OTString strSignature(m_Signature); BIO_puts(bioSignature, strSignature.Get()); // I need the Private coin request also. (Only the client has this private coin request data.) OTASCIIArmor thePrototoken; // The server sets m_nChosenIndex when it signs the token. bool bFoundToken = theRequest.GetPrivatePrototoken(thePrototoken, m_nChosenIndex); if (bFoundToken) { // OTLog::vError("THE PRIVATE REQUEST ARMORED CONTENTS:\n------------------>%s<-----------------------\n", // thePrototoken.Get()); // Decrypt the prototoken OTString strPrototoken; OTEnvelope theEnvelope(thePrototoken); theEnvelope.Open(theNym, strPrototoken); // todo check return value. // OTLog::vError("THE PRIVATE REQUEST CONTENTS:\n------------------>%s<-----------------------\n", // strPrototoken.Get()); // copy strPrototoken to a BIO BIO_puts(bioPrivateRequest, strPrototoken.Get()); // ------- Okay, the BIOs are all loaded.... let's process... PublicBank bank(bioBank); CoinRequest req(bioPrivateRequest); // TODO make sure I'm not leaking memory with these ReadNumbers // Probably need to be calling some free function for each one. // Apparently reading the request id here and then just discarding it... ReadNumber(bioSignature,"request="); // Versus the signature data, which is read into bnSignature apparently. BIGNUM * bnSignature = ReadNumber(bioSignature,"signature="); DumpNumber("signature=", bnSignature); // Produce the final unblinded token in Coin coin, and write it to bioCoin... Coin coin; // Coin Request, processes into Coin, with Bank and Signature passed in. req.ProcessResponse(&coin, bank, bnSignature); // Notice still apparently "request" info is discarded. coin.WriteBIO(bioCoin); // convert bioCoin to a C-style string... char CoinBuffer[1024]; // todo stop hardcoding these string lengths int coinLen = BIO_read(bioCoin, CoinBuffer, 1000); // cutting it a little short on purpose, with the buffer. Just makes me feel more comfortable for some reason. if (coinLen) { // ...to OTString... OTString strCoin; strCoin.Set(CoinBuffer, coinLen); // OTLog::vError("Processing token...\n%s\n", strCoin.Get()); // ...to Envelope stored in m_ascSpendable (encrypted and base64-encoded) OTEnvelope theEnvelope; theEnvelope.Seal(theNym, strCoin); // Todo check the return values on these two functions theEnvelope.GetAsciiArmoredData(m_ascSpendable); // Here's the final product. // OTLog::vError("NEW SPENDABLE token...\n--------->%s<----------------\n", m_ascSpendable.Get()); // Now the coin is encrypted from here on out, and otherwise ready-to-spend. m_State = OTToken::spendableToken; bReturnValue = true; // Lastly, we free the signature data, which is no longer needed, and which could be // otherwise used to trace the token. (Which we don't want.) m_Signature.Release(); } } // Todo log error here if the private prototoken is not found. (Very strange if so!!) // else {} // Cleanup openssl resources. BIO_free_all(bioBank); BIO_free_all(bioSignature); BIO_free_all(bioPrivateRequest); BIO_free_all(bioCoin); return bReturnValue; }
// Take all the tokens from a purse and add them to this purse. // Don't allow duplicates. // bool OTPurse::Merge(OTPseudonym & theNym, OTPurse & theNewPurse) { mapOfTokenPointers theMap; while (this->Count() > 0) { OTToken * pToken = this->Pop(theNym); OT_ASSERT(NULL != pToken); const OTASCIIArmor & ascTokenID = pToken->GetSpendable(); // I just popped a Token off of *this. Let's see if it's in my temporary map... // If it's already there, then just delete it (duplicate). for (mapOfTokenPointers::iterator ii = theMap.begin(); ii != theMap.end(); ++ii) { OTToken * pTempToken = (*ii).second; OT_ASSERT(NULL != pTempToken); const OTASCIIArmor & ascTempTokenID = pTempToken->GetSpendable(); // -------------------------------- // It's already there. Delete the one that's already there. // (That way we can add it after, whether it was there originally or not.) if (ascTempTokenID == ascTokenID) { theMap.erase(ii); delete pTempToken; //break; // In case there are multiple duplicates, not just one. } } // Now we know there aren't any duplicates on the temporary map, let's add the token to it. std::string theKey = ascTokenID.Get(); theMap.insert(std::pair<std::string, OTToken*>(theKey, pToken)); } // At this point, all of the tokens on *this have been popped, and added // to the temporary map as token pointers, with any duplicates removed. // ----------------------------------------------------------- // Basically now I just want to do the exact same thing with the other purse. while (theNewPurse.Count() > 0) { OTToken * pToken = theNewPurse.Pop(theNym); // TODO: This isn't necessarily the right nym. Need to fix purse to allow dummy nyms. OT_ASSERT(NULL != pToken); const OTASCIIArmor & ascTokenID = pToken->GetSpendable(); // I just popped a Token off of theNewPurse. Let's see if it's in my temporary map... // If it's already there, then just delete it (duplicate). for (mapOfTokenPointers::iterator ii = theMap.begin(); ii != theMap.end(); ++ii) { OTToken * pTempToken = (*ii).second; OT_ASSERT(NULL != pTempToken); const OTASCIIArmor & ascTempTokenID = pTempToken->GetSpendable(); // -------------------------------- // It's already there. Delete the one that's already there. // (That way we can add it after, whether it was there originally or not.) if (ascTempTokenID == ascTokenID) { theMap.erase(ii); delete pTempToken; //break; // In case there are multiple duplicates, not just one. } } // Now we know there aren't any duplicates on the temporary map, let's add the token to it. std::string theKey = ascTokenID.Get(); theMap.insert(std::pair<std::string, OTToken*>(theKey, pToken)); } // ----------------------------------------------------------- // At this point, all of the tokens on *this AND theNewPurse have been popped, and added // to the temporary map as token pointers, with any duplicates removed. // Now I just loop through that same map, and Push ALL of those tokens back onto *this. for (mapOfTokenPointers::iterator ii = theMap.begin(); ii != theMap.end(); ++ii) { OTToken * pToken = (*ii).second; OT_ASSERT(NULL != pToken); bool bPush = this->Push(theNym, *pToken); // purse makes it's own copy of the token into string form. if (!bPush) OTLog::Error("Failure pushing token in OTPurse::Merge.\n"); } // ----------------------------------------------------- // Next I clean up all the tokens out of the temporary map, since they will leak otherwise. while (!theMap.empty()) { OTToken * pToken = theMap.begin()->second; OT_ASSERT(NULL != pToken); delete pToken; pToken = NULL; theMap.erase(theMap.begin()); } // ----------------------------------------------------- return true; }