A TECHNICAL DEEP-DIVE
How To Develop Custom Transaction Types With Core GTI
In this post, we will take a deep-dive into developing custom transaction types with our Core GTI (Generic Transaction Interface) technology.
Related posts: In the previous post, Part 1 — The Introduction To Blockchain Development with ARK , we addressed the developing of distributed blockchain applications in general and demonstrated how to apply recommended architectural best practices.
You can learn more about the vision of Generic Transaction Interface in one of our recent blog posts covering ARK Core GTI and the reasoning behind it.
This post will be followed by separate tutorials and hands-on workshops where we will build a fully working blockchain application (backend and frontend).
By using GTI you will be able to follow a streamlined process of creating and securing your new custom transaction type that can be deployed to any ARK based bridgechain and managed inside a separate core module (plugin).
A general overview of important classes supporting custom transaction development can be seen in the
Class Diagram picture below. Abstract classes and methods in the class diagram are presented with italic text*.*
To develop a custom transaction type we need to implement code-contracts defined by GTI interfaces and abstract classes (the blue colored items in the class diagram above). Implementation is pretty straight forward. We override default transaction behavior and add custom business logic, by implementing the Transaction, Builder and Handler type classes (the green-colored items in the diagram above). We will implement the following three classes:
- Transaction — introduces your new transaction type structure
- Builder — implements payload building and signing
- Handler — handles blockchain protocol and makes your new transaction a fully-fledged member
We will explain each of the three class types, their mechanics and purpose in the following sections. The use of the term
serde throughout this document refers to the processes of transaction serialization and deserialization.
- Implement BusinessRegistrationTransaction Class
The purpose of this class is to define and implement transaction structure, fields, serde process (transaction serialization and deserialization) and set schema validation rules. We need to inherit (extend) base Transaction class to follow GTI rules.
a.) Build Your New Transaction Structure
Your custom transaction fields must be defined inside the
BusinessRegistration transaction class. They follow the rules of the inherited
Transaction class. You can introduce any number of new fields and their respectful types. All new fields will be stored in the base transaction field called
transaction.assets. The source-code snippet below introduces custom fields with interfaces.
The defined interface makes use of new custom transaction fields stricter and is part of the serde process.
Our Public API enables searching of transactions with new custom fields by design (no API changes needed).
b.) Implement the
We need to implement custom
serde methods that will take care of the
serde process for our newly introduced transaction fields. Abstract methods
deserialize() are defined by the base
Transaction class, and are automatically called inside our custom class during the serde process.
c.) Define Schema Validation For The New Transaction Fields
Each custom transaction is accompanied by enforced schema validation. To achieve this we must extend base TransactionSchema and provide rules for the custom field validation (fields introduced in IBusinessRegistrationAsset). Schema is defined with AJV and we access it by calling the
getSchema() method inside your new transaction class, in our case
d.) Define BusinessRegistrationTransaction
type are used internally by Core to register a transaction. Non-core transactions have to define the
typeGroup otherwise Core won’t be able to categorize them. All transactions (from the release of core v2.6) will be signed with
type. By omitting the
core will fall back to
typeGroup: 1, which is the default Core group. We define
type in our BusinessRegistration class, like this:
This should give us unique transaction type registrations across the ARK bridgechains ecosystem. TypeGroup is something that can be unique to a specific bridgechain and makes transaction numbering easier (each type group can start its own numbering scheme from start).
- Implement The BusinessRegistrationBuilder Class
This class implements the
builder pattern. We use it to build and sign our transaction payload. Builder class handles versioning, serde process, milestones, dynamic-fee logic and all cryptography related items (sign, multisign, second-sign, sign with and without WIF, nonce logic). The source-code snippet shows the usage of the
BusinessRegistrationBuilder class (link below the code snippet will take you to the actual class implementation).
3. Implement BusinessRegistrationHandler Class
The previous two classes,
Transaction, introduced a new transaction type, implemented the serde process, and created signed transaction payload. In this part of custom transaction implementation, we will be handling verification and validation, following strict blockchain mechanics ( consensus rules, transaction, and block processing).
By inheriting default
TransactionHandler behavior we enforce existing GTI rules and provide options to implement additional transaction
apply logic. Apply logic consists of basic rules, for example, i.) check if there are enough funds in the wallet, ii.) check for duplicate transactions, iii.) if the received transaction is on the correct network (correct bridgechain), and many, many more.
We will explain GTI
TransactionHandler and the role it plays in our blockchain protocol in the following sections:
a.) How To Define Your Custom Transaction Dependencies
We must define the Transaction Type registration order if our custom transaction (e.g.
BusinessRegistrationTransaction ) depends on other transactions (e.g.
MultiSignature )— in short, the MultiSignature transaction must be registered before ours. We define transaction dependencies by using the
dependencies() method call, where we return an array of dependent classes. The source-code snippet shows how we return
MultiSignatureTransaction as a dependent class for
b.) How To Add Attributes To Global Wallets
We defined custom transaction fields and structure in part 1**. Implement BusinessRegistrationTransaction class** of this article (see above). Usually, we want to add custom properties to our global state (the
walletManager class). These properties need to be quickly accessible (
memoization) and searchable (
We will accomplish this with the
walletAttributes() method, where we define the
keys for our wallet attributes. Keys can be set during runtime by calling
wallet.setAttribute(key, value) method.
The source-code below shows registering of a new wallet attribute with key=
business. We set the attribute value during the
bootstrap() method call. When we are done with custom wallet attribute value changes, a reindex call is recommended on the
c.) Tapping Into the Transaction Bootstrap Process
Bootstrap process is run each time a core node is started. The process evaluates all of the transactions in the local database and applies them to the corresponding wallets. All of the amounts, votes, and other custom properties are calculated and applied to the global state —
walletManager. Since our new custom transaction
BusinessRegistrationTransaction follows the same blockchain mechanics, we only need to implement relevant
apply methods defined by the
TransactionHandler interface. These methods are:
d.) How To Implement Transaction-Pool Validation
The Transaction Pool serves as a temporary layer where valid and verified transactions are stored locally until it is their turn to be included in the newly forged (created) blocks. Each new custom transaction type needs to be verified and accepted bythe same strict limitation rules that are enforced for our core transactions. We need to implement
canEnterTransactionPool() method (see source-code snippet below) to follow the rules and execution structure. The method is called from the core.
4. Registration of a Newly Implemented Transaction Type Within Core
You made it. The final step awaits, and it is the easiest: registration of the newly implemented
BusinessRegistrationTransaction type. To accomplish this, we need to get access to the
core-transactions handler and call
registerTransactionHandler method (see code below).
Your custom transaction type implementation is now COMPLETE. A fully working example is available for you to examine, learn and download here. This example is implemented as a core module (plugin). You can learn more about core modules at and is using develop branch of the Core to achieve the above results (upcoming v2.6 Core).
How To Access New Transaction Types via Our Public Interfaces
Our newly implemented transaction type becomes a full member of a
core node after the registration call — meaning we can query it via existing Public API interfaces.
You can read more about our Public API here: *<em><a href="https://api.ark.dev" target="_blank" rel="noopener nofollow" class="inline-flex items-center space-x-2 font-semibold cursor-pointer whitespace-nowrap link" > <span>https://api.ark.dev</span> <svg wire:key="Etm3hbHL" class="fill-current w-4 h-4 mx-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23.251 7.498V.748h-6.75m6.75 0l-15 15m3-10.5h-9a1.5 1.5 0 00-1.5 1.5v15a1.5 1.5 0 001.5 1.5h15a1.5 1.5 0 001.5-1.5v-9" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg> </a> </em> .
Seamless Integration With ARK Core: We provide twelve (12+) different programming language implementations of our API, all accompanied by full cryptography protocol implementation**.***Simply install the* SDK of your choice and start interacting with the blockchain. For more information about our SDKs (REST API and crypto) refer to .
Secure JSON-RPC client: We also provide a JSON-RPC compliant package, targeting exchanges and other trusted execution environments. JSON-RPC client is meant to run inside a trusted environment.
After learning the best practices and architectural approaches in Part 1 of this series, we took a deep-dive into custom transaction type development with our Core GTI technology. We learned how to:
- Implement a new transaction type structure
- Implement a new custom transaction builder class
- Implement a general transaction handler that hooks our newly created transaction type with the blockchain protocol
- Use existing API interfaces to interact with core blockchain and new transaction types
DOWNLOAD: A fully working example is available for you to learn and download here.
Your newly implemented transaction type can now be packed into a core module and distributed to any ARK technology-based bridgechain (API and protocol compliant).
This series will be followed by separate tutorials and hands-on workshops where we will build a fully working blockchain application — backend and frontend. Stay tuned for exact dates and webinar registration links, and get involved!
Here’s a quick list of what your next steps might be to get involved with ARK: