Previous << Scripts
Next >> FLIX (Flow Interaction Templates)
INFO
Flow上のEVM Accountsに関する情報を探しているEVM開発者の方ですか? その場合は、EVM固有のドキュメントをこちらでご確認ください。
Transaction Fees
トランザクション手数料は、支払者アカウントが Flow に支払う費用であり、トランザクションを Flow ブロックチェーンに含めるために必要です。手数料は、スパムや無限に実行され続けるトランザクションからネットワークを保護し、Flow ネットワークを構成する参加者に金銭的なインセンティブを提供するために必要です。
トランザクション手数料は、トランザクションが成功したか失敗したかに関わらず支払われます。支払者アカウントにトランザクション手数料を支払うのに十分なFlow残高がない場合、トランザクションは失敗します。トランザクションを送信する際にガスリミット値を指定することで、トランザクション手数料をある程度制限することができます。
Understanding the need for transaction fees
セグメント化されたトランザクション手数料は、ネットワークへの影響を考慮した公正な価格設定を確保するために不可欠です。例えば、より高負荷な操作は、トランザクションの処理と伝播により多くのリソースが必要です。しかし、一般的な操作は妥当な価格に抑えられます。
手数料は、ネットワーク上の悪意のある行為(スパムなど)を実行しにくくすることで、ネットワーク全体のセキュリティを向上させます。
独自のFlowアーキテクチャは、高い処理能力を目標としています。これはシステムに余裕を持たせやすくなるため、短時間の急激な負荷にもより適切に対応することができます。
Fee Structure
各トランザクション手数料は、実行手数料、組み入れ手数料、ネットワーク・サージ要因の3つの要素で構成されます。
Execution Fee
トランザクションに対する実行努力は、そのトランザクションがたどるコードのパス(code path)と実行するアクションによって決定されます。実行努力コストに関連するアクションは、大きく4つのカテゴリーに分類できます。
- 通常のCadenceの処理、ループ、または関数呼び出し
- ストレージからのデータ読み取り、読み込みバイト単位で課金される
- ストレージへのデータ書き込み、書き込みバイト単位で課金される
- アカウントの作成
Transaction Type | Estimated cost (FLOW) |
---|---|
FT transfer | 0.00000185 |
Mint a small NFT (heavily depends on the NFT size) | 0.0000019 |
Empty Transaction | 0.000001 |
Add key to an account | 0.000001 |
Create 1 Account | 0.00000315 |
Create 10 accounts | 0.00002261 |
Deploying a contract that is ~50kb | 0.00002965 |
Inclusion Fee
トランザクションの組み入れ努力には、以下のような作業が必要となります。
- トランザクションをブロックに含める
- ノードからノードへトランザクション情報を転送する
- トランザクション署名の検証
現在、組み入れ努力は常に1.0であり組み入れ努力コストは0.000001
に固定されています。
Surge Factor
将来的には、処理が必要なトランザクションの急増やトランザクション処理能力の低下によりネットワークが混雑した際に、ネットワークサージが適用されることになります。現在、ネットワークサージは1.0
に固定されています。
現在、インクルージョンフィーとサージファクターは、いずれもFlowフィーに大幅に反映されるものではありません。将来的に変更される可能性があることをご留意ください。
Estimating transaction costs
コスト見積もりには2段階のプロセスがあります。まず、エミュレーター、テストネット、またはメインネットのいずれかで実行努力を集める必要があります。次に、トランザクションの実行努力を使用して、JavaScriptまたはGo FCL SDKのいずれかを使用して最終的な手数料を計算します。
Storage
Flowのストレージ容量に対するアプローチは、最低残高を維持することで月額アカウント手数料を免除する一部の銀行の料金モデルに少し似ています。ここで、あなたのアカウント内のデータ量があなたの最低残高を決定します。最低残高を下回ると、入金またはデータの削除を除いて、あなたのアカウントでトランザクションができなくなります。ストレージ料金モデルの本質は、ストレージ料金を継続的に課金することなくデータの可用性を確保し、同時にネットワークのストレージリソースに負担をかける可能性がある不正使用を防止することです。現状とブロックチェーンの歴史のこの差異は、ストレージ要件と制限を理解する上で極めて重要です。
各 Flow アカウントには、使用されているストレージが紐付けられています。アカウントの使用ストレージは、アカウントのストレージに保存されているすべてのデータのバイトサイズです。アカウントにはストレージ容量があり、これはアカウントが保有する Flow トークンの量に直接関連しています。アカウントは、追加費用なしで、ストレージ容量までのストレージを好きなだけ使用できます。
WARNING
トランザクションによりアカウントの保存容量を超える場合、そのトランザクションは失敗し、取り消されます。同様に、トランザクションによりアカウントの残高が0.001 Flowトークン(アカウントが持つことができる最低残高)を下回る場合、そのトランザクションも失敗します。
Storage Capacity
アカウントのストレージ容量は、保有しているFLOWの量によって決まります。
DANGER
アカウントに設定できる最小のFLOW量は0.001です。この最小値は、アカウント作成時にアカウント作成者が設定します。
最低アカウント保有分は、誰かがアカウントに(NFTなど)何かを預け入れた場合でも、ほとんどのアカウントでストレージ容量が不足することはありません。
現在、アカウントストレージに100MBを保存するために必要な量は1FLOWです。
Flowのアカウントにデータを保存しても、アカウントからトークンが徴収されることはありません。トークンを予備として確保しておくだけです。ストレージが解放されたら、Flowトークンを転送することができます。
Storage Capacity of the Payer
トランザクションの支払者のストレージ容量は、通常、他のアカウントのストレージ容量と同じ方法で計算されますが、しかし、システムでは、トランザクションの終了時に支払者が負担するトランザクション手数料を考慮する必要があります。ストレージ容量のコンプライアンスをチェックする段階では、最終的なトランザクション手数料の金額は完全に把握されていません。もし使用ストレージ量がストレージ容量より多いなら、トランザクションは失敗してしまいます。
このため、ストレージのコンプライアンスを確認する際には、支払者の残高は最大限のトランザクション手数料分だけ控えめに考慮されます。特定のトランザクションの最大トランザクション手数料は、トランザクションが実行努力のリミット(execution effort limit)をすべて使い切った場合のトランザクション手数料です。
Storage Used
アカウントのストレージにあるすべてのデータは、使用ストレージ容量としてカウントされます。アカウントが新規に作成された直後の場合でも、そのストレージは空ではありません。ストレージにはすでにいくつかのアイテムが存在しています。
- アカウントが存在することを示すメタデータ。
- 空のFLOW金庫(vault)、および保存されたreceiverのCapability。
- アカウントが鍵で作成された場合は、そのアカウントの公開鍵。
- アカウントがコントラクトで作成された場合は、そのアカウントにデプロイされているスマートコントラクト。
- 符号なし整数のアカウントのストレージ使用量の値。
アカウントに追加のキー、スマートコントラクト、Capability、リソースなどを追加すると、使用済みストレージにカウントされます。
Flowブロックチェーンに保存されたデータは、キーバリュー型台帳(key-value ledger)の中に保存されます。それぞれのデータのkeyは、そのデータの所有者のアドレスと、そのデータへのパスが含んでいます。アカウントは多数のキーを保存できるため、Flowはアカウントのキーとデータが一緒に保存されていると見なします。つまり、各データが使用するストレージは、そのデータのバイト長に、そのデータのキーのバイト長を加えたものとなります。
Maximum available balance
ストレージの制限により、ユーザーがウォレットから引き出せる残高には上限があります。コアコントラクトであるFlowStorageFees
は、その値を取得する関数を提供しています。
import "FlowStorageFees"
access(all) fun main(accountAddress: Address): UFix64 {
return FlowStorageFees.defaultTokenAvailableBalance(accountAddress)
}
あるいは、開発者はAccount
のavailableBalance
プロパティを使用することもできます。
access(all) fun main(address: Address): UFix64 {
let acc = getAccount(address)
let balance = acc.availableBalance
return balance
}
Practical Understanding of Fees
Using Flow Emulator
エミュレータはFlow CLIを使用して起動できます。トランザクションを実行し、発行されたイベントを見てみます。
0|emulator | time="2022-04-06T17:13:22-07:00" level=info msg="⭐ Transaction executed" computationUsed=3 txID=a782c2210c0c1f2a6637b20604d37353346bd5389005e4bff6ec7bcf507fac06
computationUsed
フィールドが表示されているはずです。その値をメモしてください。次のステップでそれを使用します。
On testnet or mainnet
一旦トランザクションが完了すると、Flowdiverなどのエクスプローラーを使用して、トランザクションの詳細と発行されたイベントを確認することができます。Flowdiverの場合、疑問のトランザクションを開き、FlowFees
コントラクトからFeesDeducted
イベントを探します。
右側にあるイベントのデータには、トランザクションの料金を表すフィールドが表示されています。
- Total Fees Paid(支払総額)
- Inclusion Effort(取り込み努力)
- Execution Effort(実行努力)
リストの最後の値、executionEffort
の値をメモしてください。次のステップで使用します。
Calculating final costs
トランザクションのコストは、メインネット or テストネット上でそれぞれ以下のFCLスクリプトを使用して計算できます。
On mainnet
import FlowFees from 0xf919ee77447b7497
access(all) fun main(
inclusionEffort: UFix64,
executionEffort: UFix64
): UFix64 {
return FlowFees.computeFees(inclusionEffort: inclusionEffort, executionEffort: executionEffort)
}
On testnet
import FlowFees from 0x912d5440f7e3769e
access(all) fun main(
inclusionEffort: UFix64,
executionEffort: UFix64
): UFix64 {
return FlowFees.computeFees(inclusionEffort: inclusionEffort, executionEffort: executionEffort)
}
Configuring execution limits
注意:リミットはユーザーが支払う最終的なフィーを制限するものではないことにご注意ください。リミットは、特に実行努力を制限するためのものです。
高すぎず、低すぎないリミットを設定することが重要です。リミットが高すぎると、支払者はトランザクションを送信する前にアカウントに多くの資金を用意しておく必要があります。リミットが低すぎると、トランザクションが失敗し、すべての状態(ステート)変更が破棄される可能性があります。
Using FCL JS SDK
mutate
関数にはlimit
パラメータを設定する必要があります。例えば:
import * as fcl from "@onflow/fcl"
const transactionId = await fcl.mutate({
cadence: `
transaction {
execute {
log("Hello from execute")
}
}
`,
proposer: fcl.currentUser,
payer: fcl.currentUser,
limit: 100
})
const transaction = await fcl.tx(transactionId).onceSealed();
console.log(transaction;)
Using FCL Go SDK
SetComputeLimit
メソッドをコールしてフィーのリミットを設定する必要があります。例えば:
import (
"github.com/onflow/flow-go-sdk"
"github.com/onflow/flow-go-sdk/crypto"
)
var (
myAddress flow.Address
myAccountKey flow.AccountKey
myPrivateKey crypto.PrivateKey
)
tx := flow.NewTransaction().
SetScript([]byte("transaction { execute { log(\"Hello, World!\") } }")).
SetComputeLimit(100).
SetProposalKey(myAddress, myAccountKey.Index, myAccountKey.SequenceNumber).
SetPayer(myAddress)
Maximum transaction fees of a transaction
トランザクションの支払者に課される可能性のある手数料の上限は、取り込みコストと実行コストの合計として計算できます。実行コストは、指定された実行努力のリミットに基づいてトランザクションの実行のフィーとして計算されます。
支払者は、この金額を超えるフィーを支払うことはありません。
Optimizing Cadence code to reduce effort
いくつかの最適化により、トランザクションの実行時間を短縮することができます。以下に、その例をいくつか挙げます。このリストは網羅的なものではなく、例示的なものです。
Limit functions calls
関数を呼び出す時には、それが絶対に必要なものであることを確認してください。いくつかのケースでは、前提条件(preなど)をチェックすることで、追加の(関数)呼び出しを回避できるかもしれません。
for obj in sampleList {
/** check if call is required */
if obj.id != nil {
functionCall(obj)
}
}
Limit loops and iterations
リストを繰り返し処理したい時は、それが必ず、リストのサブセットではなくすべての要素を繰り返し処理する必要があることを確認してください。時間とともにループが大きくなり過ぎることを避けてください。可能ならループ処理を制限してください。
/* Iterating over long lists can be costly */
access(all) fun sum(list: [Int]): Int {
var total = 0
var i = 0
/* if list grows too large, this might not be possible anymore */
while i < list.length {
total = total + list[i]
}
return total
}
/* Consider designing transactions (and scripts) in a way where work can be "chunked" into smaller pieces */
access(all) fun partialSum(list: [Int], start: Int, end: Int): Int {
var partialTotal = 0
var i = start
while i < end {
partialTotal = partialTotal + list[i]
}
return partialTotal
}
Understand the impact of function calls
関数によっては、他の関数よりも実行努力を必要とするものもあります。どのような関数呼び出しが行われ、どのような実行が伴うのかを慎重に確認する必要があります。
/* be aware functions that call a lot of other functions
(or call themselves) might cost a lot */
access(all) fun fib(_ x: Int): Int {
if x == 1 || x== 0 {
return x
}
/* + 2 function calls each recursion */
return fib(x-1) + fib(x-2)
}
/* consider inlining functions with single statements, to reduce costs */
access(all) fun add(_ a: Int, _ b: Int): Int {
/* single statement; worth inlining */
return a + b
}
Avoid excessive load and save operations
コストのかかるストレージの取出しや保存を避け、可能なら参照を借ります(borrow references)。例えば:
transaction {
prepare(acct: auth(BorrowValue) &Account) {
/* Borrows a reference to the stored vault, much less costly operation that removing the vault from storage */
let vault <- acct.storage.borrow<&ExampleToken.Vault>(from: /storage/exampleToken)
let burnVault <- vault.withdraw(amount: 10)
destroy burnVault
/* No `save` required because we only used a reference */
}
}
Note:リクエストされたリソースが存在しない場合は、読み取り費用は発生しません。
Limit accounts created per transaction
アカウントの作成やキーの追加には費用がかかります。アカウントやキーは必要な場合のみ作成するようにしてください。
Check user’s balance before executing transactions
ユーザーの残高が、想定される最高額のフィーをカバーできるだけの残高があることを確認してください。FT送金の場合は、想定される最高額のフィーに加えて、送金金額をカバーする必要があります。
How to learn more
トランザクションフィーについてさらに詳しく知るには、これらの場所があります。
Note:Flowでのトランザクション手数料の導入についてご意見をお持ちの方は、このフォーラムにフィードバックを残すことができます。
FAQs
When will the fee update go into effect?
更新は2022年4月6日のSporkでロールアウトされ、毎週あるエポック移行期間の6月1日に有効化されました。
Why are fees collected even when transactions fail?
トランザクションの伝播と確認には実行が必要なので、コストは適切に差し引かれます。
What execution costs are considered above average?
実行コストに平均値はありません。実装されたロジックによって、すべての関数が大幅に異なります。コスト削減が可能かどうかを判断するためには、最適化のベストプラクティスを確認する必要があります。
Do hardware wallets like Ledger support segmented fees?
Yes.
What is the lowest execution cost?
実行コストの最低値は1です。これは、あなたのトランザクションに(日付の読み書きを行わない)一つの関数呼び出しまたはループが1つ含まれていたことを意味します。
Can I determine how much a transaction will cost on mainnet without actually paying?
コストは、次の2つのプロセスで見積もりを行うことができます。1)(エミュレータまたはテストネットの)トランザクションの実行コストを見定める。2)FCL SDK メソッドを使用して最終的なトランザクション手数料を計算する。
How accurate will testnet fees be to mainnet fees?
最終的な手数料は、ネットワークのサージファクターによって決定されます。テストネットのサージファクターはメインネットのサージファクターとは異なるため、メインネットとテストネットの見積もりには差異が生じることを想定しておく必要があります。
I use Blocto and I haven't paid any fees yet. Why is that?
それは、Bloctoがトランザクションの支払者として機能しているためです。Self-custody(自己管理)型ウォレットでは、ユーザーがトランザクションフィーの支払いを求められる場合があります。さらに、アプリがトランザクションフィーを資金援助
することも可能です。
Why would the same transaction have different fees when executed for different accounts?
実行コストには、アカウントのストレージからデータを読み込むコストなどが含まれます。保存されているデータはアカウントごとに異なるため、実行コストも異なり、その結果、トランザクション手数料も異なります。
追加詳細:
- Cadenceで最もコストがかかるのは、ストレージへの読み書きです。これは罰則ではありません!すべての読み取りは、検証(メルケル証明付き)のためにすべての検証ノードに送信する必要があり、すべての書き込みには、メルケルハッシュのパスを更新する必要があります。ストレージへの読み書きは、どのブロックチェーンでも本質的にコストがかかります。
- アカウント内のデータの保存方法はツリー形式です(「atree」という名前にヒントがありますね😉)。そのため、アカウント内の要素が増えればツリーのレベルも増え、読み取りや更新が必要なツリーのノード数も増えます。したがって、アカウントのバイトサイズを調べれば、コストを把握する適切な代替手段となります。
- ツリーであるため、読み取りと書き込みのコストは log(n) に比例して増加しますが、スケールします。
- atree には、Crescendo (Flowのv1.0アップグレード時の名称) 用に順番待ちになっている更新があり、それがこれを改善する予定です。以前のバージョンでは、(コードをシンプルに保つため)ツリーに新しいレベルを追加する際にエラーが発生しました。一方、新しいバージョンでは、各レベルに多くのデータを詰め込むようにしています。これにより、同じバイトサイズでもレベル数が少なくなるはずです。さらに、よりコンパクトなエンコーディングが含まれているため、ほとんどのアカウントでバイトサイズが縮小されます。
- これらの改善があっても、この関係は今後もずっと続くでしょう。アカウントが大きくなればなるほど、ノードが処理しなければならない簿記作業が増えるため、トランザクション手数料が多少大きくなるでしょう。
Last updated on Dec 11, 2024 by Chase Fleming
翻訳元