Create, sign and send a transaction
A user can modify the blockchain’s state by submitting a transaction. A transaction is a user-initiated instruction specifying a desired state change. Technically, a transaction specifies an action to be executed within a smart contract, accompanied by any necessary input parameters. The execution of this action can alter the smart contract’s state.
Creating, signing and sending a transaction
Section titled “Creating, signing and sending a transaction”To change the blockchain state using a transaction you must follow three steps:
Create a transaction
Section titled “Create a transaction”A transaction consists of:
-
The sender’s
nonce, which specifies how many transactions the sender has sent and is used to prevent replaying old transactions.The nonce for an account can be fetched from the following endpoint: http://localhost:9432/chain/accounts/{account-address}
-
An Unix timestamp specifying, the expiration time, called
validToTime. The timestamp specifies the amount of time you are willing to wait for the nodes to execute the transaction and change the state of the blockchain. It is used to prevent that the transaction sits in a queue for a very long time before being executed in the case of the network being slow. -
The amount of
gasallocated for executing the transactions. Gas is the amount of work, the transaction is allowed to have performed by the nodes. -
The blockchain address of the smart contract that is the target of the transaction.
-
The RPC (remote procedure call) payload of the transaction. A transaction calls an action on the targeted smart contract, you can read more about how to create the transaction payload here.
A transaction has the following binary format:
::= {
validToTime: 0xnn×8
(big-endian)
gas: 0xnn×8
(big-endian)
address: [Address](../../technical-reference/binary-formats/binary-formats/transaction/#address)
rpc: [Rpc](../../technical-reference/binary-formats/binary-formats/transaction/#rpc)
There are several ways of creating transactions. Below, we demonstrate how to do this using the terminal, Typescript, and Java.
Sign a transaction
Section titled “Sign a transaction”You must sign your transaction before sending it, because the signature proves your identity as the sender.
You create the signature on the transaction with your private key, by signing the serialize transaction.
On the blockchain, we use the ECDSA (Elliptic Curve Digital Signature Algorithm) signature scheme, using secp256k1 as the curve.
An example of a private key on this curve is d6f4e13c010dbca23f647627d9b6085b816c933678f6026446f9a9596a2fb0d7.
Every user should create their own private key, to use for signing transactions.
The signature has the following binary format:
::= {
recoveryId: 0xnn
valueR: 0xnn×32
(big-endian)
valueS: 0xnn×32
(big-endian)
}
The signature includes:
- A recovery id between 0 and 3 used to recover the public key when verifying the signature
- The r value of the ECDSA signature
- The s value of the ECDSA signature
To create a signed transaction you combine the transaction and the signature. The signed transaction is ready for sending onto the chain.
The signed transaction has the following binary format:
::= {
signature: [Signature](#signature)
transaction: [Transaction](#transaction)
}
A signed transaction includes:
- The signature of the transaction payload
- The transaction
Send a signed transaction
Section titled “Send a signed transaction”To send a signed transaction, comprising the transaction and its signature, you must submit it to the blockchain via an HTTP PUT request to any blockchain node’s endpoint. All the other nodes receive the signed transaction from the flooding network between all the blockchain nodes.
Examples
Section titled “Examples”Next, we provide detailed examples of how to create, sign and send transactions using the terminal, and in Typescript or Java.
Example in the terminal
Section titled “Example in the terminal”To send a transaction from your terminal, first you must set up the local integration environment and connect cargo pbc with the running Platform.
See how to do it here.
Here, we will use a Nickname smart contract
as an example. This contract allows users to give nicknames to blockchain addresses.
The contract defines the add_nickname action.
You can use your terminal to send a transaction which calls this action to give an address a nickname.
To run this example, you will need:
- The PBC-file of a Nickname smart contract
- A private key
First, deploy the Nickname contract with its PBC file. Read more about deploying contracts here.
cargo pbc transaction --net local deploy path/to/nickname.pbcOnce you have deployed the contract and have its blockchain address, you can send transactions from your terminal.
You can build, sign, and send a transaction with one single command.
Using the action command, you can add the nickname, my nickname,
by calling the action give_nickname with the same key address as before:
cargo pbc transaction --net local action nicknameAddress give_nickname 000000000000000000000000000000000000000001 "my nickname" --gas=10000In your application
Section titled “In your application”You can create, sign and send transactions from your application. Your application has to create the RPC for the transaction, the easiest solution is to generate code for a smart contract. The code can be generated for Java and TypeScript. If you are using a different language you will have to hand-write the code for creating the RPC. You can read more about generating the code or implementing the payload creation yourself here.
Common libraries
Section titled “Common libraries”The Partisia Platform includes a library to interact with the blockchain.
There are two implementations available, one in TypeScript and one in Java here.
Specifically, a client - BlockchainTransactionClient - for signing and sending transactions.
The BlockchainTransactionClient uses HTTP requests to communicate with the blockchain nodes.
The BlockchainTransactionClient can sign transactions creating a SignedTransaction.
The BlockchainTransactionClient can then send the SignedTransaction to any blockchain node for execution and inclusion in a block.
This call returns a SentTransaction, which contains:
- The signed transaction that was sent.
- A pointer to the signed transaction that was sent.
The transaction pointer is used to keep track of the transaction, e.g. to check that it has been included in a block.
Using TypeScript
Section titled “Using TypeScript”To run the example, you will need:
- Generated code from the ABI-file of the Nickname contract, to read more about how you do it, click here.
- The contract address of a deployed Nickname contract.
- The url to an endpoint exposed by any blockchain node.
- A key pair.
TypeScript example for Nickname
async function nicknameExample() { // Create the action transaction payload const nicknameRpc = giveNickname( '000000000000000000000000000000000000000005', 'a very good nickname', );
// Create the transaction by providing the arguments const nicknameAddress = '000000000000000000000000000000000000000001'; const transaction: Transaction = { address: nicknameAddress, rpc: nicknameRpc };
// Create authentication from a private key to create signatures const privateKey = 'aa'; const authentication = SenderAuthenticationKeyPair.fromString(privateKey);
// Create the client that creates signatures and communicates with the chain const blockchainUrl: string = 'url'; const transactionClient = BlockchainTransactionClient.create(blockchainUrl, authentication);
// Sign the transaction. You must determine how much gas to allocate. const signedTransaction = await transactionClient.sign(transaction, 12345);
// Send the signed transaction const sentTransaction = await transactionClient.send(signedTransaction);
// Recursively wait for the inclusion of all events spawned by the transaction // and the transaction's events await transactionClient.waitForSpawnedEvents(sentTransaction);}TypeScript example for Nickname - Sign and send
const sentTransaction = await transactionClient.signAndSend(transaction, gasAmount);Using Java
Section titled “Using Java”To run this code example, you will need:
- The generated code from the ABI-file of the Nickname contract, to read more about how you do it, click here.
- The contract address of a deployed Nickname contract.
- The URL to access the endpoint exposed by a blockchain node.
- A key pair.
Java example for Nickname
public class NicknameExample {
private static BlockchainAddress nicknameAddress; private static String privateKey; private static String blockchainUrl;
public static void main(String[] args) throws ApiException {
// Create a BlockchainTransactionClient with the blockchain url and a private key ApiClient apiClient = new ApiClient().setBasePath(blockchainUrl); ChainControllerApi chainControllerApi = new ChainControllerApi(apiClient); ShardControllerApi shardControllerApi = new ShardControllerApi(apiClient); SenderAuthenticationKeyPair keyPair = SenderAuthenticationKeyPair.fromString(privateKey); BlockchainTransactionClient transactionClient = BlockchainTransactionClient.create(chainControllerApi, shardControllerApi, keyPair);
// Create the rpc for giving a nickname by providing the arguments byte[] nicknameRpc = Nickname.giveNickname( BlockchainAddress.fromString("000000000000000000000000000000000000000005"), "a very good nickname");
// Create the transaction from the contract address and the transaction payload Transaction transaction = Transaction.create(nicknameAddress, nicknameRpc);
// Authentication to create signatures - takes a private key SenderAuthenticationKeyPair authentication = SenderAuthenticationKeyPair.fromString(privateKey);
// Sign the transaction. You must determine how much gas to allocate. SignedTransaction signedTransaction = transactionClient.sign(transaction, 12345);
// Send the signed transaction SentTransaction sentTransaction = transactionClient.send(signedTransaction);
// Recursively wait for the inclusion of all events spawned by the transaction // and the transaction's events transactionClient.waitForSpawnedEvents(sentTransaction); } }Java example for Nickname - Sign and send
SentTransaction sentTransaction = transactionClient.signAndSend( transaction, gasCost );
nonce: 0xnn×8
(big-endian)