Skip to content

Commit

Permalink
initial DID implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mvadari committed Jul 31, 2023
1 parent aded4a7 commit cef1f64
Show file tree
Hide file tree
Showing 23 changed files with 804 additions and 12 deletions.
2 changes: 2 additions & 0 deletions Builds/CMake/RippledCore.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ target_sources (rippled PRIVATE
src/ripple/app/tx/impl/CreateTicket.cpp
src/ripple/app/tx/impl/DeleteAccount.cpp
src/ripple/app/tx/impl/DepositPreauth.cpp
src/ripple/app/tx/impl/DID.cpp
src/ripple/app/tx/impl/Escrow.cpp
src/ripple/app/tx/impl/InvariantCheck.cpp
src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp
Expand Down Expand Up @@ -760,6 +761,7 @@ if (tests)
src/test/app/DeliverMin_test.cpp
src/test/app/DepositAuth_test.cpp
src/test/app/Discrepancy_test.cpp
src/test/app/DID_test.cpp
src/test/app/DNS_test.cpp
src/test/app/Escrow_test.cpp
src/test/app/FeeVote_test.cpp
Expand Down
215 changes: 215 additions & 0 deletions src/ripple/app/tx/impl/DID.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================

#include <ripple/app/tx/impl/DID.h>

#include <ripple/basics/Log.h>
#include <ripple/ledger/ApplyView.h>
#include <ripple/ledger/View.h>
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/protocol/st.h>

namespace ripple {

/*
DID
======
TODO: add docs here
*/

//------------------------------------------------------------------------------

NotTEC
DIDSet::preflight(PreflightContext const& ctx)
{
if (!ctx.rules.enabled(featureDID))
return temDISABLED;

if (ctx.tx.getFlags() & tfUniversalMask)
return temINVALID_FLAG;

if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
return ret;

if (!ctx.tx.isFieldPresent(sfURI) && !ctx.tx.isFieldPresent(sfData))
return temEMPTY_DID;

if (ctx.tx.isFieldPresent(sfURI) && ctx.tx[sfURI].empty() &&
ctx.tx.isFieldPresent(sfData) && ctx.tx[sfData].empty())
return temEMPTY_DID;

return preflight2(ctx);
}

TER
addSLE(
ApplyContext& ctx,
std::shared_ptr<SLE> const& sle,
AccountID const& owner)
{
auto const sleAccount = ctx.view().peek(keylet::account(owner));
if (!sleAccount)
return tefINTERNAL;

// Check reserve availability for new object creation
{
auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
auto const reserve =
ctx.view().fees().accountReserve((*sleAccount)[sfOwnerCount] + 1);

if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
}

// Add ledger object to ledger
ctx.view().insert(sle);

// Add ledger object to owner's page
{
auto page = ctx.view().dirInsert(
keylet::ownerDir(owner), sle->key(), describeOwnerDir(owner));
if (!page)
return tecDIR_FULL;
(*sle)[sfOwnerNode] = *page;
}
adjustOwnerCount(ctx.view(), sleAccount, 1, ctx.journal);
ctx.view().update(sleAccount);

return tesSUCCESS;
}

TER
DIDSet::doApply()
{
// Edit ledger object if it already exists
Keylet const didKeylet = keylet::did(account_);
if (auto const sleDID = ctx_.view().peek(didKeylet))
{
if (auto const uri = ctx_.tx[~sfURI])
{
if (uri->empty())
{
sleDID->makeFieldAbsent(sfURI);
}
else
{
(*sleDID)[sfURI] = *uri;
}
}
if (auto const data = ctx_.tx[~sfData])
{
if (data->empty())
{
sleDID->makeFieldAbsent(sfData);
}
else
{
(*sleDID)[sfData] = *data;
}
}
if (!sleDID->isFieldPresent(sfURI) && !sleDID->isFieldPresent(sfData))
{
return tecEMPTY_DID;
}
ctx_.view().update(sleDID);
return tesSUCCESS;
}

// Create new ledger object otherwise
auto const sleDID = std::make_shared<SLE>(didKeylet);
(*sleDID)[sfAccount] = account_;
if (auto const uri = ctx_.tx[~sfURI]; uri.has_value() && !uri->empty())
(*sleDID)[sfURI] = uri.value();
if (auto const data = ctx_.tx[~sfData]; data.has_value() && !data->empty())
(*sleDID)[sfData] = data.value();

if (auto const ret = addSLE(ctx_, sleDID, account_); !isTesSuccess(ret))
return ret;

return tesSUCCESS;
}

NotTEC
DIDDelete::preflight(PreflightContext const& ctx)
{
if (!ctx.rules.enabled(featureDID))
return temDISABLED;

if (ctx.tx.getFlags() & tfUniversalMask)
return temINVALID_FLAG;

if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
return ret;

return preflight2(ctx);
}

TER
DIDDelete::deleteSLE(ApplyContext& ctx, Keylet sleKeylet, AccountID const owner)
{
auto const sle = ctx.view().peek(sleKeylet);
if (!sle)
return tecNO_ENTRY;

return DIDDelete::deleteSLE(ctx.view(), sle, owner, ctx.journal);
}

TER
DIDDelete::deleteSLE(
ApplyView& view,
std::shared_ptr<SLE> sle,
AccountID const owner,
beast::Journal j)
{
// Remove object from owner directory
{
auto const page = (*sle)[sfOwnerNode];
if (!view.dirRemove(keylet::ownerDir(owner), page, sle->key(), true))
{
JLOG(j.fatal()) << "Unable to delete DID Token from owner.";
return tefBAD_LEDGER;
}
}

auto const sleOwner = view.peek(keylet::account(owner));
adjustOwnerCount(view, sleOwner, -1, j);
view.update(sleOwner);

// Remove object from ledger
view.erase(sle);
return tesSUCCESS;
}

TER
DIDDelete::doApply()
{
AccountID const account = ctx_.tx[sfAccount];
auto const didKeylet = keylet::did(account);

if (auto const ret = deleteSLE(ctx_, didKeylet, account_);
!isTesSuccess(ret))
return ret;

return tesSUCCESS;
}

} // namespace ripple
73 changes: 73 additions & 0 deletions src/ripple/app/tx/impl/DID.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================

#ifndef RIPPLE_TX_DID_H_INCLUDED
#define RIPPLE_TX_DID_H_INCLUDED

#include <ripple/app/tx/impl/Transactor.h>

namespace ripple {

class DIDSet : public Transactor
{
public:
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};

explicit DIDSet(ApplyContext& ctx) : Transactor(ctx)
{
}

static NotTEC
preflight(PreflightContext const& ctx);

TER
doApply() override;
};

//------------------------------------------------------------------------------

class DIDDelete : public Transactor
{
public:
static constexpr ConsequencesFactoryType ConsequencesFactory{Normal};

explicit DIDDelete(ApplyContext& ctx) : Transactor(ctx)
{
}

static NotTEC
preflight(PreflightContext const& ctx);

static TER
deleteSLE(ApplyContext& ctx, Keylet sleKeylet, AccountID const owner);

static TER
deleteSLE(
ApplyView& view,
std::shared_ptr<SLE> sle,
AccountID const owner,
beast::Journal j);

TER
doApply() override;
};

} // namespace ripple

#endif
15 changes: 15 additions & 0 deletions src/ripple/app/tx/impl/DeleteAccount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
//==============================================================================

#include <ripple/app/tx/impl/DID.h>
#include <ripple/app/tx/impl/DeleteAccount.h>
#include <ripple/app/tx/impl/DepositPreauth.h>
#include <ripple/app/tx/impl/SetSignerList.h>
Expand Down Expand Up @@ -133,6 +134,18 @@ removeNFTokenOfferFromLedger(
return tesSUCCESS;
}

TER
removeDIDFromLedger(
Application& app,
ApplyView& view,
AccountID const& account,
uint256 const& delIndex,
std::shared_ptr<SLE> const& sleDel,
beast::Journal j)
{
return DIDDelete::deleteSLE(view, sleDel, account, j);
}

// Return nullptr if the LedgerEntryType represents an obligation that can't
// be deleted. Otherwise return the pointer to the function that can delete
// the non-obligation
Expand All @@ -151,6 +164,8 @@ nonObligationDeleter(LedgerEntryType t)
return removeDepositPreauthFromLedger;
case ltNFTOKEN_OFFER:
return removeNFTokenOfferFromLedger;
case ltDID:
return removeDIDFromLedger;
default:
return nullptr;
}
Expand Down
1 change: 1 addition & 0 deletions src/ripple/app/tx/impl/InvariantCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ LedgerEntryTypesMatch::visitEntry(
case ltNFTOKEN_PAGE:
case ltNFTOKEN_OFFER:
case ltAMM:
case ltDID:
break;
default:
invalidTypeAdded_ = true;
Expand Down
Loading

0 comments on commit cef1f64

Please sign in to comment.