A transaction generally represents a unit of work within a database system. In the case of blockchain, that is when an action signed by an account changes its state.
Symbol supports many different transaction types. For example, there are transactions to transfer mosaics between accounts, messages or configure the ownership of accounts (including the use of multisig rules), and more.
The following transaction types are included in Symbol based networks by default:
Id | Type | Description |
---|---|---|
Account Link | ||
0x414C | AccountKeyLinkTransaction | Delegate the account importance to a proxy account. Required for all accounts willing to activate delegated harvesting. |
0x424C | NodeKeyLinkTransaction | Link an account with a public key used by TLS to create sessions. Required for node operators. |
Aggregate | ||
0x4141 | AggregateCompleteTransaction | Send transactions in batches to different accounts. |
0x4241 | AggregateBondedTransaction | Propose an arrangement of transactions between different accounts. |
– | CosignatureTransaction | Cosign an AggregateBondedTransaction. |
Core | ||
0x4143 | VotingKeyLinkTransaction | Link an account with a BLS public key. Required for node operators willing to vote finalized blocks. |
0x4243 | VrfKeyLinkTransaction | Link an account with a VRF public key. Required for all harvesting eligible accounts. |
Mosaic | ||
0x414D | MosaicDefinitionTransaction | Create a new mosaic. |
0x424D | MosaicSupplyChangeTransaction | Change the mosaic total supply. |
Namespace | ||
0x414E | NamespaceRegistrationTransaction | Register a namespace to organize your assets. |
0x424E | AddressAliasTransaction | Attach a namespace name to an account. |
0x434E | MosaicAliasTransaction | Attach a namespace name to a mosaic. |
Metadata | ||
0x4144 | AccountMetadataTransaction | Associate a key-value state to an account. |
0x4244 | MosaicMetadataTransaction | Associate a key-value state to a mosaic. |
0x4344 | NamespaceMetadataTransaction | Associate a key-value state to a namespace. |
Multisignature | ||
0x4155 | MultisigAccountModificationTransaction | Create or modify a multisig contract. |
Hash Lock | ||
0x4148 | HashLockTransaction | Lock a deposit needed to announce aggregate bonded transactions. |
Secret Lock | ||
0x4152 | SecretLockTransaction | Start a token swap between different chains. |
0x4252 | SecretProofTransaction | Conclude a token swap between different chains. |
Account restriction | ||
0x4150 | AccountAddressRestrictionTransaction | Allow or block incoming and outgoing transactions for a given a set of addresses. |
0x4250 | AccountMosaicRestrictionTransaction | Allow or block incoming transactions containing a given set of mosaics. |
0x4350 | AccountOperationRestrictionTransaction | Allow or block outgoing transactions by transaction type. |
Mosaic restriction | ||
0x4151 | MosaicGlobalRestrictionTransaction | Set global rules to transfer a restrictable mosaic. |
0x4251 | MosaicAddressRestrictionTransaction | Set address specific rules to transfer a restrictable mosaic. |
Transfer | ||
0x4154 | TransferTransaction | Send mosaics and messages between two accounts. |
Every base transaction type available in Symbol is defined as a separate plugin. The plugin approach allows developers to introduce new transaction types without modifying the core engine or disrupting other features.
Transactions are defined in a serialized form. Every transaction extends from the base transaction schema definition, adding the type’s particular properties.
All transactions should define a deadline and a max_fee:
deadline
: A transaction has a time window to be accepted before it reaches its deadline. The transaction expires when the deadline is reached and all the nodes reject the transaction. By default, the SDK sets the deadline to 2 hours, but it can be extended up to 24 hours.max_fee
: The maximum amount of network currency that the sender of the transaction is willing to pay to get the transaction accepted. The next documentation shows you how to set the optimal max_fee value.Note
The catbuffer schemas repository defines how each transaction type should be serialized. In combination with the catbuffer-generators project, developers can generate builder classes for a given set of programming languages.
We recommend using the SDK to define new transactions.
// replace with recipient address
const rawAddress = 'TB6Q5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ';
const recipientAddress = Address.createFromRawAddress(rawAddress);
// replace with network type
const networkType = NetworkType.TEST_NET;
// replace with symbol.xym id
const networkCurrencyMosaicId = new MosaicId('5E62990DCAC5BE8A');
// replace with network currency divisibility
const networkCurrencyDivisibility = 6;
const transferTransaction = TransferTransaction.create(
Deadline.create(),
recipientAddress,
[new Mosaic (networkCurrencyMosaicId,
UInt64.fromUint(10 * Math.pow(10, networkCurrencyDivisibility)))],
PlainMessage.create('This is a test message'),
networkType,
UInt64.fromUint(2000000));
Accounts must sign transactions before announcing them to the network. Signing a transaction expresses the account’s agreement to change the network state as defined.
For example, a TransferTransaction describes who the recipient is and the number of mosaics to transfer. In this case, signing the transaction means to accept moving those mosaics from one account’s balance to another.
An account has to follow the next steps to sign a transaction:
signing bytes
, which are all the bytes of the transaction except the size, signature, and signer.generation hash
. You can query nodeUrl + '/node/info'
and copy meta.networkGenerationHash
value.signature
.payload
.// replace with sender private key
const privateKey = '1111111111111111111111111111111111111111111111111111111111111111';
const account = Account.createFromPrivateKey(privateKey, networkType);
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash = '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = account.sign(transferTransaction, networkGenerationHash);
console.log('Payload:', signedTransaction.payload);
console.log('Transaction Hash:', signedTransaction.hash);
Signed transactions are ready to be announced to the network.
You can either use the SDK TransactionHttp
service or append the payload to the request of the transaction endpoint.
// replace with node endpoint
const nodeUrl = 'http://api-01.us-east-1.096x.symboldev.network:3000';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp
.announce(signedTransaction)
.subscribe((x) => console.log(x), (err) => console.error(err));
curl -X PUT -H "Content-type: application/json" -d '{"payload":"B3000000F77A8DCFCB57B81F9BE5B46738F7132998F55123BFF4D89DC8E5CAE1F071A040E5571F4D8DA125B243C785DA5261F878E3DE898815F6E8F12A2C0A5F0A9C3504FA6249E8334E3F83E972461125504AFFD3E7750AFBB3371E7B2D22A599A3D0E3039054410000000000000000265DEE3F1700000090FA39EC47E05600AFA74308A7EA607D145E371B5F4F1447BC0F00010057656C636F6D6520546F204E454D44B262C46CEABB858096980000000000"}' http://localhost:3000/transaction
After announcing the transaction, the REST API will always return an OK response immediately. At this point, it is still unknown whether the transaction is valid.
The first stage of validation happens in the API nodes. If the transaction encounters an error, the WebSocket throws a notification through the status channel. If not, the transaction reaches the P2P network with an unconfirmed status. In this state, it is not yet clear if the transaction will get included in a block. Thus, an unconfirmed transaction should never be replied upon.
The second validation happens before the transaction is added in a harvested block. If successful, the harvester stores the transaction in a block and the transaction reaches the confirmed status.
Continuing the previous example, the transaction gets processed and the amount stated gets transferred from the signer’s account to the recipient’s account. Additionally, the transaction fee is deducted from the signer’s account.
The transaction has zero confirmations at this point. When another block is added to the blockchain, the transaction has one confirmation. The next block added to the chain will give it two confirmations and so on.
Under certain circumstances, like network failure or partition, the most recent confirmed blocks might need to be reversed. Rollbacks are characteristic of blockchain systems and essential to resolve forks.
In the public network, a transaction is considered to be irrevocable when it receives 398
confirmations. But the maximum number of blocks that can be rolled back is configurable per network.
In other words, it is necessary to wait at least 398
blocks after a transaction receives its first confirmation to guarantee that it cannot be reversed on the public network.
The node’s cache holds unconfirmed transactions until they can be included in a block. Since cache is a valuable resource, Symbol implements a spam throttle that prevents an attacker from filling the cache with unconfirmed transactions while still letting honest actors successfully submit new unconfirmed transactions.
The spam throttle controls the amount of unconfirmed transactions accounts can submit by calculating the fair share of cache for each account relative to its importance score. If an account has surpassed its fair share of the cache and the node cache contains more unconfirmed transactions than the amount that can be included in a single block, the transaction will be rejected. This effectively blocks malicious actors from spamming a node with transactions while allowing other users to continue using the node normally.
Turning the asynchronous transaction announcement into synchronous
Handy snippet to announce a transaction and wait until this is confirmed.
Continue: Fees.
Did you find what you were looking for? Give us your feedback.