diff --git a/src/cpp/ripple/OfferCreateTransactor.cpp b/src/cpp/ripple/OfferCreateTransactor.cpp index afff90699..686b21e83 100644 --- a/src/cpp/ripple/OfferCreateTransactor.cpp +++ b/src/cpp/ripple/OfferCreateTransactor.cpp @@ -426,6 +426,17 @@ TER OfferCreateTransactor::doApply() terResult = terNO_ACCOUNT; } + else if (isSetBit(sleTakerPays->getFieldU32(sfFlags), lsfRequireAuth)) { + SLE::pointer sleRippleState = mEngine->entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uPaysIssuerID, uPaysCurrency)); + bool bHigh = mTxnAccountID > uPaysIssuerID; + + if (!sleRippleState + || !isSetBit(sleRippleState->getFieldU32(sfFlags), (bHigh ? lsfHighAuth : lsfLowAuth))) { + cLog(lsWARNING) << "OfferCreate: delay: can't receive IOUs from issuer without auth."; + + terResult = terNO_AUTH; + } + } } STAmount saPaid; diff --git a/src/cpp/ripple/RippleCalc.cpp b/src/cpp/ripple/RippleCalc.cpp index 213923acf..b8a0b0f0e 100644 --- a/src/cpp/ripple/RippleCalc.cpp +++ b/src/cpp/ripple/RippleCalc.cpp @@ -114,7 +114,7 @@ TER PathState::pushImply( // Append a node and insert before it any implied nodes. // Offers may go back to back. -// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_LINE, tecPATH_DRY +// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_ACCOUNT, terNO_AUTH, terNO_LINE, tecPATH_DRY TER PathState::pushNode( const int iType, const uint160& uAccountID, @@ -231,11 +231,30 @@ TER PathState::pushNode( << STAmount::createHumanCurrency(pnCur.uCurrencyID) << "." ; - STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID); + SLE::pointer sleBck = lesEntries.entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(pnBck.uAccountID)); + bool bHigh = pnBck.uAccountID > pnCur.uAccountID; - if (!saOwed.isPositive() && -saOwed >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID)) + if (!sleBck) { - terResult = tecPATH_DRY; + cLog(lsWARNING) << "pushNode: delay: can't receive IOUs from non-existent issuer: " << RippleAddress::createHumanAccountID(pnBck.uAccountID); + + terResult = terNO_ACCOUNT; + } + else if (isSetBit(sleBck->getFieldU32(sfFlags), lsfRequireAuth) + && !isSetBit(sleRippleState->getFieldU32(sfFlags), (bHigh ? lsfHighAuth : lsfLowAuth))) { + cLog(lsWARNING) << "pushNode: delay: can't receive IOUs from issuer without auth."; + + terResult = terNO_AUTH; + } + + if (tesSUCCESS == terResult) + { + STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID); + + if (!saOwed.isPositive() && -saOwed >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID)) + { + terResult = tecPATH_DRY; + } } } } @@ -287,7 +306,7 @@ TER PathState::pushNode( // Set to an expanded path. // -// terStatus = tesSUCCESS, temBAD_PATH, terNO_LINE, or temBAD_PATH_LOOP +// terStatus = tesSUCCESS, temBAD_PATH, terNO_LINE, terNO_ACCOUNT, terNO_AUTH, or temBAD_PATH_LOOP void PathState::setExpanded( const LedgerEntrySet& lesSource, const STPath& spSourcePath, diff --git a/src/cpp/ripple/TransactionErr.cpp b/src/cpp/ripple/TransactionErr.cpp index a605a2f49..160064ffe 100644 --- a/src/cpp/ripple/TransactionErr.cpp +++ b/src/cpp/ripple/TransactionErr.cpp @@ -82,6 +82,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) { terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." }, { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." }, { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." }, + { terNO_AUTH, "terNO_AUTH", "Not authorized to hold IOUs." }, { terNO_LINE, "terNO_LINE", "No such line." }, { terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction." }, { terOWNERS, "terOWNERS", "Non-zero owner count." }, diff --git a/src/cpp/ripple/TransactionErr.h b/src/cpp/ripple/TransactionErr.h index a1d9fb690..fe54d9f4b 100644 --- a/src/cpp/ripple/TransactionErr.h +++ b/src/cpp/ripple/TransactionErr.h @@ -95,6 +95,7 @@ enum TER // aka TransactionEngineResult terFUNDS_SPENT, // This is a free transaction, therefore don't burden network. terINSUF_FEE_B, // Can't pay fee, therefore don't burden network. terNO_ACCOUNT, // Can't pay fee, therefore don't burden network. + terNO_AUTH, // Not authorized to hold IOUs. terNO_LINE, // Internal flag. terOWNERS, // Can't succeed with non-zero owner count. terPRE_SEQ, // Can't pay fee, no point in forwarding, therefore don't burden network. diff --git a/test/path-test.js b/test/path-test.js index 59ffd8cc0..ee75afbd6 100644 --- a/test/path-test.js +++ b/test/path-test.js @@ -1189,8 +1189,8 @@ buster.testCase("Indirect paths", { }); buster.testCase("Quality paths", { - // 'setUp' : testutils.build_setup(), - 'setUp' : testutils.build_setup({ verbose: true }), + 'setUp' : testutils.build_setup(), + // 'setUp' : testutils.build_setup({ verbose: true }), // 'setUp' : testutils.build_setup({ verbose: true, no_server: true }), 'tearDown' : testutils.build_teardown(),