Skip to content

Commit d8cf6fb

Browse files
committed
add AccountPermission
1 parent 63209c2 commit d8cf6fb

19 files changed

+502
-6
lines changed

include/xrpl/protocol/Feature.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ namespace detail {
8080
// Feature.cpp. Because it's only used to reserve storage, and determine how
8181
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
8282
// the actual number of amendments. A LogicError on startup will verify this.
83-
static constexpr std::size_t numFeatures = 79;
83+
static constexpr std::size_t numFeatures = 80;
8484

8585
/** Amendments that this server supports and the default voting behavior.
8686
Whether they are enabled depends on the Rules defined in the validated

include/xrpl/protocol/Indexes.h

+11
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,17 @@ amm(Issue const& issue1, Issue const& issue2) noexcept;
272272
Keylet
273273
amm(uint256 const& amm) noexcept;
274274

275+
/** An AccountPermission */
276+
/** @{ */
277+
Keylet
278+
accountPermission(
279+
AccountID const& account,
280+
AccountID const& authorizedAccount) noexcept;
281+
282+
Keylet
283+
accountPermission(uint256 const& key) noexcept;
284+
/** @} */
285+
275286
Keylet
276287
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType);
277288

include/xrpl/protocol/Permissions.h

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//------------------------------------------------------------------------------
2+
/*
3+
This file is part of rippled: https://github.com/ripple/rippled
4+
Copyright (c) 2024 Ripple Labs Inc.
5+
6+
Permission to use, copy, modify, and/or distribute this software for any
7+
purpose with or without fee is hereby granted, provided that the above
8+
copyright notice and this permission notice appear in all copies.
9+
10+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13+
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17+
*/
18+
//==============================================================================
19+
20+
#ifndef RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED
21+
#define RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED
22+
23+
#include <optional>
24+
#include <string>
25+
#include <unordered_map>
26+
27+
namespace ripple {
28+
29+
/**
30+
* We have transaction type permissions and granular type
31+
* permissions. Since we will reuse the TransactionFormats to parse the
32+
* Transaction Permissions, we only define the GranularPermissionType here.
33+
*/
34+
35+
enum GranularPermissionType : std::uint32_t {
36+
gpTrustlineAuthorize = 65537,
37+
38+
gpTrustlineFreeze = 65538,
39+
40+
gpTrustlineUnfreeze = 65539,
41+
42+
gpAccountDomainSet = 65540,
43+
44+
gpAccountEmailHashSet = 65541,
45+
46+
gpAccountMessageKeySet = 65542,
47+
48+
gpAccountTransferRateSet = 65543,
49+
50+
gpAccountTickSizeSet = 65544,
51+
52+
gpPaymentMint = 65545,
53+
54+
gpPaymentBurn = 65546,
55+
56+
gpMPTokenIssuanceLock = 65547,
57+
58+
gpMPTokenIssuanceUnlock = 65548,
59+
};
60+
61+
class Permission
62+
{
63+
private:
64+
Permission();
65+
66+
std::unordered_map<std::string, GranularPermissionType>
67+
granularPermissionMap;
68+
69+
public:
70+
static Permission const&
71+
getInstance();
72+
73+
std::optional<std::uint32_t>
74+
getGranularValue(const std::string& name) const;
75+
76+
bool
77+
isProhibited(const std::string& name) const;
78+
};
79+
80+
} // namespace ripple
81+
82+
#endif

include/xrpl/protocol/detail/features.macro

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ XRPL_FIX (1513, Supported::yes, VoteBehavior::DefaultYe
9494
XRPL_FEATURE(FlowCross, Supported::yes, VoteBehavior::DefaultYes)
9595
XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes)
9696
XRPL_FEATURE(OwnerPaysFee, Supported::no, VoteBehavior::DefaultNo)
97+
XRPL_FEATURE(AccountPermission, Supported::yes, VoteBehavior::DefaultYes)
9798

9899
// The following amendments are obsolete, but must remain supported
99100
// because they could potentially get enabled.

include/xrpl/protocol/detail/ledger_entries.macro

+13
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,16 @@ LEDGER_ENTRY(ltORACLE, 0x0080, Oracle, ({
392392
{sfPreviousTxnID, soeREQUIRED},
393393
{sfPreviousTxnLgrSeq, soeREQUIRED},
394394
}))
395+
396+
/** A ledger object representing permissions an account has delegated to another account.
397+
398+
\sa keylet::accountPermission
399+
*/
400+
LEDGER_ENTRY(ltACCOUNT_PERMISSION, 0x0081, AccountPermission, ({
401+
{sfAccount, soeREQUIRED},
402+
{sfAuthorize, soeREQUIRED},
403+
{sfPermissions, soeREQUIRED},
404+
{sfOwnerNode, soeREQUIRED},
405+
{sfPreviousTxnID, soeREQUIRED},
406+
{sfPreviousTxnLgrSeq, soeREQUIRED},
407+
}))

include/xrpl/protocol/detail/sfields.macro

+3
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ TYPED_SFIELD(sfEmitGeneration, UINT32, 46)
111111
TYPED_SFIELD(sfVoteWeight, UINT32, 48)
112112
TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
113113
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
114+
TYPED_SFIELD(sfPermissionValue, UINT32, 52)
114115

115116
// 64-bit integers (common)
116117
TYPED_SFIELD(sfIndexNext, UINT64, 1)
@@ -309,6 +310,7 @@ UNTYPED_SFIELD(sfSignerEntry, OBJECT, 11)
309310
UNTYPED_SFIELD(sfNFToken, OBJECT, 12)
310311
UNTYPED_SFIELD(sfEmitDetails, OBJECT, 13)
311312
UNTYPED_SFIELD(sfHook, OBJECT, 14)
313+
UNTYPED_SFIELD(sfPermission, OBJECT, 15)
312314

313315
// inner object (uncommon)
314316
UNTYPED_SFIELD(sfSigner, OBJECT, 16)
@@ -355,3 +357,4 @@ UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22)
355357
// 23 unused
356358
UNTYPED_SFIELD(sfPriceDataSeries, ARRAY, 24)
357359
UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25)
360+
UNTYPED_SFIELD(sfPermissions, ARRAY, 26)

include/xrpl/protocol/detail/transactions.macro

+6
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,12 @@ TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix, ({
386386
{sfOwner, soeOPTIONAL},
387387
}))
388388

389+
/** This transaction type delegates authorized account specified permissions */
390+
TRANSACTION(ttACCOUNT_PERMISSION_SET, 54, AccountPermissionSet, ({
391+
{sfAuthorize, soeREQUIRED},
392+
{sfPermissions, soeREQUIRED},
393+
}))
394+
389395
/** This system-generated transaction type is used to update the status of the various amendments.
390396

391397
For details, see: https://xrpl.org/amendments.html

include/xrpl/protocol/jss.h

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ namespace jss {
4545
JSS(AL_size); // out: GetCounts
4646
JSS(AL_hit_rate); // out: GetCounts
4747
JSS(Account); // in: TransactionSign; field.
48+
JSS(AccountPermission); // ledger type.
4849
JSS(AccountRoot); // ledger type.
4950
JSS(AMM); // ledger type
5051
JSS(AMMID); // field
@@ -126,6 +127,7 @@ JSS(account_hash); // out: LedgerToJson
126127
JSS(account_id); // out: WalletPropose
127128
JSS(account_nfts); // out: AccountNFTs
128129
JSS(account_objects); // out: AccountObjects
130+
JSS(account_permission); // in: AccountPermission
129131
JSS(account_root); // in: LedgerEntry
130132
JSS(account_sequence_next); // out: SubmitTransaction
131133
JSS(account_sequence_available); // out: SubmitTransaction

src/libxrpl/protocol/Indexes.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ enum class LedgerNameSpace : std::uint16_t {
7373
XCHAIN_CREATE_ACCOUNT_CLAIM_ID = 'K',
7474
DID = 'I',
7575
ORACLE = 'R',
76+
ACCOUNT_PERMISSION = 'P',
7677

7778
// No longer used or supported. Left here to reserve the space
7879
// to avoid accidental reuse.
@@ -398,6 +399,23 @@ amm(uint256 const& id) noexcept
398399
return {ltAMM, id};
399400
}
400401

402+
Keylet
403+
accountPermission(
404+
AccountID const& account,
405+
AccountID const& authorizedAccount) noexcept
406+
{
407+
return {
408+
ltACCOUNT_PERMISSION,
409+
indexHash(
410+
LedgerNameSpace::ACCOUNT_PERMISSION, account, authorizedAccount)};
411+
}
412+
413+
Keylet
414+
accountPermission(uint256 const& key) noexcept
415+
{
416+
return {ltACCOUNT_PERMISSION, key};
417+
}
418+
401419
Keylet
402420
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType)
403421
{

src/libxrpl/protocol/InnerObjectFormats.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ InnerObjectFormats::InnerObjectFormats()
147147
{sfAssetPrice, soeOPTIONAL},
148148
{sfScale, soeDEFAULT},
149149
});
150+
151+
add(sfPermission.jsonName.c_str(),
152+
sfPermission.getCode(),
153+
{{sfPermissionValue, soeREQUIRED}});
150154
}
151155

152156
InnerObjectFormats const&

src/libxrpl/protocol/Permissions.cpp

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//------------------------------------------------------------------------------
2+
/*
3+
This file is part of rippled: https://github.com/ripple/rippled
4+
Copyright (c) 2024 Ripple Labs Inc.
5+
6+
Permission to use, copy, modify, and/or distribute this software for any
7+
purpose with or without fee is hereby granted, provided that the above
8+
copyright notice and this permission notice appear in all copies.
9+
10+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13+
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17+
*/
18+
//==============================================================================
19+
20+
#include <xrpl/protocol/Permissions.h>
21+
#include <xrpl/protocol/SField.h>
22+
#include <xrpl/protocol/SOTemplate.h>
23+
#include <xrpl/protocol/jss.h>
24+
25+
namespace ripple {
26+
27+
Permission::Permission()
28+
{
29+
granularPermissionMap = {
30+
{"TrustlineAuthorize", gpTrustlineAuthorize},
31+
{"TrustlineFreeze", gpTrustlineFreeze},
32+
{"TrustlineUnfreeze", gpTrustlineUnfreeze},
33+
{"AccountDomainSet", gpAccountDomainSet},
34+
{"AccountEmailHashSet", gpAccountEmailHashSet},
35+
{"AccountMessageKeySet", gpAccountMessageKeySet},
36+
{"AccountTransferRateSet", gpAccountTransferRateSet},
37+
{"AccountTickSizeSet", gpAccountTickSizeSet},
38+
{"PaymentMint", gpPaymentMint},
39+
{"PaymentBurn", gpPaymentBurn},
40+
{"MPTokenIssuanceLock", gpMPTokenIssuanceLock},
41+
{"MPTokenIssuanceUnlock", gpMPTokenIssuanceUnlock}};
42+
}
43+
44+
Permission const&
45+
Permission::getInstance()
46+
{
47+
static Permission const instance;
48+
return instance;
49+
}
50+
51+
std::optional<std::uint32_t>
52+
Permission::getGranularValue(const std::string& name) const
53+
{
54+
auto const it = granularPermissionMap.find(name);
55+
if (it != granularPermissionMap.end())
56+
return static_cast<uint32_t>(it->second);
57+
58+
return std::nullopt;
59+
}
60+
61+
bool
62+
Permission::isProhibited(const std::string& name) const
63+
{
64+
// We do not allow delegating the following transaction permissions to other
65+
// accounts for security reason.
66+
if (name == "AccountSet" || name == "SetRegularKey" ||
67+
name == "SignerListSet")
68+
return true;
69+
70+
return false;
71+
}
72+
73+
} // namespace ripple

src/libxrpl/protocol/STParsedJSON.cpp

+39-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <xrpl/beast/core/LexicalCast.h>
2424
#include <xrpl/protocol/ErrorCodes.h>
2525
#include <xrpl/protocol/LedgerFormats.h>
26+
#include <xrpl/protocol/Permissions.h>
2627
#include <xrpl/protocol/SField.h>
2728
#include <xrpl/protocol/STAccount.h>
2829
#include <xrpl/protocol/STAmount.h>
@@ -360,10 +361,44 @@ parseLeaf(
360361
{
361362
if (value.isString())
362363
{
363-
ret = detail::make_stvar<STUInt32>(
364-
field,
365-
beast::lexicalCastThrow<std::uint32_t>(
366-
value.asString()));
364+
if (field == sfPermissionValue)
365+
{
366+
std::string const strValue = value.asString();
367+
auto const granularPermission =
368+
Permission::getInstance().getGranularValue(
369+
strValue);
370+
if (!granularPermission)
371+
{
372+
// if it's not granular permission, parse as
373+
// transaction type permission.
374+
if (Permission::getInstance().isProhibited(
375+
strValue))
376+
{
377+
// we do not allow delegating some transaction
378+
// type permissions to other accounts for
379+
// security reason.
380+
error = invalid_data(json_name, fieldName);
381+
return ret;
382+
}
383+
else
384+
ret = detail::make_stvar<STUInt32>(
385+
field,
386+
static_cast<std::uint32_t>(
387+
TxFormats::getInstance().findTypeByName(
388+
strValue) +
389+
1));
390+
}
391+
else
392+
ret = detail::make_stvar<STUInt32>(
393+
field, *granularPermission);
394+
}
395+
else
396+
{
397+
ret = detail::make_stvar<STUInt32>(
398+
field,
399+
beast::lexicalCastThrow<std::uint32_t>(
400+
value.asString()));
401+
}
367402
}
368403
else if (value.isInt())
369404
{

0 commit comments

Comments
 (0)