Transaction

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.

Transactions accepted by the network are stored permanently on blocks.

Transaction types

There are different types of transactions. For example, you can transfer mosaics between accounts, transfer or configure the ownership of accounts (including the use of multisig rules), and more.

Id Type Description
Remote harvesting    
0x414C AccountLinkTransaction Delegate the account importance to a proxy account.
Aggregate    
0x4141 AggregateCompleteTransaction Send transactions in batches to different accounts.
0x4241 AggregateBondedTransaction Propose an arrangement of transactions between different accounts.
CosignatureTransaction Cosign an AggregateBondedTransaction.
Mosaic    
0x414D MosaicDefinitionTransaction Register a new mosaic.
0x424D MosaicSupplyChangeTransaction Change an existent mosaic supply.
Namespace    
0x414E NamespaceRegistrationTransaction Register namespaces 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 MultisigModificationAccountTransaction 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 a global restriction to a mosaic.
0x4251 MosaicAddressRestrictionTransaction Set a mosaic restriction to an specific address.
Transfer    
0x4154 TransferTransaction Send mosaics and messages between two accounts.

Defining a transaction

Transactions are defined in a serialized form. Each transaction extends from the transaction schema definition, combining the type’s particular properties. You can find the description of the additional properties under the “Schema” section, at the end of each built-in feature description.

We recommend using the NEM2-SDK to define transactions.

import {
    Address,
    Deadline,
    NetworkCurrencyMosaic,
    NetworkType,
    PlainMessage,
    TransferTransaction
} from "nem2-sdk";

const recipientAddress = Address
    .createFromRawAddress('SD5DT3-CH4BLA-BL5HIM-EKP2TA-PUKF4N-Y3L5HR-IR54');

const transferTransaction = TransferTransaction.create(
    Deadline.create(),
    recipientAddress,
    [NetworkCurrencyMosaic.createRelative(10)],
    PlainMessage.create('Welcome To NEM'),
    NetworkType.MIJIN_TEST);

console.log(transferTransaction.serialize());

/* Outputs:
B3000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000
000000000000039054410000000000000000B986E63F170
0000090FA39EC47E05600AFA74308A7EA607D145E371B5F
4F1447BC0F00010057656C636F6D6520546F204E454D44B
262C46CEABB858096980000000000
*/

Fees

Transactions have an associated cost. This cost is necessary to provide an incentive for the harvesters who secure the network and run the infrastructure.

The fee associated with a transaction primarily depends on the transaction’s size. The effective fee is the product of the size of the transaction, and a fee multiplier set by the harvester. The node owner can configure the latter value to all positive values, including zero.

effective_fee = transaction::size * block::fee_multiplier

A sender of a transaction must specify during the transaction definition a max_fee, meaning the maximum fee the account allows to spend for this transaction.

If the effective_fee is smaller or equal to the max_fee, the harvester can opt to include the transaction in the block. The fee_multiplier is stored in the block header, permitting to resolve which was the effective fee paid for every transaction included.

The harvesting nodes can decide their transaction inclusion strategy:

  • Prefer-oldest: Preferred for networks with high transaction throughput requirements. Include first the oldest transactions.
  • Minimize-fees: Philanthropic nodes. Include first transactions that other nodes do not want to include.
  • Maximize-fees: Most common in public networks. Include first transactions with higher fees.

By default, the fee is paid in cat.currency, the underlying currency of the NEM network. Private chains can edit the configuration of the network to eliminate fees, or use another mosaic that better suits their needs.

Signing a transaction

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 is the recipient and the quantity 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 :

  1. Get the signing bytes, which are all the bytes of the transaction except the size, signature and signer.
  2. Get the nemesis block generation hash. You can query http://localhost:3000/block/1 and copy meta.generationHash value.
  3. Prepend the nemesis block generation hash to the signing bytes.
  4. Sign the resulting string with the signer’s private key. This will give you the transaction signature.
  5. Append the signer’s signature and public key to the transaction to obtain the payload.
  6. Calculate the hash of the transaction applying the network hashing algorithm to the first 32 bytes of signature, the signer public key, nemesis block generation hash, and the remaining transaction payload.
import {Account} from "nem2-sdk";

const privateKey = process.env.PRIVATE_KEY as string;
const generationHash = process.env.GENERATION_HASH as string;
const account = Account.createFromPrivateKey(privateKey,NetworkType.MIJIN_TEST);

const signedTransaction = account.sign(transferTransaction, generationHash);

console.log(signedTransaction.payload);

/* Outputs:
B3000000F77A8DCFCB57B81F9BE5B46738F7132998F5512
3BFF4D89DC8E5CAE1F071A040E5571F4D8DA125B243C785
DA5261F878E3DE898815F6E8F12A2C0A5F0A9C3504FA624
9E8334E3F83E972461125504AFFD3E7750AFBB3371E7B2D
22A599A3D0E3039054410000000000000000265DEE3F170
0000090FA39EC47E05600AFA74308A7EA607D145E371B5F
4F1447BC0F00010057656C636F6D6520546F204E454D44B
262C46CEABB858096980000000000
 */

console.log(signedTransaction.hash);

/* Outputs:
21C4D9583CE1887BE7187D4B65B67567B45D5E6114AEE155C0CD266B6AA6A302
 */

Announcing a transaction

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.

import {TransactionHttp} from "nem2-sdk";

const transactionHttp = new TransactionHttp('http://localhost:3000');

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.

../_images/transaction-cycle.png

Transaction cycle

The first stage of validation happens in the API nodes. If the transaction presents some error, the WebSocket throws a notification through the status channel. In the positive case, the transaction reaches the P2P network with an unconfirmed status. Never rely on a transaction which has an unconfirmed state. It is not clear if it will get included in a block, as it should pass a second validation.

The second validation is done before the transaction is added in a harvested block. If valid, the harvester stores the transaction in a block, and it 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.

Rollbacks

Blockchains are designed in a way that under certain circumstances recent blocks need to be rolled back. These are essential to resolve forks of the blockchain.

The rewrite limit is the maximum number of blocks that can be rolled back. Hence, forks can only be resolved up to a certain depth too.

NEM has a rewrite limit of 40 blocks. Once a transaction has more than 40 confirmations, it cannot be reversed.

Guides

Schemas

Transaction

Serialization of a transaction.

Inlines:

Property Type Description
max_fee Amount Maximum fee allowed to spend for the transaction.
deadline Timestamp Number of seconds elapsed since the creation of the nemesis block. If a transaction does not get included in a block before the deadline is reached, it is deleted. Deadlines are only allowed to lie up to 24 hours ahead.

EmbeddedTransaction

Serialization of an aggregate inner transaction.

Inlines:

SizePrefixedEntity

Serialization of an entity that has a prefixed size.

Property Type Description
size unit32 Size of the transaction.