# [Ride v5] Функции вызова dApp из dApp
⚠️ Это документация Стандартной библиотеки версии 5. Рекомендуем использовать версию 6. Перейти к версии 6
| Название | Описание | Сложность |
|---|---|---|
| invoke | Вызывает вызываемую функцию dApp, c ограничением на повторные вызовы исходного dApp | 75 |
| reentrantInvoke | Вызывает вызываемую функцию dApp, без ограничения на повторные вызовы исходного dApp | 75 |
# invoke
Вызывает вызываемую функцию dApp, с ограничением на повторные вызовы.
invoke(dApp: Address|Alias, function: String, arguments: List[Any], payments: List[AttachedPayments]): Any
Any означает любой допустимый тип. Извлечь из него конкретный тип можно с помощью оператора match ... case, см. пример.
Функция invoke может использоваться только вызываемой функцией dApp-скрипта, но не функцией-верификатором, скриптом аккаунта или скриптом ассета.
С помощью функции invoke вызываемая функция может вызвать вызываемую функцию другого dApp или того же самого dApp, в том числе сама себя, а затем использовать результаты вызова в дальнейших вычислениях. Подробнее в разделе Вызов dApp из dApp.
💡 Чтобы гарантировать порядок выполнения вызываемых функций и применения действий скрипта, присвойте возвращаемое значение invoke нетерпеливой переменной.
Вызов может содержать платежи, которые будут переведены с баланса исходного dApp на баланс вызываемого. Платежи запрещены, если dApp вызывает сам себя.
Если токен в платеже является смарт-ассетом, то скрипт ассета верифицирует вызов invoke как InvokeScriptTransaction с полями:
dApp,payments,function,args— значения, указанные в функцииinvoke;sender,senderPublicKey— параметры dApp, который вызвал функцию;id,timestamp,fee,feeAssetId— как в транзакции вызова скрипта;version= 0.
Если скрипт ассета отклоняет действие, то транзакция, которая вызвала скрипт dApp, либо отбрасывается, либо сохраняется на блокчейне как неуспешная, см. раздел Валидация транзакций.
# Ограничение повторных вызовов
Стек вызовов, порожденный функцией invoke, не должен содержать вызовы исходного dApp после вызова другого dApp.
Пусть исходный dApp A вызывает dApp B c помощью функции invoke. Независимо от того, какую функцию использует dApp B — invoke или reentrantInvoke, следующие последовательности вызовов завершатся ошибкой:
→ dApp A
→ dapp B
→ dApp A
→ dApp A
→ dapp B
→ dApp C
→ dApp A
Следующие последовательности вызовов допустимы:
→ dApp A
→ dapp A
→ dapp A
→ dApp N
→ dapp A
→ dApp A
→ dapp N
→ dapp A
→ dapp B
→ dapp B
→ dapp A
→ dapp C
# Параметры
| Параметр | Описание |
|---|---|
| dApp: Address|Alias | Адрес или псевдоним dApp, функция которого вызывается |
| function: String|Unit | Имя вызываемой функции. unit — вызов функции по умолчанию |
| arguments: List[Any] | Параметры вызываемой функции |
| payments: List[AttachedPayment] | Платежи в пользу вызываемого dApp, не более 10 |
# Пример
Пользователь с помощью транзакции вызова скрипта вызывает функцию foo dApp1.
Функция foo вызывает функцию bar dApp2, передавая число a и прикладывая платеж 1 XTN.
Функция bar переводит dApp1 1 WAVES и возвращает удвоенное число a.
Функция foo записывает в хранилище данных dApp1:
- значение, возвращенное функцией
bar. - новый баланс dApp2 (уменьшенный на 1 WAVES, переведенный функцией
bar).
dApp1:
{-# STDLIB_VERSION 5 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
@Callable(i)
func foo(dapp2: String, a: Int, key1: String, key2: String) = {
strict res = invoke(addressFromStringValue(dapp2),"bar",[a],[AttachedPayment(base58'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p',1000000)])
match res {
case r : Int =>
(
[
IntegerEntry(key1, r),
IntegerEntry(key2, wavesBalance(addressFromStringValue(dapp2)).regular)
],
unit
)
case _ => throw("Incorrect invoke result")
}
}
dApp2:
{-# STDLIB_VERSION 5 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
@Callable(i)
func bar(a: Int) = {
(
[
ScriptTransfer(i.caller, 100000000, unit)
],
a*2
)
}
# reentrantInvoke
Вызывает вызываемую функцию dApp. Отличается от функции invoke только отсутствием ограничения на повторные вызовы исходного dApp, который использовал reentrantInvoke.
Однако, если исходный dApp был вызван повторно и на этот раз использовал функцию invoke, то в этом стеке вызовов нельзя вызвать исходный dApp еще раз.
Например, последовательность вызовов
→ dApp A
→ dapp B
→ dApp A
→ dApp C
→ dApp A
- допустима, если dApp A вызывает и dApp B, и dApp С с помощью функции
reentrantInvoke; - завершается ошибкой, если dApp A вызывает dApp B с помощью функции
reentrantInvoke, а dApp С — с помощью функцииinvoke.
reentrantInvoke(dApp: Address|Alias, function: String, arguments: List[Any], payments: List[AttachedPayments]): Any