This post will in-depth in-detailed to explain how IOTA making a transaction, from transaction to bundle, from hash to address, from private key to signature message. This is all you need about to know how IOTA proposed a transaction from one address to another.
0. Before We Start
Please make sure you have already read this two material:
It gives you the basic view of IOTA transaction.
1. The Steps to make a transaction
- Making bundle include all inputs and outputs
- Prepare output transactions
- Prepare input transactions until input value fulfill output value
- Finalized bundle to get bundle hash and filling into all transaction
- Singing transactions to filling signature message fragment
- Get two tips for trunk and branch hash
- via IRI
- via IRI
- Proof of Work
- Fill up trunk and branch hash to transaction
- Fill up tag with obsolete tag if tag is not set
- Fill up timestamp to transaction
- Calculate nonce via
pearlDiverand get transaction hash
At the end of this, we will get transaction trytes which include all elements that we need (bundle hash, branch / trunk hash, nonce, and transaction has).
2. Making bundle
In IOTA bundle, you can find three type of transaction include in it. Input transaction, Output transaction, and Meta transaction.
- Input transaction: transaction value is negative.
- Output transaction: transaction value is positive.
- Meta transaction: transaction value is 0, it can be the carieer of signature, or save other message in transaction's siganture message fragment.
Let's take an example, A has 3 address from same seed, with some value:
index 0: AAAAAAAA, balance: 50
index 1: BBBBBBBB, balance: 70
index 2: CCCCCCCC, balance: 20
When A what to send 100i to B's address
DDDDDDDD, IOTA will do something like this:
- Prepare output transaction to B's address and add into bundle
- Prepare input transaction from A's address with balance
- Add each input transaction into bundle with meta transaction slot
- meta transaction slot amount will depend on address security level, default security level of address is 2, that means we will need one additional transaction to carrying transaction signature.
- If the balance of bundle is still positive, add in an unspent output transaction to move unspent value
- Bundle finalized
- Check bundle balance is 0 (that input value = output value)
- Generate bundle hash
- Using Kerl absorb with transaction validate item (address, value, obsolete tag, timestamp, current index, and last index)
- squeeze out bundle trits and convert to bundle hash
- Check if generate a secure bundle hash, if not, increase obsolete tag and regenerate again
- Fill bundle hash and init signature fragment to all transaction
- notice that transaction hash, transaction tips, signature fragment and nonce are not filling in this step, only bundle hash is determined.
- Bundle signing
- Get key generator via
- Iterate through transactions, if transaction is an output transaction, it will try to signing this transaction (with meta transaction if needed)
- Get address private key via key generate with address index and security level
- Using address private key and bundle hash to generate signature fragment and filling into transaction's signature fragment part.
- If the security level is 2, then we will need to sign up two transaction (1 for output transaction and the following meta transaction)
- Get key generator via
At the end of this step, we will get a list of transaction trytes that including bundle hash and transaction signature with the reverse direction (from the last index to 0 index).
3. Get two tips for trunk and branch
In this article I will not cover the MCMC algorithm, think this as a black box that we can get two tips from IRI via getTransactionsToApprove.
4. Proof of Work
In the last step, we will need to fill-up trunk, branch, and find nonce (Proof of Work here!) into each transaction in the bundle.
As bundles documentation mention, a bundle is an atomic transfer item in the tangle, which means in one bundle, they will have the same tips.
It will then walk through all transactions in the bundle from the last index to 0 index, to fill-up trunk, branch hash, timestamp, and then do PoW (pearlDiver) to find nonce and generate transaction hash, then validated the PoW result.
Last index's transaction trunk and branch hash will be previous tips we get. Other transaction's trunk will be previous transaction's hash, and branch hash is trunk transaction from tips.
If everything is fine, we then can get the full transactions trytes with all field be filled in!
5. PoC code from Python with PyOTA
Here we describe how IOTA construct a bundle with transactions, and when it fill-up some critical parts of the transaction, such as bundle hash, transaction hash, trunk hash, branch hash, and nonce.
We can clearly know that in all the step to making a transaction, the essential part of an IoT device will only need to take care of the part of signing its transaction, other parts such as other output transaction, tip selection and PoW will no need to be done on it.