Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Work in Progress] add AccountPermission #5164

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from

Conversation

yinyiqian1
Copy link
Collaborator

@yinyiqian1 yinyiqian1 commented Oct 25, 2024

spec:
XRPLF/XRPL-Standards#217
XRPLF/XRPL-Standards#218

This PR includes the following changes:

  1. Added AccountPermissionSet transaction.
    to enable an account(delegating account) delegate some permissions to another account(delegated account), so that the delegated account can send transactions on behalf of the delegating account.
  2. Added Account_Permission ledger object
    The AccountPermissionSet transaction will create AccountPermission ledger object, with keylet(delegating account, delegated account)
  3. Added Onbehalf of common field.
  4. Permission has two types:
    a. transaction level permission
    b. granular permission which will be part of a transaction

more details:

  1. introduced account and isDelegated in PreflightContext, PreclaimContext and ApplyContext. The account is the account which is the transaction being operated on.
  2. transactor's member account_ is updated to the account which is the transaction being operated on.
  3. a set of Granular Permissions gpSet is added to ApplyContext. It contains the granular permissions enabled for that transaction. But if the transaction is fully delegated, then even there are granular permissions related to that transaction, the gpSet will be cleared up. To be more specific:
    a. isDelegated=true && gpSet not empty: only granular permissions delegated to the transaction
    b. isDelegated=true && gpSet is empty: the transaction is fully delegated
  4. only the granular permissions listed in Permissions.cpp are supported, so the unauthorized granular operations and the other parts under these transactions are prohibited under granular permission mode.

High Level Overview of Change

Context of Change

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (non-breaking change that only restructures code)
  • Performance (increase or change in throughput and/or latency)
  • Tests (you added tests for code that already exists, or your new feature included in this PR)
  • Documentation update
  • Chore (no impact to binary, e.g. .gitignore, formatting, dropping support for older tooling)
  • Release

API Impact

  • Public API: New feature (new methods and/or new fields)
  • Public API: Breaking change (in general, breaking changes should only impact the next api_version)
  • libxrpl change (any change that may affect libxrpl or dependents of libxrpl)
  • Peer protocol change (must be backward compatible or bump the peer protocol version)

@yinyiqian1 yinyiqian1 marked this pull request as draft October 25, 2024 19:01
Copy link

codecov bot commented Oct 25, 2024

Codecov Report

Attention: Patch coverage is 48.30287% with 198 lines in your changes missing coverage. Please review.

Project coverage is 77.6%. Comparing base (838978b) to head (372cc5c).
Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
src/xrpld/app/tx/detail/AccountPermissionSet.cpp 0.0% 59 Missing ⚠️
src/libxrpl/protocol/Permissions.cpp 0.0% 34 Missing ⚠️
src/xrpld/app/tx/detail/Transactor.cpp 8.8% 31 Missing ⚠️
src/xrpld/app/tx/detail/SetTrust.cpp 22.7% 17 Missing ⚠️
src/libxrpl/protocol/STParsedJSON.cpp 23.5% 13 Missing ⚠️
src/xrpld/app/tx/detail/Payment.cpp 20.0% 12 Missing ⚠️
src/xrpld/app/tx/detail/SetAccount.cpp 59.1% 9 Missing ⚠️
src/libxrpl/protocol/Indexes.cpp 0.0% 5 Missing ⚠️
src/xrpld/app/tx/detail/DeleteAccount.cpp 28.6% 5 Missing ⚠️
src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp 58.3% 5 Missing ⚠️
... and 3 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##           develop   #5164     +/-   ##
=========================================
- Coverage     77.9%   77.6%   -0.3%     
=========================================
  Files          782     785      +3     
  Lines        66621   66847    +226     
  Branches      8161    8277    +116     
=========================================
- Hits         51902   51897      -5     
- Misses       14719   14950    +231     
Files with missing lines Coverage Δ
include/xrpl/protocol/Feature.h 100.0% <ø> (ø)
include/xrpl/protocol/Indexes.h 100.0% <ø> (ø)
include/xrpl/protocol/detail/ledger_entries.macro 100.0% <100.0%> (ø)
include/xrpl/protocol/detail/transactions.macro 100.0% <100.0%> (ø)
src/libxrpl/protocol/InnerObjectFormats.cpp 100.0% <100.0%> (ø)
src/libxrpl/protocol/TxFormats.cpp 100.0% <ø> (ø)
src/xrpld/app/tx/applySteps.h 100.0% <100.0%> (ø)
src/xrpld/app/tx/detail/AMMBid.cpp 90.4% <100.0%> (ø)
src/xrpld/app/tx/detail/AMMClawback.cpp 100.0% <100.0%> (ø)
src/xrpld/app/tx/detail/AMMCreate.cpp 90.5% <100.0%> (ø)
... and 45 more

... and 9 files with indirect coverage changes

Impacted file tree graph

---- 🚨 Try these New Features:

gpMPTokenIssuanceUnlock = 65548,
};

class Permission
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably delete copy and copy assignment constructors

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this still needs to be done?

{
auto const sleOwner = ctx_.view().peek(keylet::account(account_));
if (!sleOwner)
return {tefINTERNAL}; // LCOV_EXCL_LINE
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return {tefINTERNAL}; // LCOV_EXCL_LINE
return tecINTERNAL; // LCOV_EXCL_LINE

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

sle = std::make_shared<SLE>(accountPermissionKey);
auto const& permissions = ctx_.tx.getFieldArray(sfPermissions);
sle->setFieldArray(sfPermissions, permissions);
auto page = ctx_.view().dirInsert(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto page = ctx_.view().dirInsert(
auto const page = ctx_.view().dirInsert(

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

keylet::accountPermission(account_, ctx_.tx[sfAuthorize]);

auto sle = ctx_.view().peek(accountPermissionKey);
if (!sle)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be refactored like

auto sle = ctx_.view().peek(accountPermissionKey);
if (sle)
{
     auto const& permissions = ctx_.tx.getFieldArray(sfPermissions);
     sle->setFieldArray(sfPermissions, permissions);
     ctx_.view().update(sle); 
     return tesSUCCESS;
}
STAmount const reserve{ctx_.view().fees().accountReserve(
         sleOwner->getFieldU32(sfOwnerCount) + 1)};
 ...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

auto const accountPermissionKey =
keylet::accountPermission(account_, ctx_.tx[sfAuthorize]);

auto sle = ctx_.view().peek(accountPermissionKey);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto sle = ctx_.view().peek(accountPermissionKey);
auto const sle = ctx_.view().peek(accountPermissionKey);

Copy link
Collaborator Author

@yinyiqian1 yinyiqian1 Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to update sle later (sle = std::make_shared<SLE>(accountPermissionKey);). can not be const.

@yinyiqian1 yinyiqian1 force-pushed the account_permissions branch 3 times, most recently from 6101542 to bd7150e Compare November 5, 2024 21:50
@yinyiqian1 yinyiqian1 force-pushed the account_permissions branch 2 times, most recently from 04cf7ad to 5c1d6a3 Compare November 18, 2024 16:24
try
{
return {pfctx, invoke_preflight(pfctx)};
// if AccountPermission is not enabled, do not use OnBehalfOf field.
if (!rules.enabled(featureAccountPermission) && tx[~sfOnBehalfOf])
Copy link
Collaborator

@shawnxie999 shawnxie999 Nov 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so what's the behavior when someone submits a tx with sfOnBehalfOf but not enabled the amendment? what error code does it return? To me, i feel we should not be throwing a runtime error, because it's a completely acceptable input. pls consider performing this check in the Transactor::preflight1 instead and return an code like temDISABLED

@gregtatcam
Copy link
Collaborator

gregtatcam commented Nov 19, 2024

PR description should be added with a link to technical specifications if applicable.

@yinyiqian1
Copy link
Collaborator Author

PR description should be added with a link to technical specifications if applicable.

just added

@yinyiqian1
Copy link
Collaborator Author

FYI: unit test failures are transient, which have passed locally. "ERR:Env Env::close() failed: no response from server"

Copy link
Collaborator

@gregtatcam gregtatcam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a pass and left a few comments.
My big concern is how sfAccount is obfuscated by sfOnBehalfOf. sfAccount pretty much should never be used in the transactors with some exceptions. It's easy to miss these kind of errors where sfAccount is used instead of the account included in the context.

LEDGER_ENTRY(ltACCOUNT_PERMISSION, 0x0082, AccountPermission, ({
{sfAccount, soeREQUIRED},
{sfAuthorize, soeREQUIRED},
{sfPermissions, soeREQUIRED},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to make this optional since it could be empty?

/** This transaction type delegates authorized account specified permissions */
TRANSACTION(ttACCOUNT_PERMISSION_SET, 61, AccountPermissionSet, ({
{sfAuthorize, soeREQUIRED},
{sfPermissions, soeREQUIRED},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to make it optional since it could be empty?

*/

enum GranularPermissionType : std::uint32_t {
gpTrustlineAuthorize = 65537,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is gp prefix necessary? Can we just have TrustlineAuthorize, etc?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gp is to indicate it is a granular permission set's member. I'm ok with either way.

@@ -77,6 +77,7 @@ enum class LedgerNameSpace : std::uint16_t {
MPTOKEN_ISSUANCE = '~',
MPTOKEN = 't',
CREDENTIAL = 'D',
ACCOUNT_PERMISSION = 'P',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value is already used by DEPOSIT_PREAUTH_CREDENTIALS

{
auto permissionObj = dynamic_cast<STObject const*>(&permission);

if (!permissionObj || (permissionObj->getFName() != sfPermission))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed? If the array is invalid it should fail in the array parsing. And if the name is not Permission then it should fail also before it gets to the transactor. Should have a unit-test fo this.

@@ -197,7 +197,7 @@ preclaimHelper<MPTIssue>(
TER
Clawback::preclaim(PreclaimContext const& ctx)
{
AccountID const issuer = ctx.tx[sfAccount];
AccountID const issuer = ctx.account;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be const&. Please check everywhere where an alias variable is used for ctx.account. It should be AccountID const&.

if (ctx_.isDelegated && !ctx_.gpSet.empty())
{
// if gpSet is not empty, granular delegation is happening.
if (bLock && ctx_.gpSet.find(gpMPTokenIssuanceLock) == ctx_.gpSet.end())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can simplify here and below.

if (bLock && !ctx.gpSet.contains(gpMPTokenIssuanceLock))

auto const amountIssue = dstAmount.issue();
if (isXRP(amountIssue))
return tecNO_AUTH;
if (amountIssue.account == account_ &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can simplify here and below:

if (amountIssue.account == account_ &&
        ctx_.gpSet.contains(gpPaymentMint))

if (bSetNoRipple || bClearNoRipple || bQualityIn || bQualityOut)
return terNO_AUTH;
if (bSetAuth &&
ctx_.gpSet.find(gpTrustlineAuthorize) == ctx_.gpSet.end())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can simplify here and below:

if (bSetAuth &&
        !ctx_.gpSet.contains(gpTrustlineAuthorize))

@@ -458,6 +458,7 @@ LedgerEntryTypesMatch::visitEntry(
switch (after->getType())
{
case ltACCOUNT_ROOT:
case ltACCOUNT_PERMISSION:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't leave a comment on unchanged lines so commenting here for ValidClawback::finalize:924, which is this line:

 AccountID const issuer = tx.getAccountID(sfAccount);

The issuer in this case could be either sfAccount or sfOnBehalfOf, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missed out. I'll also check all the other similar places which is missed out.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gregtatcam
I also need to make change to AcceptedLedgerTx.cpp, LedgerToJson.cpp, and NetworkOPs.cpp, because they also check the account id when the transaction type is ttOFFER_CREATE. I'm working on this as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants