Files
xrpl-dev-portal/content/resources/contribute-code/create-custom-transactors.ja.md
Rome Reginelli b51bcb4ea3 Information Architecture v3 (#1934)
* Update look up escrows to remove redundant info about lookups via sender/destination. Modify cancel expired escrow for brevity.

* Cancel escrow: fix notes

* Add draft of updated cancel-escrow.js.

* Update intro to escrows.

* Add Escrow Tutorial

* Minor corrections

* Fix headings, add HTML

* Update escrow docs

This commit re-creates f205a92db2 with
some adjustments:

- Omit the accidentally-created dir full of junk
- Fix some typos and one mistake in the Escrow limitations section
- Add a table to the EscrowCreate ref to clarify valid combos of fields.

* Concept info from send-a-time-held-escrow added to escrow.md

* IA: Move "Consensus Network" files

This re-creates some work from the original commit 56fffe0b9f

* Rewrite escrows article (re-created)

This commit re-creates relevant work from the following commits:

9a4a588f2b Update escrow.md context info
e1b017dc83 Remove references to using escrow for interledger payments.

* IA: Move "XRPL servers" files

This re-creates some work from original commit 7611979abf

* IA: move "production readiness" files.

Re-creates work from the following commit:

692438693a  Move tutorials to concepts

* New intro articles

Original commit: 56fffe0b9f

* IA: Reorg account concepts

Re-creates some work from original commit 56fffe0b9f

* IA: reorg transaction concepts

Original commits:
9d4eff9940  WIP - reorg accounts
7611979abf  WIP dir. reorg

* IA: reorg consensus concepts

Original commit: 56fffe0b9f

* IA: Reorg ledger docs

Original commit: 56fffe0b9f

- Rephrased some details of the section

* IA: rename issuing/operational addresses page

Original commit: 56fffe0b9f

* Moving use cases

* Fleshing out Use Cases

Note, the dactyl-config.yml file has not been fully updated.

* Clean up checks conceptual info.

* Remove redundant checks use case section

Original commit: 3c29e9c05e

* IA: move Dex under tokens

Original commit: d08b3ba7d7

* Touch up stablecoin issuer use case (#1856)

* Consolidate stablecoin use case

* Stablecoin issuer: cleanup progress through sending

* Stablecoin issuer: reorg second half

(Note: the dactyl-config.yml is not fully reconciled yet)

* Move rippled and clio tutorials into infrastructure

* Remove link to checks amendement.

* Add note to account_objects.md about commandline interface type field.

* Merge expiration case with lifecycle section.

* Interoperability Use Cases

* Add graphics to intro

* Move escrow use cases to dedicated page.

* Update use case page intros and corresponding concept info.

* Clarify meaning of direct XRP payments.

* Intro link updates

* Payment use cases

* Remove some unnecessary links in transactions section

Original commit: e6fcf4a4dc

* Link cleanup in Tokens section

Original commit: 9588dd5e70

* Touch up 'Configure Peering' section

Original commit: fc8f0990b8

* Clean up links in accounts section

Original commit: 3da5fde7a8

* Add NFT mkt use case

* p2p payments: edits to Wallets

* Clean up payments use cases

* Refine history description

* IA: use case cleanup

* IA: reconcile servers, ledgers sections

* IA: reconcile payment types, tx, tokens

* IA: reconcile accounts section

* IA: reconcile infra

* IA: Fix most broken links

* Full Docs Index: omit from sidebar

* IA: fix up most broken links

* fix Absolute path link to internal content

* Quick updates to Software Ecosystem

* Remove some absolute links to internal resources

* Fix remaining broken links in JA target

* Contributing: tweak formatting

* Tutorials: fix some minor issues

* remove interop use cases

* remove intro image and personal references to dennis

* alphabetize-transaction-nav

* Remove unused files

* Add QS escrow tutorials

* IA: move ledgers, consensus protocol files around

* IA: update nav for new page hierarchy

* reordering of topics under new networks and servers top-nav

* Move "Naming" to "What is XRP?"

* Update dactyl-config.yml

Remove xrp.md from the TOC.

* Update list-xrp-as-an-exchange.md

Update link to what-is-xrp

* Update list-xrp-as-an-exchange.ja.md

Change link to what-is-xrp

* Update currency-formats.md

Change link to what-is-xrp

* Update currency-formats.ja.md

Change link to what-is-xrp

* Update cancel-an-expired-escrow.md

Change link to what-is-xrp

* Update paymentchannelfund.md

Change link to what-is-xml

* Update look-up-escrows.md

Change link to what-is-xrp

* Update tokens.md

change link to what-is-xrp

* Update use-payment-channels.md

* Update send-a-time-held-escrow.md

Update link to what-is-xml

* fix broken links

* Update parallel-networks.md

Change link to what-is-xml

* Update parallel-networks.ja.md

* Update invariant-checking.md

Remove link to xrp.html

* Update invariant-checking.ja.md

Remove link to xrp.html

* Update transaction-cost.md

Change link to what-is-xrp

* Update transaction-cost.ja.md

Change link to what-is-xrp

* Update send-a-conditionally-held-escrow.md

Change link to what-is-xrp

* Update stablecoin-issuer.md

Change link to what-is-xrp

* Update tokens.ja.md

Change link to what-is-xml

* Update autobridging.ja.md

Change link to what-is-xrp

* Update currency-formats.md

update text

* reorganize infrastructure nav section

* Update currency-formats.md

Try removing link altogether.

* Update currency-formats.ja.md

Remove link to what-is-xrp.html

* move commandline usage topic to infrastructure

* initial intro rewrite

* minor update to language

* IA.v3: rm Production Readiness

* Delete xrp.md

* Update xrp link in snippet

* Add redirect for old xrp.html URL

* Small edits to 'What is XRP?' article

* Add missing imgs

* XRP - copy edit per @DennisDawson

* restructure tutorials nav and pages

* fix broken links

* more broken link fixes

* Algo trading: 1st draft

* Algo trading: notes on taxes

* Algo trading: edits per review

* algo trading: fix broken link

* Ledger structure: rewrite for accuracy and clarity

* Update links to removed 'tree format' header

* Ledger Structure: Update diagrams

* Re-gen CSS for ledger structure changes

* Ledger structure: edits per review

* IA.v3: fix broken NFT links introduced by rebase

* Desktop Wallet (py): update little stuff

* Update some capacity/storage details

* contribute doc nav update

* fix image link in create diagram page

* IAv3: Fix 'Ledgers' blurb

* Update full history requirements with details from community members

* add reviewer suggestions

* Edits per @trippled review

* Apply suggestions from peer review

Co-authored-by: oeggert <117319296+oeggert@users.noreply.github.com>

* FH: reword file size limit note per review

* Update software ecosystem

* updates per review

* Minor tweaks to graphics

* fixTypos

* Update content/concepts/introduction/software-ecosystem.md

Co-authored-by: Amarantha Kulkarni <amarantha-k@users.noreply.github.com>

* Update content/concepts/introduction/software-ecosystem.md

Co-authored-by: Amarantha Kulkarni <amarantha-k@users.noreply.github.com>

* [JA] update AccountDelete cost

* custom transactors doc

* add doc to dactyl config

* [JA] fix NonFungibleTokensV1_1 amendment status

* [JA] update NFTokenOffer page

* Remove old, unused XRP article (#2039)

* add reviewer suggestions

* Add tooling to check for file/nav consistency

- From the repo top, run tool/check_file_consistency.py to look for
  Markdown files that exist in the "content/" directory but aren't used
  in the documentation.
- New "enforce_filenames" filter prints a warning to console when
  building, if a file's path and filename don't match expectations
  based on its place in the nav and top heading.

* File consistency checker: correctly handle filenames starting in _

* Remove unused old 'get started' and associated code

* Create Resources section & reorg some files

- Rename some files/folders based on their place in the nav
- Move a bunch of non-documentation stuff, and docs on contributing code
  and/or docs to the new "Resources" section.
- Known issue: nav spills into a second row on page widths between
  993px-1110px. To be fixed in a later CSS update, maybe along with
  making the Resources dropdown multi-column.

* Fix #2078 code tab bug

CSS not built yet, to reduce merge conflicts. Won't have any effect
until that happens.

* fix Transaction JSON

* [JA] translate contributing contents

* fix contributing-to-documentation parent

* fix contribute-code blurb

* Top nav: add cols for Resources, fix broken links

* CSS: fix top nav overflows

* Fix broken link from redirect not in JA target

* Top nav: add Infra to article types

* Update contrib info & rename intro file

* [ja] Update link to suggested first page to translate

* [ja] fix contribute docs organization

* Run private network with docker tutorial (#2065)

* [NO-ISSUE] Run private network with docker tutorial

Adds a tutorial page in the Infrastructure section on how to run a private XRPL network with Docker.

Please let me know if you think this is a useful page to include for developers, whether the steps are clear or not, and if you have suggestions on what can be added to it.

* Add minor link fixes and Japanese target

* Apply suggestions from code review

Co-authored-by: Amarantha Kulkarni <amarantha-k@users.noreply.github.com>

* Add link to ripple-docker-testnet setup scripts in See Also section

* Update repo URL

---------

Co-authored-by: Amarantha Kulkarni <amarantha-k@users.noreply.github.com>

* add intro gfx (#2036)

* add intro gfx

* Move graphic up

* Update some graphics with their revised versions

* Add updated version of the custodial vs non-custodial graphic

---------

Co-authored-by: Amarantha Kulkarni <amarantha-k@users.noreply.github.com>
Co-authored-by: Amarantha Kulkarni <akulkarni@ripple.com>

* Update to reflect current UNL publishers

* [ja] update contributing

Co-authored-by: tequ <git@tequ.dev>

* Incorporate feedback on "What is XRP" page. (#2099)

* Add trademark info for XRP

* Revert section to previous state

* Fix broken link (#2101)

---------

Co-authored-by: Oliver Eggert <oeggert@ripple.com>
Co-authored-by: ddawson <dennis.s.dawson@gmail.com>
Co-authored-by: Maria Shodunke <mshodunke@ripple.com>
Co-authored-by: tequ <git@tequ.dev>
Co-authored-by: oeggert <117319296+oeggert@users.noreply.github.com>
Co-authored-by: Amarantha Kulkarni <amarantha-k@users.noreply.github.com>
Co-authored-by: develoQ <develoQ.jp@gmail.com>
Co-authored-by: Maria Shodunke <maria-robobug@users.noreply.github.com>
Co-authored-by: Amarantha Kulkarni <akulkarni@ripple.com>
2023-09-01 12:40:18 -07:00

16 KiB

html, parent, blurb, labels
html parent blurb labels
create-custom-transactors.html contribute-code.html XRPレジャーとやり取りするためのカスタムトランザクタを作成します。
開発
ブロックチェーン

カスタムトランザクタの作成

トランザクタ はトランザクションを処理し、XRP Ledgerを変更するコードです。カスタムトランザクタを作成することで、rippledに新しい機能を追加することができます。このチュートリアルではトランザクタのコーディングについて説明しますが、それをXRPLに追加するにはAmendmentプロセスを経る必要があります。 XRPレジャーのコードへの貢献をご覧ください。

トランザクタは 基本的な処理順序に則って処理されます。

  1. シリアライズ型レジャーエントリ(SLE/serialized type ledger entry)の view へアクセスします。
  2. view 内の値を更新、削除、挿入します。
  3. 確定した変更を view からレジャーに適用します。

注記: view はレジャーのサンドボックスです。トランザクタは必要なエラーチェックと変更のすべてをサンドボックス内で行い、レジャーでは直接行いません。値が確定した後、変更はレジャーにアトミックに適用されます。

このチュートリアルでは、既存のCreateCheckトランザクションを例として使用します。ソースファイルはここで確認できます。

ヘッダファイル

次の形式でヘッダーファイルを作成します。

namespace ripple {

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

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

    static NotTEC
    preflight(PreflightContext const& ctx);

    static TER
    preclaim(PreclaimContext const& ctx);

    TER
    doApply() override;
};

}  // namespace ripple

ApplyContextでトランザクタを初期化すると、トランザクタは以下にアクセスできます:

  • トランザクタをトリガーしたトランザクション。
  • SLEのビュー。
  • エラーを記録するためのジャーナル。

CPPファイル

1. preflight関数の追加

preflight関数はレジャーにアクセスする前にトランザクション自体にエラーがないかチェックします。無効なトランザクションや正しく設定されていないトランザクションは拒否されなければなりません。

  • PreflightContextはレジャーのビューを持っていません。

  • レジャーやトランザクションからフィールドを取得するには、次のようにブラケット記法を使用します。

      auto const curExpiration = (*sle*)[~sfExpiration];
      (*sle)[sfBalance] = (*sle)[sfBalance] + reqDelta;
    

    注記: ~記号は optional型を返します。

  • レジャーとトランザクションのスキーマはこちらから確認できます。

- rippled はトランザクションの結果を結果コードで表します。トランザクションの結果をご覧ください。

CreateCheck::preflight(PreflightContext const& ctx)
{
    // Check if this amendment functionality is enabled on the network.
    if (!ctx.rules.enabled(featureChecks))
        return temDISABLED;

    NotTEC const ret{preflight1(ctx)};
    if (!isTesSuccess(ret))
        return ret;

    if (ctx.tx.getFlags() & tfUniversalMask)
    {
        // There are no flags (other than universal) for CreateCheck yet.
        JLOG(ctx.j.warn()) << "Malformed transaction: Invalid flags set.";
        return temINVALID_FLAG;
    }
    if (ctx.tx[sfAccount] == ctx.tx[sfDestination])
    {
        // They wrote a check to themselves.
        JLOG(ctx.j.warn()) << "Malformed transaction: Check to self.";
        return temREDUNDANT;
    }

    {
        STAmount const sendMax{ctx.tx.getFieldAmount(sfSendMax)};
        if (!isLegalNet(sendMax) || sendMax.signum() <= 0)
        {
            JLOG(ctx.j.warn()) << "Malformed transaction: bad sendMax amount: "
                            << sendMax.getFullText();
            return temBAD_AMOUNT;
        }

        if (badCurrency() == sendMax.getCurrency())
        {
            JLOG(ctx.j.warn()) << "Malformed transaction: Bad currency.";
            return temBAD_CURRENCY;
        }
    }

    if (auto const optExpiry = ctx.tx[~sfExpiration])
    {
        if (*optExpiry == 0)
        {
            JLOG(ctx.j.warn()) << "Malformed transaction: bad expiration";
            return temBAD_EXPIRATION;
        }
    }

    return preflight2(ctx);
}

2. preclaim関数の追加

preclaim関数は、現在のレジャーの情報を見る必要があるエラーをチェックします。

  • このステップが結果コードtesSUCCESSまたはtecを返した場合、トランザクションはキューに入れられ、ピアに送信されます。
CreateCheck::preclaim(PreclaimContext const& ctx)
{
    AccountID const dstId{ctx.tx[sfDestination]};

    // Use the `keylet` function to get the key of the SLE. Views have either `read` or `peek` access.
    // `peek` access allows the developer to modify the SLE returned.
    auto const sleDst = ctx.view.read(keylet::account(dstId));
    if (!sleDst)
    {
        JLOG(ctx.j.warn()) << "Destination account does not exist.";
        return tecNO_DST;
    }

    auto const flags = sleDst->getFlags();

    // Check if the destination has disallowed incoming checks
    if (ctx.view.rules().enabled(featureDisallowIncoming) &&
        (flags & lsfDisallowIncomingCheck))
        return tecNO_PERMISSION;

    if ((flags & lsfRequireDestTag) && !ctx.tx.isFieldPresent(sfDestinationTag))
    {
        // The tag is basically account-specific information we don't
        // understand, but we can require someone to fill it in.
        JLOG(ctx.j.warn()) << "Malformed transaction: DestinationTag required.";
        return tecDST_TAG_NEEDED;
    }

    {
        STAmount const sendMax{ctx.tx[sfSendMax]};
        if (!sendMax.native())
        {
            // The currency may not be globally frozen
            AccountID const& issuerId{sendMax.getIssuer()};
            if (isGlobalFrozen(ctx.view, issuerId))
            {
                JLOG(ctx.j.warn()) << "Creating a check for frozen asset";
                return tecFROZEN;
            }
            // If this account has a trustline for the currency, that
            // trustline may not be frozen.
            //
            // Note that we DO allow create check for a currency that the
            // account does not yet have a trustline to.
            AccountID const srcId{ctx.tx.getAccountID(sfAccount)};
            if (issuerId != srcId)
            {
                // Check if the issuer froze the line
                auto const sleTrust = ctx.view.read(
                    keylet::line(srcId, issuerId, sendMax.getCurrency()));
                if (sleTrust &&
                    sleTrust->isFlag(
                        (issuerId > srcId) ? lsfHighFreeze : lsfLowFreeze))
                {
                    JLOG(ctx.j.warn())
                        << "Creating a check for frozen trustline.";
                    return tecFROZEN;
                }
            }
            if (issuerId != dstId)
            {
                // Check if dst froze the line.
                auto const sleTrust = ctx.view.read(
                    keylet::line(issuerId, dstId, sendMax.getCurrency()));
                if (sleTrust &&
                    sleTrust->isFlag(
                        (dstId > issuerId) ? lsfHighFreeze : lsfLowFreeze))
                {
                    JLOG(ctx.j.warn())
                        << "Creating a check for destination frozen trustline.";
                    return tecFROZEN;
                }
            }
        }
    }
    if (hasExpired(ctx.view, ctx.tx[~sfExpiration]))
    {
        JLOG(ctx.j.warn()) << "Creating a check that has already expired.";
        return tecEXPIRED;
    }
    return tesSUCCESS;
}

3. Add a doApply() function.

The doApply() function has read/write access, enabling you to modify the ledger.

CreateCheck::doApply()
{
    auto const sle = view().peek(keylet::account(account_));
    if (!sle)
        return tefINTERNAL;

    // A check counts against the reserve of the issuing account, but we
    // check the starting balance because we want to allow dipping into the
    // reserve to pay fees.
    {
        STAmount const reserve{
            view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};

        if (mPriorBalance < reserve)
            return tecINSUFFICIENT_RESERVE;
    }

    // Note that we use the value from the sequence or ticket as the
    // Check sequence.  For more explanation see comments in SeqProxy.h.
    std::uint32_t const seq = ctx_.tx.getSeqProxy().value();
    Keylet const checkKeylet = keylet::check(account_, seq);
    auto sleCheck = std::make_shared<SLE>(checkKeylet);

    sleCheck->setAccountID(sfAccount, account_);
    AccountID const dstAccountId = ctx_.tx[sfDestination];
    sleCheck->setAccountID(sfDestination, dstAccountId);
    sleCheck->setFieldU32(sfSequence, seq);
    sleCheck->setFieldAmount(sfSendMax, ctx_.tx[sfSendMax]);
    if (auto const srcTag = ctx_.tx[~sfSourceTag])
        sleCheck->setFieldU32(sfSourceTag, *srcTag);
    if (auto const dstTag = ctx_.tx[~sfDestinationTag])
        sleCheck->setFieldU32(sfDestinationTag, *dstTag);
    if (auto const invoiceId = ctx_.tx[~sfInvoiceID])
        sleCheck->setFieldH256(sfInvoiceID, *invoiceId);
    if (auto const expiry = ctx_.tx[~sfExpiration])
        sleCheck->setFieldU32(sfExpiration, *expiry);

    view().insert(sleCheck);

    auto viewJ = ctx_.app.journal("View");
    // If it's not a self-send (and it shouldn't be), add Check to the
    // destination's owner directory.
    if (dstAccountId != account_)
    {
        auto const page = view().dirInsert(
            keylet::ownerDir(dstAccountId),
            checkKeylet,
            describeOwnerDir(dstAccountId));

        JLOG(j_.trace()) << "Adding Check to destination directory "
                        << to_string(checkKeylet.key) << ": "
                        << (page ? "success" : "failure");

        if (!page)
            return tecDIR_FULL;

        sleCheck->setFieldU64(sfDestinationNode, *page);
    }

    {
        auto const page = view().dirInsert(
            keylet::ownerDir(account_),
            checkKeylet,
            describeOwnerDir(account_));

        JLOG(j_.trace()) << "Adding Check to owner directory "
                        << to_string(checkKeylet.key) << ": "
                        << (page ? "success" : "failure");

        if (!page)
            return tecDIR_FULL;

        sleCheck->setFieldU64(sfOwnerNode, *page);
    }
    // If we succeeded, the new entry counts against the creator's reserve.
    adjustOwnerCount(view(), sle, 1, viewJ);
    return tesSUCCESS;
}

追加の関数

必要に応じて、カスタムトランザクタにヘルパー関数を追加することができます。特殊な場合に役立つ特別な関数がいくつかあります。

calculateBaseFee

ほとんどのトランザクションはデフォルトのReferenceトランザクションコストをそのまま引き継ぎます。しかし、トランザクションで通常以外のトランザクションコストを定義する必要がある場合、トランザクションのcalculateBaseFeeメソッドをカスタムメソッドに置き換えることができます。

次の例では、EscrowFinishランザクションが条件付きエスクローに対して、フルフィルメントの大きさに応じて追加コストを請求する方法を示しています。

XRPAmount
EscrowFinish::calculateBaseFee(ReadView const& view, STTx const& tx)
{
    XRPAmount extraFee{0};

    if (auto const fb = tx[~sfFulfillment])
    {
        extraFee += view.fees().base * (32 + (fb->size() / 16));
    }

    return Transactor::calculateBaseFee(view, tx) + extraFee;
}

makeTxConsequences

rippledTxConsequencesクラスを使用して、トランザクション適用時のアカウントへの結果を記述します。このクラスは手数料、使用可能な最大XRP、トランザクションによって消費されたシーケンス番号の数を追跡します。結果には次の3つのタイプがあります。

  • **ノーマル:**トランザクションは署名に影響を与えず、XRP手数料を消費するのみです。手数料を超えてXRPを消費するトランザクションは正常とはみなされません。
  • **ブロッカー:**トランザクションの署名に影響を与え、有効なトランザクションがその後ろにキューイングされるのを防ぎます。
  • **カスタム:**トランザクタは結果を決定するために追加の作業を行う必要があります。

makeTxConsequences関数を使うと、以下のような状況に対してカスタム結果を作成することができます:

  • XRPを送信する支払い。
  • 複数のシーケンス番号を消費するチケット。
  • 設定されたフラグやフィールドによって、正常またはブロッカーとなるトランザクション。

注記: TxConsequencesトランザクションキューにのみ影響します。トランザクションがレジャーに適用されたときに手数料を請求する可能性が高い場合、それはピアに送信されます。手数料を請求する可能性がない場合、またはそれが判断できない場合は、送信されません。

SetAccount::makeTxConsequences(PreflightContext const& ctx)
{
    // The SetAccount may be a blocker, but only if it sets or clears
    // specific account flags.
    auto getTxConsequencesCategory = [](STTx const& tx) {
        if (std::uint32_t const uTxFlags = tx.getFlags();
            uTxFlags & (tfRequireAuth | tfOptionalAuth))
            return TxConsequences::blocker;

        if (auto const uSetFlag = tx[~sfSetFlag]; uSetFlag &&
            (*uSetFlag == asfRequireAuth || *uSetFlag == asfDisableMaster ||
             *uSetFlag == asfAccountTxnID))
            return TxConsequences::blocker;

        if (auto const uClearFlag = tx[~sfClearFlag]; uClearFlag &&
            (*uClearFlag == asfRequireAuth || *uClearFlag == asfDisableMaster ||
             *uClearFlag == asfAccountTxnID))
            return TxConsequences::blocker;

        return TxConsequences::normal;
    };

    return TxConsequences{ctx.tx, getTxConsequencesCategory(ctx.tx)};
}

次のステップ

新しいトランザクタでサーバを再コンパイルし、スタンドアロンモードでテストしてください。もしAmendmentの後ろにトランザクタをコーディングした場合、設定ファイルを使ってその機能を強制的に有効にすることができます。