You’ll notice this outputs array already has an output for our transaction. This is our change output. If we spend 10.25 Grin, and if we are only using one input in this transaction (as is the case here), then thatinput contains at least 10.25 Grin. If this input consists of 20 Grin, for example, then this transaction alsorequires an output to send 9.75 Grin back to us!

Grin is unique in that Bob needs to be involved in any output that goes to him, and since we haven’t actually sent this file to Bob yet, we’re not ready to create that part of the transaction. Our change output has nothing to do with Bob, though, which is why we are already able to compute our change output.

Besides the features and commit, this output contains a proof. This is the range proof for the output, and it proves that the amount of Grin in that output is non-negative. Range proofs allow us to cryptographically prove the output is non-negative without revealing what that output actually is.

The transaction kernel also starts with the features variable. This part may be a little confusing: the features variable you see for any output is either “Plain” or “Coinbase”, as I explained earlier. But in the transaction kernel, the features variable can either be “Plain”, “Coinbase”, or “HeightLocked”.

The three different kinds of “features” in a transaction kernel: Coinbase, Plain, and HeightLocked

A “Plain” transaction means a lock_height of 0. In other words, once this transaction is broadcast to the network, it can be mined immediately. As soon as any Grin transaction is mined, its outputs can be spent. A HeightLocked transaction, in contrast, means that the transaction can’t be mined until a certain block number.

Once mined, the output will have a feature of either “Plain” or “Coinbase”, as we saw above, because the fact that it may have been HeightLocked before it was mined is no longer relevant.

amount: The amount of Grin being transferred, as a multiple of the atomic unit 1 nanoGrin. A nanoGrin is one billionth of a Grin. Only the sender and recipient will ever see this amount.

fee: The mining fee for the transaction, also as a multiple of 1 nanoGrin.

height: The block number at which this transaction file was created.

lock_height: The block number at which the outputs from this transaction become spendable. You’ll notice in this case, the lock_height is equal to the height variable, meaning this transaction can be mined immediately.

part_sig: Our partial signature is empty, because we’re not able to create it until we receive data back from Bob.

message: An extra “message” that can be added to your transaction. If you create this file with a -g flag and put any arbitrary string afterwards, that message would appear here.

Note: when people generally refer to the “message” of a Grin transaction, they typically mean the transaction fee, if any, and the lock_height, if any. This extra “message” field is entirely separate: you can add a string to send to Bob, and vice-versa, that never gets published on-chain.

message_sig: The extra “message” field I just mentioned is signed by your sum of all blinding factors. That signature is placed here, and Bob can verify that message by using your commitment to your sum of all blinding factors. Bob can add his own extra message and message_sig to the file once he receives this file. We can verify his message the same way.

We send this file to Bob, and await his response file in return.

Bob’s Response File

Bob accepts this file in his Grin client with the following command:

grin wallet receive -I my_grin_transaction.tx

This command generates a my_grin_transaction.tx.response file for Bob that he will send back to us.

As we can see, this file is everything we sent to Bob, plus some of his own data he added on top of it.

In the participant data array, we see a new entry for a participant with an id of 1 (Bob). Bob adds his commitment to his blinding factor, along with his commitment to his nonce, and finally his partial signature.

Finalizing the Transaction

When we receive Bob’s response file, we run the following to finalize the transaction:

grin wallet finalize -i my_grin_transaction.tx.response

We don’t actually see the missing pieces filled in — instead, we see:

grin wallet finalize command run successfully

We now has all the information we need from Bob to create his output and add it to the outputs array. Behind the scenes, our Grin client fills in the missing pieces (like excess and excess_signature), serializes this data into a byte array, and sends it across the Grin network for validation.

Soon, this Grin transaction will be mined, Bob will receive his 10.25 Grin, and we will receive our change.