fix: uritoken destination & amount preflight check (#188)

* fix: uritoken destination & amount

* Update URIToken.cpp

* add lsfBurnable flag

* make uritoken patch a fix amendment

* clang-format
This commit is contained in:
Denis Angell
2023-11-10 10:42:57 +01:00
committed by GitHub
parent 559b504c7d
commit 4ada3f85bb
8 changed files with 51 additions and 8 deletions

View File

@@ -45,7 +45,6 @@ include(RippledSanity)
include(RippledVersion) include(RippledVersion)
include(RippledSettings) include(RippledSettings)
include(RippledNIH) include(RippledNIH)
# this check has to remain in the top-level cmake # this check has to remain in the top-level cmake
# because of the early return statement # because of the early return statement
if (packages_only) if (packages_only)

View File

@@ -135,7 +135,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
// issuer is also a strong TSH if the burnable flag is set // issuer is also a strong TSH if the burnable flag is set
auto const issuer = ut->getAccountID(sfIssuer); auto const issuer = ut->getAccountID(sfIssuer);
if (issuer != owner) if (issuer != owner)
ADD_TSH(issuer, ut->getFlags() & tfBurnable); ADD_TSH(issuer, ut->getFlags() & lsfBurnable);
break; break;
} }
@@ -154,7 +154,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
// issuer is a strong TSH if the burnable flag is set // issuer is a strong TSH if the burnable flag is set
if (issuer != owner) if (issuer != owner)
ADD_TSH(issuer, ut->getFlags() & tfBurnable); ADD_TSH(issuer, ut->getFlags() & lsfBurnable);
// destination is a strong tsh // destination is a strong tsh
if (tx.isFieldPresent(sfDestination)) if (tx.isFieldPresent(sfDestination))

View File

@@ -78,6 +78,17 @@ URIToken::preflight(PreflightContext const& ctx)
} }
} }
// fix amendment to return temMALFORMED if sfDestination field is present
// and sfAmount field is not present
if (ctx.rules.enabled(fixURITokenV1))
{
if (ctx.tx.isFieldPresent(sfDestination) &&
!ctx.tx.isFieldPresent(sfAmount))
{
return temMALFORMED;
}
}
// the validation for the URI field is also the same regardless of the txn // the validation for the URI field is also the same regardless of the txn
// type // type
if (ctx.tx.isFieldPresent(sfURI)) if (ctx.tx.isFieldPresent(sfURI))
@@ -231,7 +242,7 @@ URIToken::preclaim(PreclaimContext const& ctx)
} }
case ttURITOKEN_BURN: { case ttURITOKEN_BURN: {
if (leFlags == tfBurnable && acc == *issuer) if (leFlags == lsfBurnable && acc == *issuer)
{ {
// pass, the issuer can burn the URIToken if they minted it with // pass, the issuer can burn the URIToken if they minted it with
// a burn flag // a burn flag
@@ -805,9 +816,9 @@ URIToken::doApply()
} }
else if ( else if (
sleU->getAccountID(sfIssuer) == account_ && sleU->getAccountID(sfIssuer) == account_ &&
(sleU->getFlags() & tfBurnable)) (sleU->getFlags() & lsfBurnable))
{ {
// pass, issuer may burn if the tfBurnable flag was set during // pass, issuer may burn if the lsfBurnable flag was set during
// minting // minting
} }
else else

View File

@@ -74,7 +74,7 @@ namespace detail {
// Feature.cpp. Because it's only used to reserve storage, and determine how // Feature.cpp. Because it's only used to reserve storage, and determine how
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
// the actual number of amendments. A LogicError on startup will verify this. // the actual number of amendments. A LogicError on startup will verify this.
static constexpr std::size_t numFeatures = 65; static constexpr std::size_t numFeatures = 66;
/** Amendments that this server supports and the default voting behavior. /** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated Whether they are enabled depends on the Rules defined in the validated
@@ -353,6 +353,7 @@ extern uint256 const fixNFTokenRemint;
extern uint256 const featureImport; extern uint256 const featureImport;
extern uint256 const featureXahauGenesis; extern uint256 const featureXahauGenesis;
extern uint256 const featureHooksUpdate1; extern uint256 const featureHooksUpdate1;
extern uint256 const fixURITokenV1;
} // namespace ripple } // namespace ripple

View File

@@ -310,6 +310,9 @@ enum LedgerSpecificFlags {
// ltNFTOKEN_OFFER // ltNFTOKEN_OFFER
lsfSellNFToken = 0x00000001, lsfSellNFToken = 0x00000001,
// ltURI_TOKEN
lsfBurnable = 0x00000001, // True, issuer can burn the token
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -459,6 +459,7 @@ REGISTER_FEATURE(URIToken, Supported::yes, VoteBehavior::De
REGISTER_FEATURE(Import, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FEATURE(Import, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes);
REGISTER_FIX (fixURITokenV1, Supported::yes, VoteBehavior::DefaultNo);
// The following amendments are obsolete, but must remain supported // The following amendments are obsolete, but must remain supported

View File

@@ -260,6 +260,34 @@ struct URIToken_test : public beast::unit_test::suite
using namespace jtx; using namespace jtx;
using namespace std::literals::chrono_literals; using namespace std::literals::chrono_literals;
// fixURITokenV1
{
for (bool const withFixURITokenV1 : {true, false})
{
auto const amend =
withFixURITokenV1 ? features : features - fixURITokenV1;
auto const txResult =
withFixURITokenV1 ? ter(temMALFORMED) : ter(tefINTERNAL);
Env env{*this, amend};
auto const alice = Account("alice");
auto const bob = Account("bob");
env.fund(XRP(1000), alice, bob);
env.close();
std::string const uri(2, '?');
auto const tid = tokenid(alice, uri);
std::string const hexid{strHex(tid)};
// temMALFORMED - cannot include sfDestination without sfAmount
Json::Value destTx = mint(alice, uri);
destTx[jss::Destination] = bob.human();
env(destTx, txResult);
env.close();
}
}
// setup env // setup env
Env env{*this, features}; Env env{*this, features};
auto const alice = Account("alice"); auto const alice = Account("alice");

View File

@@ -1705,7 +1705,7 @@ public:
"json", "ledger_entry", to_string(jvParams))[jss::result]; "json", "ledger_entry", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::node][sfOwner.jsonName] == alice.human()); BEAST_EXPECT(jrr[jss::node][sfOwner.jsonName] == alice.human());
BEAST_EXPECT(jrr[jss::node][sfURI.jsonName] == strHex(uri)); BEAST_EXPECT(jrr[jss::node][sfURI.jsonName] == strHex(uri));
BEAST_EXPECT(jrr[jss::node][sfFlags.jsonName] == 1); BEAST_EXPECT(jrr[jss::node][sfFlags.jsonName] == lsfBurnable);
} }
{ {
// Request an index that is not a uritoken. // Request an index that is not a uritoken.