Dive into Nebulas 4— Transactions

All interactions in blockchains are achieved through transactions. In this post, I’ll share what transactions in Nebulas look like and how to submit transactions in different situations.

Transaction

In Nebulas, we have three kinds of transactions: binary, deploy and call. Binary transactions are used to transfer tokens between accounts. Deploy transactions are used to deploy a smart contract. Call transactions are used to call functions in a deployed smart contract.

All transactions consist of 5 core parts: from/to, value, nonce, data, gas price/gas limit and signature.

From/To

From is always the sender’s address of the transaction. Otherwise, to differs in different transactions.

  1. Binary: to is the receiver of the tokens.
  2. Deploy: to is same as From.
  3. Call: to is the address of the smart contract to be called.

Value

Value is the count of tokens to be transferred. In Nebulas, 1 Wei equals 1 token and 1 NAS equals 10¹⁸ tokens.

Nonce

The nonce is designed to prevent replay attacks. For a given account, only after its transaction with nonce N is accepted, will its transaction with nonce N+1 be processed. Thus, we have to check the latest nonce of the account on chain before preparing a new transaction.

For example, we can use the following request to check current state of the account.

> curl -i -H 'Content-Type: application/json' -X POST http://localhost:8685/v1/user/accountstate -d '{"address":"n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE"}'
{"result":{"balance":"4999998999999939999999980","nonce":"1","type":87}}

The latest nonce of the account is 1. If we want to submit a new transaction using this account, the transaction should be with nonce 2.

Data

Data consists of Type and Payload. Type is the type of the transaction, such as binary, deploy and call. Payload varies in different transactions.

  1. Binary: Payload can be any byte array within 128 bytes.
  2. Deploy: Payload should be a JSON string, which contains codes with 128k, type of codes and initial arguments.
  3. Call: Payload should be a JSON string, which contains function name and arguments.

Gas Price/Gas Limit

In Nebulas, the sender of every transaction will be charged a few tokens by miners. Therefore, the execution of transaction will consume some Gas like Ethereum. Gas Price is the count of tokens that the sender wants to pay for each Gas consumed. Gas Limit is the max count of tokens that the sender wants to pay for the execution of the transaction.

More details about how the gas is calculated can be found here.

Signature

In Nebulas, the sender should sign the transaction to prove it’s sent by him. This is the basis of trust.

Send Transaction

In this section, I’ll introduce three methods to submit transactions and the typical situation they will be used in.

Sign and Send

In this way, we can sign a transaction in an offline environment and then submit it to another online node. This is the safest method for everyone to submit a transaction without exposing your own private key to the Internet.

First, sign the transaction to get raw data. We offer three methods to make it now.

Use Web-Wallet

Open the “Send Offline” page in Web-Wallet and choose the local net. Then fill in your address and inquire the information to check the state of your account.

Select your keystore file and unlock it with your passphrase. Everything happens locally so you don’t need to worry about security. You can even do this with your network disconnected to make sure your private key is safe.

Fill in the “To Address” and “Value/Amount to Send”, then generate the transaction to get the raw data of the signed transaction.

Use Local Node

Start your own node following this article and send the request as below.

> curl -i -H 'Content-Type: application/json' -X POST http://localhost:8685/v1/admin/sign -d '{"transaction":{"from":"n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE","to":"n1QZMXSZtW7BUerroSms4axNfyBGyFGkrh5", "value":"1000000000000000000","nonce":1,"gasPrice":"1000000","gasLimit":"2000000"}, "passphrase":"passphrase"}'
{"result":{"data":"CiCn3SxT3hBFCbcRa9D3GvaQhn+YT16nx5vqUlPps4Um7hIaGVcH+WT/SVMkY18ix7SG4F1+Z8evXJoA35caGhlXbip8PupTNxwV4SRM87r798jXWADXpWngIhAAAAAAAAAAAA3gtrOnZAAAKAEwrOPm1gU6CAoGYmluYXJ5QGRKEAAAAAAAAAAAAAAAAAAPQkBSEAAAAAAAAAAAAAAAAAAehIBYAWJBFvxLYeGgtj0Ob3g/AnaX9977E+9LTKLN+DqCJW23PaJs++OfTl+Yy7IO04UskAp6UrU17wXpxhVs7YlcQj1sEQE="}}

Use Neb.js

Make sure you include nebulas.js in your page and run the following commands.

var nebulas = require("nebulas")

var account = nebulas.Account

var transaction = nebulas.Transaction

var from = new account()

from.fromKey('{"address":"n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE","crypto":{"cipher":"aes-128-ctr","ciphertext":"b5041a4b9d4738bc2bcce580aeaadf53aa7c63b6aa3916b76c452630692fc397","cipherparams":{"iv":"f9d54f7854929e9e28731ee69d306a22"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":4096,"p":1,"r":8,"salt":"daa130fd5e3f9a77efe6028170becf7b1d9c73ce5c1d75d1142e90a68df12fed"},"mac":"aa390e6ed50741ed38670d1e1b11a1e44e174f9f66e41acc2e2d1762ebf1dfad","machash":"sha3256"},"id":"078fcad9-8f82-40e0-96c4-fb14b986c134","version":3}', 'passphrase', false)

var tx = new transaction({
chainID: 100,
from: from,
to: "n1SAeQRVn33bamxN4ehWUT7JGdxipwn8b17",
value: 10,
nonce: 1,
gasPrice: 1000000,
gasLimit: 2000000
});

tx.signTransaction()
tx.toProtoString()
"CiBTbM72sNjAbEqGfZcC913Qmz83o3EXJBLDo3Axdo5lOhIaGVcH+WT/SVMkY18ix7SG4F1+Z8evXJoA35caGhlXf89CeLWgHFjKu9/6tn4KNbelsMDAIIi2IhAAAAAAAAAAAAAAAAAAAAAKKAEw7+nm1gU6CAoGYmluYXJ5QGRKEAAAAAAAAAAAAAAAAAAPQkBSEAAAAAAAAAAAAAAAAAAehIBYAWJBRv9cm3+BLPfTy2tIeZOLIUEQYaBOFh874IiCyZoLD/5z5SBnjZdN9743nVS0d7jHnZFdH7sGAneKedv56fvUhgE="

The result is different from the first one because the TIMESTAMP is not same.

Then, send the raw data to an online Nebulas node.

> curl -i -H 'Content-Type: application/json' -X POST http://remote-ip:remote-port/v1/user/rawtransaction -d '{"data":"CiBTbM72sNjAbEqGfZcC913Qmz83o3EXJBLDo3Axdo5lOhIaGVcH+WT/SVMkY18ix7SG4F1+Z8evXJoA35caGhlXf89CeLWgHFjKu9/6tn4KNbelsMDAIIi2IhAAAAAAAAAAAAAAAAAAAAAKKAEw7+nm1gU6CAoGYmluYXJ5QGRKEAAAAAAAAAAAAAAAAAAPQkBSEAAAAAAAAAAAAAAAAAAehIBYAWJBRv9cm3+BLPfTy2tIeZOLIUEQYaBOFh874IiCyZoLD/5z5SBnjZdN9743nVS0d7jHnZFdH7sGAneKedv56fvUhgE="}'

Send with Passphrase

If you trust a Nebulas node so much that you can delegate your keystore files to it, the second method is a good fit for you.

First, upload your keystore files to the keydir folders in the trusted Nebulas node.

Then, send the transaction with your passphrase.

Use Local Node

Upload your keystore files to the keydir folders in your trusted remote node. Then send the request with your passphrase as below.

> curl -i -H 'Content-Type: application/json' -X POST http://remote-ip:remote-port/v1/admin/transactionWithPassphrase -d '{"transaction":{"from":"n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE","to":"n1QZMXSZtW7BUerroSms4axNfyBGyFGkrh5", "value":"1000000000000000000","nonce":2,"gasPrice":"1000000","gasLimit":"2000000"},"passphrase":"passphrase"}'
{"result":{"txhash":"6db26dce3cffcff45196750bc395399313c7e41776ea0ff33325e66b86d60700","contract_address":""}}

Use Neb.js

Upload your keystore files to the keydir folders in your trusted remote node. Then send the request with your passphrase as below.

var nebulas = require("nebulas");

var neb = new nebulas.Neb();

neb.setRequest(new nebulas.HttpRequest("http://remote-ip:remote-port"));
neb.admin.sendTransactionWithPassphrase({
from: "n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE",
to: "n1SAeQRVn33bamxN4ehWUT7JGdxipwn8b17",
value: 10,
nonce: 2,
gasPrice: 1000000,
gasLimit: 2000000,
passphrase: "passphrase"
}).then(function(tx) {
console.log(tx)
});

Send Directly

This is the most dangerous method. You probably shouldn’t use it unless you you have complete trust in the receiving Nebulas node.

First, upload your keystore files to the keydir folders in the trusted Nebulas node.

Then unlock your accounts with your passphrase for a given duration in the node. The unit of the duration is nano seconds(300000000000=300s).

> curl -i -H 'Content-Type: application/json' -X POST http://remote-ip:remote-port/v1/admin/account/unlock -d '{"address":"n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE","passphrase":"passphrase","duration":"300000000000"}'

After unlocking the account, everyone is able to send any transaction directly within the duration in that node without your authorization.

> curl -i -H 'Content-Type: application/json' -X POST http://remote-ip:remote-port/v1/admin/transaction -d '{"from":"n1FF1nz6tarkDVwWQkMnnwFPuPKUaQTdptE","to":"n1SAeQRVn33bamxN4ehWUT7JGdxipwn8b17", "value":"1000000000000000000","nonce":3,"gasPrice":"1000000","gasLimit":"2000000"}'

What’s Next?

I hope this helped you to understand the different methods for sending transactions on Nebulas, so you can choose the right one that works for you. Next, I’ll explain how to deploy and call a smart contract in Nebulas.