diff --git a/src/ripple/app/tx/impl/Escrow.cpp b/src/ripple/app/tx/impl/Escrow.cpp index cd0c6c328..1051fd71b 100644 --- a/src/ripple/app/tx/impl/Escrow.cpp +++ b/src/ripple/app/tx/impl/Escrow.cpp @@ -93,7 +93,8 @@ after(NetClock::time_point now, std::uint32_t mark) TxConsequences EscrowCreate::makeTxConsequences(PreflightContext const& ctx) { - return TxConsequences{ctx.tx, ctx.tx[sfAmount].xrp()}; + return TxConsequences{ctx.tx, + isXRP(ctx.tx[sfAmount]) ? ctx.tx[sfAmount].xrp() : beast::zero}; } NotTEC @@ -270,7 +271,7 @@ EscrowCreate::doApply() STAmount balance = (*sleLine)[sfBalance]; - STAmount lockedBalance {sfLockedBalance}; + STAmount lockedBalance {sfLockedBalance, amount.issue()}; if (sleLine->isFieldPresent(sfLockedBalance)) lockedBalance = (*sleLine)[sfLockedBalance]; @@ -343,10 +344,9 @@ EscrowCreate::doApply() else if (ctx_.view().rules().enabled(featurePaychanAndEscrowForTokens) && sleLine) { // update trustline to reflect locked up balance - auto const issuer = amount.getIssuer(); - bool high = account > issuer; + bool high = account > amount.getIssuer(); - STAmount lockedBalance; + STAmount lockedBalance {sfLockedBalance, amount.issue()}; if (sleLine->isFieldPresent(sfLockedBalance)) lockedBalance = (*sleLine)[sfLockedBalance]; @@ -898,7 +898,11 @@ EscrowCancel::doApply() } sleSrcLine->setFieldAmount(sfBalance, isLow ? finalBalance : -finalBalance); - sleSrcLine->setFieldAmount(sfLockedBalance, isLow ? finalLockedBalance : -finalLockedBalance); + + if (finalLockedBalance == beast::zero) + sleSrcLine->makeFieldAbsent(sfLockedBalance); + else + sleSrcLine->setFieldAmount(sfLockedBalance, isLow ? finalLockedBalance : -finalLockedBalance); view.update(sleSrcLine); } diff --git a/src/ripple/app/tx/impl/InvariantCheck.cpp b/src/ripple/app/tx/impl/InvariantCheck.cpp index 73b20a0f1..9d158678a 100644 --- a/src/ripple/app/tx/impl/InvariantCheck.cpp +++ b/src/ripple/app/tx/impl/InvariantCheck.cpp @@ -95,11 +95,14 @@ XRPNotCreated::visitEntry( drops_ -= (*before)[sfBalance].xrp().drops(); break; case ltPAYCHAN: - drops_ -= - ((*before)[sfAmount] - (*before)[sfBalance]).xrp().drops(); + if (isXRP((*before)[sfAmount])) + drops_ -= + ((*before)[sfAmount] - (*before)[sfBalance]).xrp().drops(); break; case ltESCROW: - drops_ -= (*before)[sfAmount].xrp().drops(); + if (isXRP((*before)[sfAmount])) + drops_ -= + (*before)[sfAmount].xrp().drops(); break; default: break; @@ -114,14 +117,14 @@ XRPNotCreated::visitEntry( drops_ += (*after)[sfBalance].xrp().drops(); break; case ltPAYCHAN: - if (!isDelete) - drops_ += ((*after)[sfAmount] - (*after)[sfBalance]) - .xrp() - .drops(); + if (!isDelete && isXRP((*after)[sfAmount])) + drops_ += + ((*after)[sfAmount] - (*after)[sfBalance]).xrp().drops(); break; case ltESCROW: - if (!isDelete) - drops_ += (*after)[sfAmount].xrp().drops(); + if (!isDelete && isXRP((*after)[sfAmount])) + drops_ += + (*after)[sfAmount].xrp().drops(); break; default: break; @@ -281,12 +284,26 @@ NoZeroEscrow::visitEntry( bool NoZeroEscrow::finalize( - STTx const&, + STTx const& txn, TER const, XRPAmount const, - ReadView const&, + ReadView const& rv, beast::Journal const& j) { + // bypass this invariant check for IOU escrows + if (bad_ && + rv.rules().enabled(featurePaychanAndEscrowForTokens) && + txn.isFieldPresent(sfTransactionType) && + txn.isFieldPresent(sfAmount)) + { + uint16_t tt = txn.getFieldU16(sfTransactionType); + if (tt == ttESCROW_CREATE || tt == ttESCROW_FINISH || tt == ttESCROW_CANCEL) + { + if (!isXRP(txn.getFieldAmount(sfAmount))) + return true; + } + } + if (bad_) { JLOG(j.fatal()) << "Invariant failed: escrow specifies invalid amount";