How to use Tezos RPCs
In this very short story, we’re going to learn how to use RPCs with Tezos. At the end of this, again, very short story, you should know how to use them and where to look for more information about it. Let’s get started!
Before starting
I highly suggest you to check my story “I tested Tezos” (Part. 1) https://medium.com/chain-accelerator/i-tested-tezos-b254504775be so you know how to run a node.
Once your node is running, you can now start using RPCs :)
Using RPCs
First thing to know about RPCs is that you can find a complete documentation about them here: http://tezos.gitlab.io/mainnet/api/rpc.html
You will have access to a list of all available RPCs that you can get.
You can do the same thing using the tezos-client
, like this:
chainacc@tezos:~/tezos$ ./tezos-client rpc list
And you will get the list of all available RPCs. You can use the same command for each service. For example,
chainacc@tezos:~/tezos$ ./tezos-client rpc list /chains/main/
will return the following:
Warning:
This is NOT the Tezos Mainnet.
The node you are connecting to claims to be running on the
Tezos Alphanet DEVELOPMENT NETWORK.
Do NOT use your fundraiser keys on this network.
Alphanet is a testing network, with free tokens.Available services:
+ chains/main/
- GET /chains/main/blocks
Lists known heads of the blockchain sorted with decreasing fitness.
Optional arguments allows to returns the list of predecessors for
known heads or the list of predecessors for a given list of blocks.
- /chains/main/blocks/<block_id> <dynamic>
- GET /chains/main/chain_id
The chain unique identifier.
- GET /chains/main/invalid_blocks
Lists blocks that have been declared invalid along with the errors
that led to them being declared invalid.
- GET /chains/main/invalid_blocks/<block_hash>
The errors that appears during the block (in)validation.
- DELETE /chains/main/invalid_blocks/<block_hash>
Remove an invalid block for the tezos storage
- /chains/main/mempool <dynamic>Dynamic parameter description:
<block_hash>
block_hash (Base58Check-encoded)
<block_id>
A block identifier. This is either a block hash in Base58Check
notation, one the predefined aliases: 'genesis', 'head' or a block
level (index in the chain). One might also use 'head~N' or '<hash>~N'
where N is an integer to denote the Nth predecessor of the designated
block.Also, '<hash>+N' denotes the Nth successor of a block.
Which contains all the available services you can call under /chains/main/
.
We are first going to handle a few GET and then we will do some POST in order to inject a transaction.
GET RPCs
Before I start, you must know that most of the responses (if not all) from the RPC calls I will make will be different from yours, which is completely normal.
For now, we’re going to use this route:
/chains/<chain_id>
with <chain_id>
being main
. So, to get the ID of the main
chain, we can use this:
chainacc@tezos:~/tezos$ ./tezos-client rpc get /chains/main/chain_id
In my case, it returns:
"NetXgtSLGNJvNye"
which is the ID of the main
chain. Let’s go further, let’s get some information about a block.
chainacc@tezos:~/tezos$ ./tezos-client rpc get /chains/main/blocks/
The above command will list known heads of the blockchain. You can now take one of them, and use it for our next command:
chainacc@tezos:~/tezos$ ./tezos-client rpc get /chains/main/blocks/BLOCK_HERE
So, the final command should look like this:
chainacc@tezos:~/tezos$ ./tezos-client rpc get /chains/main/blocks/BLfcT1XX1bx1QiYSxfMjdSuWvfqemPMYvnEssXTXzcrYyQnQbHL
It basically gets a bunch of information about the specified blocks. I will show you what it displayed for me at the moment I entered the command. It’s kinda huge, sorry in advance.
{ "protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"chain_id": "NetXgtSLGNJvNye",
"hash": "BLfcT1XX1bx1QiYSxfMjdSuWvfqemPMYvnEssXTXzcrYyQnQbHL",
"header":
{ "level": 439394, "proto": 2,
"predecessor": "BLKsHXHjacbLYQFTZ1hgymZjkjefpTj5YgQUfW4HYFsDE5akn1V",
"timestamp": "2019-06-13T14:12:48Z", "validation_pass": 4,
"operations_hash":
"LLoZVZcZ5qNUEWHoBCXcfYitfDJZiGzDJQgvUdpavwjejMFc7UVBo",
"fitness": [ "00", "0000000000c98f02" ],
"context": "CoWAK4SWWt9cWFbt3tQBzJ1ZxRSpdKBW326kmo4MaNukkdnJDeqe",
"priority": 0, "proof_of_work_nonce": "00000003b6818d3e",
"signature":
"sigqPNHueubaGZmr8yMbTAGMsPGmjKDCe5u9zFpGpfH4BcXmUXa52gtUhXjQNDngpp9qqiErEBLdjHwyf6ZGuBH54psrAq4R" },
"metadata":
{ "protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"next_protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"test_chain_status": { "status": "not_running" },
"max_operations_ttl": 60, "max_operation_data_length": 16384,
"max_block_header_length": 238,
"max_operation_list_length":
[ { "max_size": 32768, "max_op": 32 }, { "max_size": 32768 },
{ "max_size": 135168, "max_op": 132 }, { "max_size": 524288 } ],
"baker": "tz1X7fu4GXBXp9A8fchu1px3zzMDKtagDBk3",
"level":
{ "level": 439394, "level_position": 439393, "cycle": 214,
"cycle_position": 1121, "voting_period": 53,
"voting_period_position": 5217, "expected_commitment": false },
"voting_period_kind": "proposal", "nonce_hash": null,
"consumed_gas": "0", "deactivated": [],
"balance_updates":
[ { "kind": "contract",
"contract": "tz1X7fu4GXBXp9A8fchu1px3zzMDKtagDBk3",
"change": "-512000000" },
{ "kind": "freezer", "category": "deposits",
"delegate": "tz1X7fu4GXBXp9A8fchu1px3zzMDKtagDBk3", "cycle": 214,
"change": "512000000" },
{ "kind": "freezer", "category": "rewards",
"delegate": "tz1X7fu4GXBXp9A8fchu1px3zzMDKtagDBk3", "cycle": 214,
"change": "16000000" } ] },
"operations":
[ [ { "protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"chain_id": "NetXgtSLGNJvNye",
"hash": "ooQNZYbkneJgRewPBBR8hBYktx3BLuZAtyunpRwJUZ7hyK7o65b",
"branch": "BLKsHXHjacbLYQFTZ1hgymZjkjefpTj5YgQUfW4HYFsDE5akn1V",
"contents":
[ { "kind": "endorsement", "level": 439393,
"metadata":
{ "balance_updates":
[ { "kind": "contract",
"contract": "tz3gN8NTLNLJg5KRsUU47NHNVHbdhcFXjjaB",
"change": "-512000000" },
{ "kind": "freezer", "category": "deposits",
"delegate": "tz3gN8NTLNLJg5KRsUU47NHNVHbdhcFXjjaB",
"cycle": 214, "change": "512000000" },
{ "kind": "freezer", "category": "rewards",
"delegate": "tz3gN8NTLNLJg5KRsUU47NHNVHbdhcFXjjaB",
"cycle": 214, "change": "16000000" } ],
"delegate": "tz3gN8NTLNLJg5KRsUU47NHNVHbdhcFXjjaB",
"slots": [ 29, 26, 11, 10, 4, 3, 2, 0 ] } } ],
"signature":
"sigNjvJvNKNTtXuRU4bSCnXAqKB9dk6XgqV7bsnK9nVxTFQd6t75Sn8NDsTwnxgNUJUWyNG4bQny6faQjuEagu8cbzXcGJae" },
{ "protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"chain_id": "NetXgtSLGNJvNye",
"hash": "opKz7E5nfF2d6mi9KHPNVGSktYK7PfCSiwYhrhvLYMHgBZ5YEq6",
"branch": "BLKsHXHjacbLYQFTZ1hgymZjkjefpTj5YgQUfW4HYFsDE5akn1V",
"contents":
[ { "kind": "endorsement", "level": 439393,
"metadata":
{ "balance_updates":
[ { "kind": "contract",
"contract": "tz1X7fu4GXBXp9A8fchu1px3zzMDKtagDBk3",
"change": "-64000000" },
{ "kind": "freezer", "category": "deposits",
"delegate": "tz1X7fu4GXBXp9A8fchu1px3zzMDKtagDBk3",
"cycle": 214, "change": "64000000" },
{ "kind": "freezer", "category": "rewards",
"delegate": "tz1X7fu4GXBXp9A8fchu1px3zzMDKtagDBk3",
"cycle": 214, "change": "2000000" } ],
"delegate": "tz1X7fu4GXBXp9A8fchu1px3zzMDKtagDBk3",
"slots": [ 22 ] } } ],
"signature":
"sigTWUypVPf9qzWpHGTEAzxwN2ts9KKPH8g91mcXuQ3RJFsYMup4FFF1UGJdvGz5FV6AARXf717zpUckPUsbizFXgoeEUBdZ" },
{ "protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"chain_id": "NetXgtSLGNJvNye",
"hash": "opZGJcoEQVoLtbGjL6qrCahLA62DDu1oYYFdeXpoitc5CbeLd7N",
"branch": "BLKsHXHjacbLYQFTZ1hgymZjkjefpTj5YgQUfW4HYFsDE5akn1V",
"contents":
[ { "kind": "endorsement", "level": 439393,
"metadata":
{ "balance_updates":
[ { "kind": "contract",
"contract": "tz1aWXP237BLwNHJcCD4b3DutCevhqq2T1Z9",
"change": "-64000000" },
{ "kind": "freezer", "category": "deposits",
"delegate": "tz1aWXP237BLwNHJcCD4b3DutCevhqq2T1Z9",
"cycle": 214, "change": "64000000" },
{ "kind": "freezer", "category": "rewards",
"delegate": "tz1aWXP237BLwNHJcCD4b3DutCevhqq2T1Z9",
"cycle": 214, "change": "2000000" } ],
"delegate": "tz1aWXP237BLwNHJcCD4b3DutCevhqq2T1Z9",
"slots": [ 24 ] } } ],
"signature":
"signjdkRNh9DHPgQ2jNZdTcamZwMNLaB6d9v8UPQZUuadhF51k9e4qPvK1pjYkWWw6NjamPaDhDnA9tR95WiTzzBcwBHvb1i" },
{ "protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"chain_id": "NetXgtSLGNJvNye",
"hash": "opKomgXnBYA5YoYin9B67EVejJGhDnhfUrroYeQ5B1psvnXUoUk",
"branch": "BLKsHXHjacbLYQFTZ1hgymZjkjefpTj5YgQUfW4HYFsDE5akn1V",
"contents":
[ { "kind": "endorsement", "level": 439393,
"metadata":
{ "balance_updates":
[ { "kind": "contract",
"contract": "tz3WXYtyDUNL91qfiCJtVUX746QpNv5i5ve5",
"change": "-576000000" },
{ "kind": "freezer", "category": "deposits",
"delegate": "tz3WXYtyDUNL91qfiCJtVUX746QpNv5i5ve5",
"cycle": 214, "change": "576000000" },
{ "kind": "freezer", "category": "rewards",
"delegate": "tz3WXYtyDUNL91qfiCJtVUX746QpNv5i5ve5",
"cycle": 214, "change": "18000000" } ],
"delegate": "tz3WXYtyDUNL91qfiCJtVUX746QpNv5i5ve5",
"slots": [ 31, 28, 23, 19, 17, 15, 14, 13, 6 ] } } ],
"signature":
"sigmJf62sxchuvAYysyGzhBVz5u1tMo9BLJL7STJFfb1kMK9anJL9uZh4rrYhyUTJoEpn81XzpPhkq4z5uvrBjsUi1U8KgTh" },
{ "protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"chain_id": "NetXgtSLGNJvNye",
"hash": "ooUreTSWpUiexpmU2EeeEEPGdvzZtVAohjTM9Mf3ydpK3f2QDwg",
"branch": "BLKsHXHjacbLYQFTZ1hgymZjkjefpTj5YgQUfW4HYFsDE5akn1V",
"contents":
[ { "kind": "endorsement", "level": 439393,
"metadata":
{ "balance_updates":
[ { "kind": "contract",
"contract": "tz1hodJSw6uv7LqArLW86zKuUjkXiayJvqCf",
"change": "-128000000" },
{ "kind": "freezer", "category": "deposits",
"delegate": "tz1hodJSw6uv7LqArLW86zKuUjkXiayJvqCf",
"cycle": 214, "change": "128000000" },
{ "kind": "freezer", "category": "rewards",
"delegate": "tz1hodJSw6uv7LqArLW86zKuUjkXiayJvqCf",
"cycle": 214, "change": "4000000" } ],
"delegate": "tz1hodJSw6uv7LqArLW86zKuUjkXiayJvqCf",
"slots": [ 21, 8 ] } } ],
"signature":
"sigoU9KqeiEmghqR8nF2Snvf3jKcsac3rBQhtumDJn3mq3VJnxUWJkXtD4osc6syS18BB1LQj86x5aAUaoTk2WC4KUfL5u3T" },
{ "protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"chain_id": "NetXgtSLGNJvNye",
"hash": "ooJMd8NBKnVtFzc6RuzboYTgB31titPzPkUX2rBpxwdMh5sJija",
"branch": "BLKsHXHjacbLYQFTZ1hgymZjkjefpTj5YgQUfW4HYFsDE5akn1V",
"contents":
[ { "kind": "endorsement", "level": 439393,
"metadata":
{ "balance_updates":
[ { "kind": "contract",
"contract": "tz1YCABRTa6H8PLKx2EtDWeCGPaKxUhNgv47",
"change": "-320000000" },
{ "kind": "freezer", "category": "deposits",
"delegate": "tz1YCABRTa6H8PLKx2EtDWeCGPaKxUhNgv47",
"cycle": 214, "change": "320000000" },
{ "kind": "freezer", "category": "rewards",
"delegate": "tz1YCABRTa6H8PLKx2EtDWeCGPaKxUhNgv47",
"cycle": 214, "change": "10000000" } ],
"delegate": "tz1YCABRTa6H8PLKx2EtDWeCGPaKxUhNgv47",
"slots": [ 30, 27, 16, 7, 1 ] } } ],
"signature":
"sigVzAUw89uitmc1uT2XHTmZrsBYYyzQSwJS4uNVJ1vSA7PtHTXscMiPjTYx2GtSi62ZAuQPiqueeC8BvLkFRcpp81WYnsoH" } ],
[], [], [] ] }
It is pretty self-explanatory, so I advise you to take some time and read what the command returns.
Let’s go further and add /context/constants
at the end of the line in order to get some information about the block’s constants.
chainacc@tezos:~/tezos$ ./tezos-client rpc get /chains/main/blocks/BLfcT1XX1bx1QiYSxfMjdSuWvfqemPMYvnEssXTXzcrYyQnQbHL/context/constants
Here is what it returns for me:
{ "proof_of_work_nonce_size": 8, "nonce_length": 32,
"max_revelations_per_block": 32, "max_operation_data_length": 16384,
"max_proposals_per_delegate": 20, "preserved_cycles": 3,
"blocks_per_cycle": 2048, "blocks_per_commitment": 32,
"blocks_per_roll_snapshot": 256, "blocks_per_voting_period": 8192,
"time_between_blocks": [ "30", "40" ], "endorsers_per_block": 32,
"hard_gas_limit_per_operation": "800000",
"hard_gas_limit_per_block": "8000000",
"proof_of_work_threshold": "70368744177663",
"tokens_per_roll": "8000000000", "michelson_maximum_type_size": 1000,
"seed_nonce_revelation_tip": "125000", "origination_size": 257,
"block_security_deposit": "512000000",
"endorsement_security_deposit": "64000000", "block_reward": "16000000",
"endorsement_reward": "2000000", "cost_per_byte": "1000",
"hard_storage_limit_per_operation": "60000",
"test_chain_duration": "1966080" }
Among other interesting information, we get the hard gas limit per operation ("hard_gas_limit_per_operation": "800000"
) for this specific block. We also have the "tokens_per_roll"
which is equivalent to 8,000 tez (it used to be 10,000 but it decreased a few weeks ago).
This is a very basic approach to how you can use Tezos RPCs GET. Please, do use Tezos’ official documentation linked at the beginning of the story, to learn more about them and what you can do with them.
Let’s now see POST RPCs.
POST RPCs
What is better than creating a transaction to use POST RPCs? Let’s do this!
So, in order to create a transaction, we’re going to need:
- The hash of the head block
- The sender
- The gas limit
- The storage limit
- and the receiver
You can get everything using the GET RPCs we used above. In order to run the operation, use the following POST RPC:
chainacc@tezos:~/tezos$ ./tezos-client rpc post /chains/main/blocks/head/helpers/scripts/run_operation
When entering this, it will ask you for the following:
{ "branch": "/definitions/block_hash",
"contents": [ "/definitions/operation.alpha.contents" ],
"signature": "/definitions/Signature" }
After editing it, it should look like this:
{ "branch": "BLnfTrJ6zwakFL6LbBzrD2tRSQuVJ2YymAnNHsYqW9FqEQLEFHT",
"contents": [
{ "kind": "transaction",
"source": "tz1VFgcWrcLvxpWcMvKnzFZpLjWxNT4wuosx",
"fee": "1",
"counter": "36904",
"gas_limit": "800000",
"storage_limit": "60000",
"amount": "1",
"destination": "tz1hBT7dx9aaiZTEsSJUnB8fKQ76EswyTLgZ" }
],
"signature": "edsigtXomBKi5CTRf5cjATJWSyaRvhfYNHqSUGrn4SdbYRcGwQrUGjzEfQDTuqHhuA8b2d8NarZjz8TRf65WkpQmo423BtomS8Q"
}
As it’s just a simulation, it doesn’t check for signature. So you can use a fake one, but it has to be in the good format. Use this one:
edsigtXomBKi5CTRf5cjATJWSyaRvhfYNHqSUGrn4SdbYRcGwQrUGjzEfQDTuqHhuA8b2d8NarZjz8TRf65WkpQmo423BtomS8Q
And you can save and run the call. What we do with this RPC call is we simulate the transaction to make sure everything is fine. It should return something like this:
{ "contents":
[ { "kind": "transaction",
"source": "tz1VFgcWrcLvxpWcMvKnzFZpLjWxNT4wuosx", "fee": "1",
"counter": "36904", "gas_limit": "800000", "storage_limit": "60000",
"amount": "1", "destination": "tz1hBT7dx9aaiZTEsSJUnB8fKQ76EswyTLgZ",
"metadata":
{ "balance_updates":
[ { "kind": "contract",
"contract": "tz1VFgcWrcLvxpWcMvKnzFZpLjWxNT4wuosx",
"change": "-1" },
{ "kind": "freezer", "category": "fees",
"delegate": "tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU",
"cycle": 223, "change": "1" } ],
"operation_result":
{ "status": "applied",
"balance_updates":
[ { "kind": "contract",
"contract": "tz1VFgcWrcLvxpWcMvKnzFZpLjWxNT4wuosx",
"change": "-1" },
{ "kind": "contract",
"contract": "tz1hBT7dx9aaiZTEsSJUnB8fKQ76EswyTLgZ",
"change": "1" } ], "consumed_gas": "10200" } } } ] }
We can see it consumed “10200” gas and no storage. The status
is applied
, which means that the transaction was successfully simulated by our node.
Before continuing and pre-applying the transaction, we need a signature, and this time: a real one. To do so, we’re going to forge a binary operation. Be careful: the node is going to send us a binary transaction, so you have to be SURE that you can trust the node. Otherwise, it could just send you a different binary transaction.
Based on the previous response, we know that our operation should be like this:
{ "branch": "BLnfTrJ6zwakFL6LbBzrD2tRSQuVJ2YymAnNHsYqW9FqEQLEFHT",
"contents": [
{ "kind": "transaction",
"source": "tz1VFgcWrcLvxpWcMvKnzFZpLjWxNT4wuosx",
"fee": "1",
"counter": "36904",
"gas_limit": "10500",
"storage_limit": "0",
"amount": "1",
"destination": "tz1hBT7dx9aaiZTEsSJUnB8fKQ76EswyTLgZ" }
]
}
We updated gas_limit
based on the info we received from the simulation (it was 10200
but we added 300 for security) and storage_limit
to 0. The signature is not here yet, it’s normal since we don’t have it. Speaking about it, let’s get the signature right now.
We have to translate the above operation to a binary format. To do so, let’s use a new POST RPC:
chainacc@tezos:~/tezos$ ./tezos-client rpc post /chains/main/blocks/head/helpers/forge/operations
It should show you something like:
"/definitions/operation.alpha.unsigned_operation"
Which you can delete and paste your operation (see above) instead. It returns this, which should obviously be different for you:
"8da5164e7a0ae00e8282e57f7950367a9cc2ef777271cf21ed89971d2218a34d08000069775863172a9ee22b0b72e9aa8d2fe8a7747dc901a8a002845200010000ec4bec608f7f8ccd26e9419999736ed7918b8d9900"
This basically is the binary representation of your operation in a hexadecimal format. Although, we also need the operation to be signed by the manager before continuing.
We’re going to use tezos-client
to do so, but we could also do it on our own using the secret key of the sender. As it’s easier and a little bit less technical, we’re going to do it with tezos-client
for this article (tezos-client
already knows the secret key).
First, save the binary representation you got earlier, without quotes, in a file savedOperation.hex
. Then, run the following command:
chainacc@tezos:~/tezos$ ./tezos-client sign bytes 0x03$(cat savedOperation.hex) for Alice
A little bit of explanation from OcamlPro:
The
0x03$(cat operation.hex)
is the concatenation of the0x03
prefix and the hexa content of theoperation.hex
, which is equivalent to0x03ce69...3c00
. The prefix is used (1) to indicate that the representation is hexadecimal (0x
), and (2) that it should start with03
, which is a watermark for operations in Tezos.
Note that Alice is the account I use as the sender, but it will probably be different for you. Adapt accordingly.
It gives me the following:
Signature: edsigtxQAGyXJAAS4eSX8RNvSpknW4ynfSdrTAZTEcedNyKxsgDHiqVjoNf9JDUByFJAUCDMcoZ2EEHNiEN7tqGX3ZMvfQWWuD9
Awesome! We have our signature. It is in a base68check
format, which is enough for the run_operation
and preapply
RPCs. However, it is not enough for the injection
RPC.
Let’s add our signature to our operation, as well as the protocol at the top:
[ { "protocol": "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd",
"branch": "BLnfTrJ6zwakFL6LbBzrD2tRSQuVJ2YymAnNHsYqW9FqEQLEFHT",
"contents": [
{ "kind": "transaction",
"source": "tz1VFgcWrcLvxpWcMvKnzFZpLjWxNT4wuosx",
"fee": "1",
"counter": "36904",
"gas_limit": "10500",
"storage_limit": "0",
"amount": "1",
"destination": "tz1hBT7dx9aaiZTEsSJUnB8fKQ76EswyTLgZ" }
],
"signature": "edsigtxQAGyXJAAS4eSX8RNvSpknW4ynfSdrTAZTEcedNyKxsgDHiqVjoNf9JDUByFJAUCDMcoZ2EEHNiEN7tqGX3ZMvfQWWuD9"
} ]
We can then pre-apply this operation. We simulate it again, but this time with signature check and with adjusted fees, gas limit, storage limit, etc… Let’s do it:
chainacc@tezos:~/tezos$ ./tezos-client rpc post /chains/main/blocks/head/helpers/preapply/operations
It should show you something like this:
[ "/definitions/next_operation" ]
As usual, simply delete that and paste your operation from above, with the real signature we made. After calling the RPC, it should return something like this:
[ { "contents":
[ { "kind": "transaction",
"source": "tz1VFgcWrcLvxpWcMvKnzFZpLjWxNT4wuosx", "fee": "1",
"counter": "36904", "gas_limit": "10500", "storage_limit": "0",
"amount": "1",
"destination": "tz1hBT7dx9aaiZTEsSJUnB8fKQ76EswyTLgZ",
"metadata":
{ "balance_updates":
[ { "kind": "contract",
"contract": "tz1VFgcWrcLvxpWcMvKnzFZpLjWxNT4wuosx",
"change": "-1" },
{ "kind": "freezer", "category": "fees",
"delegate": "tz1Ke2h7sDdakHJQh8WX4Z372du1KChsksyU",
"cycle": 223, "change": "1" } ],
"operation_result":
{ "status": "applied",
"balance_updates":
[ { "kind": "contract",
"contract": "tz1VFgcWrcLvxpWcMvKnzFZpLjWxNT4wuosx",
"change": "-1" },
{ "kind": "contract",
"contract": "tz1hBT7dx9aaiZTEsSJUnB8fKQ76EswyTLgZ",
"change": "1" } ], "consumed_gas": "10200" } } } ],
"signature":
"edsigtxQAGyXJAAS4eSX8RNvSpknW4ynfSdrTAZTEcedNyKxsgDHiqVjoNf9JDUByFJAUCDMcoZ2EEHNiEN7tqGX3ZMvfQWWuD9" } ]
Now, let’s get to the final step: the injection. Before that, we need the signed_operation_bytes
. It corresponds to operation_bytes
(that we saved in savedOperation.hex
) + the decoded signature.
So, let’s first decode the signature. There is a few ways of doing this. One would be to use Python and the base58check
module. Altough, for this post, we’re going to use an online website that does it for us. After typing “Decode base58” on Google, I found this website: https://incoherency.co.uk/base58/ which we can use to do so. Simply paste your signature (remember, mine is edsigtxQAGyXJAAS4eSX8RNvSpknW4ynfSdrTAZTEcedNyKxsgDHiqVjoNf9JDUByFJAUCDMcoZ2EEHNiEN7tqGX3ZMvfQWWuD9
) on the right box and click on “Decode”.
It gave me this:
09f5cd8612bbfac1a5ef087e3a1fefb4e577e14925c0afea5725b57f6275bcdec4f6193bead3cfd550e29984080ed66f8cf8f2cae9e106f5fb30704a6f21544aec9efee00b2391e6c8
However, there is a prefix and a suffix in this that we do not need. Indeed, current representation is (prefix)(decoded_signature)(suffix)
. We need to remove the prefix and suffix. Prefix is most of the times 09f5cd8612
(first 10 hexadecimal characters) and suffix is composed of the last 8 hex characters (in my case: 2391e6c8
). So let’s remove those and here is what it looks like for me:
bbfac1a5ef087e3a1fefb4e577e14925c0afea5725b57f6275bcdec4f6193bead3cfd550e29984080ed66f8cf8f2cae9e106f5fb30704a6f21544aec9efee00b
Above is my DECODED SIGNATURE. Now we can have our signed_operation_bytes
by adding our decoded_signature
next to our operation_bytes
(saved in savedOperation.hex
), it should like this:
8da5164e7a0ae00e8282e57f7950367a9cc2ef777271cf21ed89971d2218a34d08000069775863172a9ee22b0b72e9aa8d2fe8a7747dc901a8a002845200010000ec4bec608f7f8ccd26e9419999736ed7918b8d9900bbfac1a5ef087e3a1fefb4e577e14925c0afea5725b57f6275bcdec4f6193bead3cfd550e29984080ed66f8cf8f2cae9e106f5fb30704a6f21544aec9efee00b
I’ve separated the two parts by putting the decode_signature
in bold, so you can see it more clearly.
We can now inject the operation into the chain ;)
chainacc@tezos:~/tezos$ ./tezos-client rpc post /injection/operation?chain=main
It will display two double quotes ""
in which you can paste your long string, so it looks like this:
"8da5164e7a0ae00e8282e57f7950367a9cc2ef777271cf21ed89971d2218a34d08000069775863172a9ee22b0b72e9aa8d2fe8a7747dc901a8a002845200010000ec4bec608f7f8ccd26e9419999736ed7918b8d9900bbfac1a5ef087e3a1fefb4e577e14925c0afea5725b57f6275bcdec4f6193bead3cfd550e29984080ed66f8cf8f2cae9e106f5fb30704a6f21544aec9efee00b"
After running, it displays:
"opRG9VZ5duM7jtXhY2qbzNVpdeqzZbUEoGvBJ2EDrEF6VE4fnuY"
Which, obviously, will be different for you.
Congratulations! You just injected an operation in the block, and you can now check it on https://alphanet.tzscan.io/
And we’re done for this article! ;) Stay tuned for next ones!