As we discussed earlier, transactions are the smallest activities happened on the Forge backed chains and the code backing the transactions is called transaction protocol. Transaction protocol to Forge transaction is just like smart contract to Ethereum transaction.
By default, Forge ships with a set of core transaction protocols - each protocol covers a set of typical use cases. Application developers could decide to install all these protocols or just pick protocols that they want to support. For example, an application may decide no normal asset creation is allowed in its chain, so it installs core protocols without create_asset / update_asset protocols. Application can build and install their own protocols as well if they feel that existing protocols cannot fit for their needs.
For core transaction protocols we grouped them into the follow categories.
This is the most basic transaction protocols that a chain must install. Right now it contains one transaction protocol: core, which provides all the basic functions for state creation / update. Note this transaction protocol is subject to change.
Account related transaction protocols. Including:
- declare: declare a wallet in the chain. See: Declare Transaction.
- account_migrate: migrate a wallet from one address to another. See: Account Migration Transaction.
Asset related transaction protocols. Including -
Basic asset creation and manipulation:
- create_asset: create a new asset. See: Create Asset Transaction.
- update_asset: update and existing asset. See: Update Asset Transaction.
- consume_asset: consume an asset to get certain service. See: Consume Asset Transaction.
Advanced asset creation and exchange:
- create_asset_factory: create a factory that could generate the similar assets, like a vending machine. See: Create Asset Factory Transaction.
- acquire_asset: pay to an asset factory to get the asset. See: Acquire Asset Transaction.
- transfer: send tokens or/and assets from one account to the other. See: Transfer Transaction.
- exchange: exchange tokens/assets with other's tokens/assets. See: Exchange Transaction.
Document will be exposed soon.
Document will be exposed soon.
How to write a transaction protocol
To write a new transaction protocol you basically need to prepare the following files:
- config.yml or config.json: configuration for this transaction protocol. Used by
forge-compilerto know which files to compile and what metadata to include in the protocol.
- a proto file (optional): the protobuf definition for your transaction protocol. Must be referenced in config.yml.
- a pipeline file (optional): the transaction pipeline for your transaction protocol. Must be referenced in config.yml.
- a set of source code: the logic of the transaction protocol.
Once you write a new tx protocol, you can either compile it directly with
$ forge-compiler config.yml
or add it into
Makefile so that
make build-protocols will take care it for you.
The compiled result is a url based64 encoded (padding: false) deploy protocol itx. For your local node, you can use a moderator's wallet to send it to the chain.
An example of config.yml looks like this:
--- name: consume_asset version: 0 namespace: CoreTx description: Consume an asset that is owned by self type_urls: fg:t:consume_asset: ForgeAbi.ConsumeAssetTx proto: protocol.proto pipeline: protocol.yml sources: - protocol.ex
type_urls are a map of type urls (key is the type_url and value is the module name) that you'd register to ForgeAbi. The type_urls mentioned here will be used by
version must be monotonically increasing. Forge will refuse to install a tx protocol with an old version.
protocol source code
Normally you just need a single file if your protocol is not too complex. The file structure looks like this:
defmodule CoreTx.ProtocolName do # RPC helper function for sdk to use defmodule Rpc do import ForgeSdk.Tx.Builder, only: [tx: 1] tx :protocol_name end # customized pipe for Check pipeline defmodule CheckTx do use ForgePipe.Builder def init(opts), do: opts def call(info, _opts) do info end end # customized pipe for Verify pipeline defmodule CheckTx do use ForgePipe.Builder def init(opts), do: opts def call(info, _opts) do info end end # customized pipe for Update pipeline defmodule UpdateTx do use ForgePipe.Builder def init(opts), do: opts def call(info, _opts) do info end end end
If your code logic is too complex to put into one file, you can use multiple source files, just remember to reference them into the config.yml.
Guide on protocol upgrade
Protobuf message model ensures that if we're following certain rules, we can upgrade the message with backward-compatible changes. These rules are:
- Existing fields should not be renumbered. If you have already used
string name = 1you can not do
string name = 2later on.
- Existing fields should not have their types changed. You can't change
BigSint value = 2to
BigUint value = 2. Exceptions:
- regular field can be upgraded to an oneof
- a regular field can be upgraded to a repeated field.
- New fields should not reuse any previously assigned field number.
- Enum defaults should be picked such that they make sense looking forward, or be set to UNSPECIFIED.