Beispiel #1
0
// Called by the above function.
// This ledger is an outbox, and it is creating a report of itself, 
// adding each report item to this balance item.
// DO NOT call this, it's meant to be used only by above function.
void OTLedger::ProduceOutboxReport(OTItem & theBalanceItem)  
{
	if (OTLedger::outbox != GetType())
	{
		OTLog::Error("OTLedger::ProduceOutboxReport: Wrong ledger type.\n");
		return;
	}
	
	// loop through the OUTBOX transactions, and produce a sub-item onto theBalanceItem for each, which will
	// be a report on each pending transfer in this outbox, therefore added to the balance item.
	// (So the balance item contains a complete report on the outoing transfers in this outbox.)
	OTTransaction * pTransaction = NULL;
	
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); 
		 ii != m_mapTransactions.end(); ++ii)
	{
		pTransaction = (*ii).second;
		
		OT_ASSERT(NULL != pTransaction);
		
		// it only reports receipts where we don't yet have balance agreement.
		pTransaction->ProduceOutboxReportItem(theBalanceItem);	// <======= This function adds a pending transfer sub-item to theBalanceItem, where appropriate.
	}
	
	// ---------------------------------------------------------	
}
Beispiel #2
0
// for inbox only, allows you to lookup the total value of pending transfers within the inbox.
// (And it really loads the items to check the amount, but does all this ONLY for pending transfers.)
//
long OTLedger::GetTotalPendingValue()
{
	long lTotalPendingValue = 0;
	
	if (OTLedger::inbox != GetType())
	{
		OTLog::Error("OTLedger::GetTotalPendingValue: Wrong ledger type (expected inbox).\n");
		return 0;
	}
	
	OTTransaction * pTransaction = NULL;
	
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); 
		 ii != m_mapTransactions.end(); ++ii)
	{
		pTransaction = (*ii).second;
		
		OT_ASSERT(NULL != pTransaction);
		
		if (pTransaction->GetType() == OTTransaction::pending)
			lTotalPendingValue += pTransaction->GetReceiptAmount(); // this actually loads up the original item and reads the amount.
	}	
	
	return lTotalPendingValue;
}
Beispiel #3
0
// Look up a transaction by transaction number and see if it is in the ledger.
// If it is, return a pointer to it, otherwise return NULL.
OTTransaction * OTLedger::GetTransaction(long lTransactionNum)
{
	// loop through the items that make up this transaction
	
//  OTLog::vError("OTLedger::GetTransaction: Checking ledger for trans %ld. COUNT: %d \n", lTransactionNum, GetTransactionCount());
    
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); ii != m_mapTransactions.end(); ++ii)
	{
		OTTransaction * pTransaction = (*ii).second;
		OT_ASSERT(NULL != pTransaction);
		
//      OTLog::vError("OTLedger::GetTransaction: Looping. Currently on trans %ld \n", pTransaction->GetTransactionNum());
        
		if (pTransaction->GetTransactionNum() == lTransactionNum)
        {
//          OTLog::vOutput(5, "OTLedger::GetTransaction: Returning transaction# %ld \n", lTransactionNum);
            
			return pTransaction;
        }
//		else // this was for debugging only. It's actually normal for non-matching numbers to be on this list.
//			OTLog::vOutput(5"Expected transaction number %ld, but found %ld on the list instead. Bad data?\n",
//						  lTransactionNum, pTransaction->GetTransactionNum());
	}
	
//        OTLog::Error("OTLedger::GetTransaction: Returning NULL \n");

	return NULL;
}
// Look up a transaction by transaction number and see if it is in the ledger.
// If it is, return a pointer to it, otherwise return NULL.
OTTransaction * OTLedger::GetTransaction(long lTransactionNum)
{
	// See if there's something there with that transaction number.
	mapOfTransactions::iterator it = m_mapTransactions.find(lTransactionNum);
	
	if ( it == m_mapTransactions.end() )
	{
		// not found.
		return NULL;
	}
	// Found it!
	else 
	{
		OTTransaction * pTransaction = (*it).second;
		
		OT_ASSERT((NULL != pTransaction));
		
		if (pTransaction->GetTransactionNum() == lTransactionNum)
			return pTransaction;
		else 
			OTLog::vError("Expected transaction number %ld, but found %ld on the list instead. Bad data?\n",
						  lTransactionNum, pTransaction->GetTransactionNum());
	}
	
	return NULL;
}
// OTMessageOutbuffer deletes the OTMessage when you call this.
//
bool OTMessageOutbuffer::RemoveSentMessage(const OTTransaction & theTransaction)
{
    const int64_t &    lRequestNum = theTransaction.GetRequestNum();
    const OTString  strServerID(theTransaction.GetPurportedServerID());
    const OTString  strNymID(theTransaction.GetUserID());
    // -------------------------------------
    return RemoveSentMessage(lRequestNum, strServerID, strNymID);
}
Beispiel #6
0
/// If transaction #87, in reference to #74, is in the inbox, you can remove it
/// by calling this function and passing in 74.
///
bool OTLedger::RemovePendingTransaction(long lTransactionNum) // if false, transaction wasn't found.
{	
	// loop through the items that make up this transaction.
	OTTransaction * pTransaction = NULL;
	
	mapOfTransactions::iterator it;
	
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); ii != m_mapTransactions.end(); ++ii)
	{
		it = ii;
		
		pTransaction = (*ii).second;
		
		OT_ASSERT(NULL != pTransaction);
		
		bool bCorrectType = false;
		
		switch (pTransaction->GetType()) 
		{
			case OTTransaction::pending:
			case OTTransaction::transferReceipt:
			case OTTransaction::chequeReceipt:
				bCorrectType = true;
				break;
			default:
				break;
		}
		
		if (bCorrectType && pTransaction->GetReferenceToNum() == lTransactionNum)
			break;
		else
			pTransaction = NULL;
		
	}
	
	// If it's not already on the list, then there's nothing to remove.
	if ( NULL == pTransaction )
	{
		OTLog::vError("OTLedger::RemovePendingTransaction: Attempt to remove Transaction from ledger,\n"
					  "when not already there: (the number in reference to) %ld\n",
					  lTransactionNum);
		return false;
	}
	// Otherwise, if it WAS already there, remove it properly.
	else 
	{		
		m_mapTransactions.erase(it);
		delete pTransaction;
		return true;		
	}
	
	return false;
}
// SignContract will call this function at the right time.
void OTLedger::UpdateContents() // Before transmission or serialization, this is where the ledger saves its contents 
{
	// Notice I use the PURPORTED Account ID and Server ID to create the output. That's because
	// I don't want to inadvertantly substitute the real ID for a bad one and then sign it.
	// So if there's a bad one in there when I read it, THAT's the one that I write as well!
	OTString strType, strLedgerAcctID(GetPurportedAccountID()), strLedgerAcctServerID(GetPurportedServerID()),
		strUserID(GetUserID());
	
	switch (m_Type) {
		case OTLedger::message:
			strType.Set("message");
			break;
		case OTLedger::inbox:
			strType.Set("inbox");
			break;
		case OTLedger::outbox:
			strType.Set("outbox");
			break;
		default:
			strType.Set("error-unknown");
			break;
	}
	
	// I release this because I'm about to repopulate it.
	m_xmlUnsigned.Release();
	
	//	m_xmlUnsigned.Concatenate("<?xml version=\"%s\"?>\n\n", "1.0");		
	
	m_xmlUnsigned.Concatenate("<accountLedger version=\"%s\"\n type=\"%s\"\n accountID=\"%s\"\n userID=\"%s\"\n"
							  "serverID=\"%s\" >\n\n", m_strVersion.Get(), strType.Get(), 
							  strLedgerAcctID.Get(), strUserID.Get(), strLedgerAcctServerID.Get());		
	
	// loop through the transactions and print them out here.
	OTTransaction * pTransaction = NULL;
	
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); 
		 ii != m_mapTransactions.end(); ++ii)
	{
		if ((pTransaction = (*ii).second)) // if pointer not null
		{
			OTString strTransaction;
			pTransaction->SaveContract(strTransaction);
			
			OTASCIIArmor ascTransaction;
			ascTransaction.SetString(strTransaction, true); // linebreaks = true
			
			m_xmlUnsigned.Concatenate("<transaction>\n%s</transaction>\n\n", ascTransaction.Get());
		}
	}
	
	m_xmlUnsigned.Concatenate("</accountLedger>\n");				
}
Beispiel #8
0
// Return a count of all the transactions in this ledger that are IN REFERENCE TO a specific trans#.
//
// Might want to change this so that it only counts ACCEPTED receipts.
//
int OTLedger::GetTransactionCountInRefTo(const long lReferenceNum)
{
    int nCount = 0;
    
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); ii != m_mapTransactions.end(); ++ii)
	{
		OTTransaction * pTransaction = (*ii).second;
		OT_ASSERT(NULL != pTransaction);
		
        if (pTransaction->GetReferenceToNum() == lReferenceNum)
            nCount++;
	}
	
	return nCount;
}
Beispiel #9
0
// While processing a transaction, you may wish to query it for items of a certain type.
OTTransaction * OTLedger::GetTransaction(const OTTransaction::transactionType theType) 
{
	// loop through the items that make up this transaction
	
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); ii != m_mapTransactions.end(); ++ii)
	{
		OTTransaction * pTransaction = (*ii).second;
		OT_ASSERT(NULL != pTransaction);
		
		if (theType == pTransaction->GetType())
			return pTransaction;
	}
	
	return NULL;
}
Beispiel #10
0
// If you TRANSFER REQUEST to me (transaction #1), then the server will create a 
// PENDING transaction in my inbox (transaction #41) and a PENDING transaction in 
// your outbox (also transaction #41) which both contain a copy of transaction#1 in their
// "In Reference To" ascii-armored field.
//
// The above function would look up #41 in my inbox, or #41 in your outbox, but
// you could NOT pass #1 to that function and get a pointer back. You'd get NULL.
// But the below function specifically returns the pointer of a transaction ONLY
// IF THE "IN REFERENCE TO" Transaction ID matches the one passed in (such as #1
// in the example above.
// If it can't find anything, it will return NULL.
OTTransaction * OTLedger::GetPendingTransaction(long lTransactionNum)
{
	// loop through the items that make up this transaction.
	OTTransaction * pTransaction = NULL;
	
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); ii != m_mapTransactions.end(); ++ii)
	{
		pTransaction = (*ii).second;
		
		OT_ASSERT(NULL != pTransaction);
		
		if (pTransaction->GetReferenceToNum() == lTransactionNum)
			return pTransaction;
	}
	
	return NULL;
}
Beispiel #11
0
// Find the finalReceipt in this Inbox, that has lTransactionNum as its "in reference to".
// This is useful for cases where a marketReceipt or paymentReceipt has been found,
// yet the transaction # for that receipt isn't on my issued list... it's been closed.
// Normally this would be a problem: why is it in my inbox then? Because those receipts
// are still valid as long as there is a "FINAL RECEIPT" in the same inbox, that references
// the same original transaction that they do.  The below function makes it easy to find that
// final receipt, if it exists.
//
OTTransaction * OTLedger::GetFinalReceipt(long lReferenceNum)
{
	// loop through the items that make up this transaction.
	OTTransaction * pTransaction = NULL;
	
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); ii != m_mapTransactions.end(); ++ii)
	{
		pTransaction = (*ii).second;
		
		OT_ASSERT(NULL != pTransaction);
		
        if (OTTransaction::finalReceipt != pTransaction->GetType()) // <=======
            continue;
        // ---------------------------------
		if (pTransaction->GetReferenceToNum() == lReferenceNum)
			return pTransaction;
	}
	
	return NULL;
}
Beispiel #12
0
bool OTLedger::AddTransaction(OTTransaction & theTransaction)
{
	// See if there's something else already there with the same transaction number.
	mapOfTransactions::iterator it = m_mapTransactions.find(theTransaction.GetTransactionNum());
	
	// If it's not already on the list, then add it...
	if ( it == m_mapTransactions.end() )
	{
		m_mapTransactions[theTransaction.GetTransactionNum()] = &theTransaction;
		return true;
	}
	// Otherwise, if it was already there, log an error.
	else 
	{
		OTLog::vError("Attempt to add Transaction to ledger when already there for that number: %ld\n",
					  theTransaction.GetTransactionNum());
	}
	
	return false;
}
Beispiel #13
0
// If my outbox has a pending transfer, #1901, referencing 1884, and then the 
// recipient accepts it with his #781, referencing 1884, then it will pop into my inbox
// as a transfer receipt, #1902 (say) and referencing 781. Attached to that
// transfer receipt is a copy of the actual #781, which is in reference to 1884.
//
// Why does this matter? Because when I am verifying a balance agreement, and an
// outbox item 1901/1884 is missing, that means there is probably a corresponding 
// transferReceipt in the Inbox. In that case, I START with #1901 referencing 1884 (from
// the outbox) and I need to FIND #1902, in reference to 781, referencing 1884 in the inbox.
//
// Therefore, loop through all items and filter by transfer receipt. For each, load its
// Reference string (containing the acceptPending) and get ITS ReferenceNum() to compare
// to the one passed in.
//
// Therefore 1884 would be passed in, and the appropriate transferReceipt will be returned.
//
OTTransaction * OTLedger::GetTransferReceipt(long lTransactionNum)
{
	// loop through the items that make up this transaction.
	OTTransaction * pTransaction = NULL;
	
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); ii != m_mapTransactions.end(); ++ii)
	{
		pTransaction = (*ii).second;
		
		OT_ASSERT(NULL != pTransaction);
		
		if (OTTransaction::transferReceipt == pTransaction->GetType())
		{
			OTString strReference;
			pTransaction->GetReferenceString(strReference);
			
			OTItem * pOriginalItem = OTItem::CreateItemFromString(strReference, 
																  pTransaction->GetPurportedServerID(), 
																  pTransaction->GetReferenceToNum()); 
			OT_ASSERT(NULL != pOriginalItem);
			OTCleanup<OTItem> theItemAngel(*pOriginalItem);
			
			if (pOriginalItem->GetType() != OTItem::acceptPending) 
			{
				OTLog::Error("OTLedger::GetTransferReceipt: Wrong item type attached to transferReceipt!\n");
				return NULL;
			}
			else 
			{
				if (pOriginalItem->GetReferenceToNum() == lTransactionNum)
					return pTransaction; // FOUND IT!
			}
		}
	}
	
	return NULL;
}
Beispiel #14
0
/// Only if it is an inbox, a ledger will loop through the transactions
/// and produce the XML output for the report that's necessary during
/// a balance agreement. (Any balance agreement for an account must
/// include the list of transactions the nym has issued for use, as
/// well as a listing of the transactions in the inbox for that account.
/// This function does that last part :)
///
/// returns a new balance statement item containing the inbox report
/// CALLER IS RESPONSIBLE TO DELETE.
OTItem * OTLedger::GenerateBalanceStatement(const long lAdjustment, const OTTransaction & theOwner, 
											OTPseudonym & theNym, const OTAccount & theAccount, OTLedger & theOutbox) 
{
	if (OTLedger::inbox != GetType())
	{
		OTLog::Error("OTLedger::GenerateBalanceStatement: Wrong ledger type.\n");
		return NULL;
	}
	
	// ------------------------------------------------------
	
	const OTIdentifier theNymID(theNym);
	
	if (
		(theAccount.GetPurportedAccountID()	!= GetPurportedAccountID()) ||
		(theAccount.GetPurportedServerID()	!= GetPurportedServerID()) ||
		(theAccount.GetUserID()				!= GetUserID()) )
	{
		OTLog::Error("Wrong Account passed in to OTLedger::GenerateBalanceStatement.\n");
		return NULL;
	}
	if (
		(theOutbox.GetPurportedAccountID()	!= GetPurportedAccountID()) ||
		(theOutbox.GetPurportedServerID()	!= GetPurportedServerID()) ||
		(theOutbox.GetUserID()				!= GetUserID()) )
	{
		OTLog::Error("Wrong Outbox passed in to OTLedger::GenerateBalanceStatement.\n");
		return NULL;
	}
	if (
		(theNymID	!= GetUserID()))
	{
		OTLog::Error("Wrong Nym passed in to OTLedger::GenerateBalanceStatement.\n");
		return NULL;
	}
	// ---------------------------------------------------------

	// theOwner is the withdrawal, or deposit, or whatever, that wants to change
	// the account balance, and thus that needs a new balance agreement signed.
	//
	OTItem * pBalanceItem = OTItem::CreateItemFromTransaction(theOwner, OTItem::balanceStatement); // <=== balanceStatement type, with user ID, server ID, account ID, transaction ID.

	// The above has an ASSERT, so this this will never actually happen.
	if (NULL == pBalanceItem)
		return NULL;
	
	// ---------------------------------------------------------
	
	// COPY THE ISSUED TRANSACTION NUMBERS FROM THE NYM to the MESSAGE NYM.
	
	OTPseudonym theMessageNym;
	    
	theMessageNym.HarvestIssuedNumbers(this->GetPurportedServerID(), 
                                       theNym /*unused in this case, not saving to disk*/, theNym, false); // bSave = false;
	
	// -------------------------------------
	
    
    
	switch (theOwner.GetType()) 
	{
			// These five options will remove the transaction number from the issued list, SUCCESS OR FAIL.
			// Server will expect the number to be missing from the list, in the case of these.
			// Therefore I remove it here in order to generate a proper balance agreement, acceptable to the server.
		case OTTransaction::processInbox:
		case OTTransaction::deposit:
		case OTTransaction::withdrawal:
        case OTTransaction::cancelCronItem:
		case OTTransaction::exchangeBasket:

			theMessageNym.RemoveIssuedNum(theOwner.GetRealServerID(), theOwner.GetTransactionNum());  // a transaction number is being used, and REMOVED from my list of responsibility,
			theMessageNym.RemoveTransactionNum(theOwner.GetRealServerID(), theOwner.GetTransactionNum());  // a transaction number is being used, and REMOVED from my list of  available numbers.
			break;
		case OTTransaction::transfer:
		case OTTransaction::marketOffer:
		case OTTransaction::paymentPlan:
			// Nothing removed here since the transaction is still in play. (Assuming success.)
			// If the server replies with rejection for any of these three, then I can remove
			// the transaction number from my list of issued/signed for. But if success, then I
			// am responsible for the transaction number until I sign off on closing it.
			// Since the Balance Statement ANTICIPATES SUCCESS, NOT FAILURE, it assumes the number
			// to be "in play" here, and thus DOES NOT remove it (vs the cases above, which do.)
			break;
		default: 
			// Error
			OTLog::vError("OTLedger::GenerateBalanceStatement: wrong owner transaction type: %s\n",
						  theOwner.GetTypeString());
			break;
	}
	
	OTString	strMessageNym(theMessageNym); // Okay now we have the transaction numbers in this MessageNym string.

	pBalanceItem->SetAttachment(strMessageNym);				// <======== This is where the server will read the transaction numbers from (A nym in item.m_ascAttachment)
	
	// ---------------------------------------------------------

	long lCurrentBalance = theAccount.GetBalance();
	
	pBalanceItem->SetAmount(lCurrentBalance + lAdjustment);  // <==== Here's the new (predicted) balance for after the withdrawal is complete. (item.GetAmount)
	
	// ---------------------------------------------------------
	// loop through the INBOX transactions, and produce a sub-item onto pBalanceItem for each, which will
	// be a report on each transaction in this inbox, therefore added to the balance item.
	// (So the balance item contains a complete report on the receipts in this inbox.)
	OTTransaction * pTransaction = NULL;
	
	OTLog::Output(2, "About to loop through the inbox items and produce a report for each one...\n");
	
	for (mapOfTransactions::iterator ii = m_mapTransactions.begin(); 
		 ii != m_mapTransactions.end(); ++ii)
	{
		pTransaction = (*ii).second;
		
		OT_ASSERT(NULL != pTransaction);

		OTLog::Output(2, "Producing a report...\n");

		// it only reports receipts where we don't yet have balance agreement.
//      pTransaction->ProduceInboxReportItem(*pBalanceItem, const_cast<OTTransaction &>(theOwner));
		pTransaction->ProduceInboxReportItem(*pBalanceItem);	// <======= This function adds a receipt sub-item to pBalanceItem, where appropriate for INBOX items.
        // self note: I added the const_cast because the function needs to loop through it, even though it doesn't really change it
        // (doesn't violate the const, just needs to perform a loop and the const screws with the loop.)
	}
	
	// ---------------------------------------------------------
	
	theOutbox.ProduceOutboxReport(*pBalanceItem);	// <======= This function adds receipt sub-items to pBalanceItem, where appropriate for the OUTBOX items.
	
	// ---------------------------------------------------------
	
	pBalanceItem->SignContract(theNym); // <=== Sign, save, and return. OTTransactionType needs to weasel in a "date signed" variable.
	pBalanceItem->SaveContract();
	
	return pBalanceItem;
}
Beispiel #15
0
// LoadContract will call this function at the right time.
// return -1 if error, 0 if nothing, and 1 if the node was processed.
int OTLedger::ProcessXMLNode(irr::io::IrrXMLReader*& xml)
{	
	OTString strKeyName;
	OTString strKeyValue;
	
	OTString strTransaction;
	OTASCIIArmor ascTransaction;
	
	if (!strcmp("accountLedger", xml->getNodeName()))
	{	
		OTString strType, strLedgerAcctID, strLedgerAcctServerID, strUserID;
		
		strType = xml->getAttributeValue("type");
		
		if (strType.Compare("message"))
			m_Type = OTLedger::message;
		else if (strType.Compare("inbox"))
			m_Type = OTLedger::inbox;
		else if (strType.Compare("outbox"))
			m_Type = OTLedger::outbox;
		else if (strType.Compare("nymbox"))
			m_Type = OTLedger::nymbox;
		else
			m_Type = OTLedger::error_state;
	
		m_strVersion			= xml->getAttributeValue("version");	
		strLedgerAcctID			= xml->getAttributeValue("accountID"); 
		strLedgerAcctServerID	= xml->getAttributeValue("serverID");
		strUserID				= xml->getAttributeValue("userID");
		
		OTIdentifier ACCOUNT_ID(strLedgerAcctID), SERVER_ID(strLedgerAcctServerID), USER_ID(strUserID);
		
		SetPurportedAccountID(ACCOUNT_ID);
		SetPurportedServerID(SERVER_ID);
		SetUserID(USER_ID);
		
		OTLog::vOutput(2, "Loaded account ledger of type \"%s\", version: %s\n",
//				"accountID:\n%s\n userID:\n%s\n serverID:\n%s\n----------\n", 
				strType.Get(),
				m_strVersion.Get()
//				strLedgerAcctID.Get(), strUserID.Get(), strLedgerAcctServerID.Get()
				);
			
		// Since we just loaded this stuff, let's verify it.
		// We may have to remove this verification here and do it outside this call.
		// But for now...
		if (VerifyContractID())
			return 1;
		else {
			return -1;
		}

	}
	else if (!strcmp("transaction", xml->getNodeName()))
	{
		// go to the next node and read the text.
		xml->read();
		
		if (EXN_TEXT == xml->getNodeType())
		{
			// the ledger contains a series of transactions.
			// Each transaction is initially stored as an OTASCIIArmor string.
			ascTransaction.Set(xml->getNodeData());		// Put the ascii-armored node data into the ascii-armor object
			ascTransaction.GetString(strTransaction);	// Decode that into strTransaction, so we can load the transaction object from that string.
			OTTransaction * pTransaction = new OTTransaction(GetUserID(), GetPurportedAccountID(), GetPurportedServerID());
			
			// If we're able to successfully base64-decode the string and load it up as
			// a transaction, then let's add it to the ledger's list of transactions
			if (pTransaction && pTransaction->LoadContractFromString(strTransaction)
				&& pTransaction->VerifyContractID())
				// I responsible here to call pTransaction->VerifyContract() since
				// I am loading it here and adding it to the ledger. (So I do.)
			{
				m_mapTransactions[pTransaction->GetTransactionNum()] = pTransaction;
//				OTLog::Output(5, "Loaded transaction and adding to m_mapTransactions in OTLedger\n");
			}
			else {
				OTLog::Error("ERROR: loading transaction in OTLedger::ProcessXMLNode\n");
				if (pTransaction)
				{
					delete pTransaction;
					pTransaction = NULL;
				}
				return (-1);
			}

		}
		else {
			OTLog::Error("Error in OTLedger::ProcessXMLNode: transaction without value.\n");
			return (-1); // error condition
		}
		
		return 1;
	}
	
	return 0;
}