Horizen Sidechain Tutorial: ZEN Transfer Between Chains
This article is the translation of the article written by Xavier Garreau, a French community member, for is website: https://mescryptos.fr/les-sidechains-horizen-transfert-de-zen/. This is the third article in this three-part series. Read the first article here.
Translated by Manon Boudoux
Horizen Sidechains: ZEN Transfer
In the third episode of this Horizen sidechain presentation, I will look at the transfers from the Horizen mainchain to the sidechain (forward transfer), within the sidechain, and finally, from the sidechain to the Horizen mainchain (backward transfer).
Forward Transfer: From Mainchain to Sidechain
I make sure that my mainchain is launched (zend), as well as the sidechain (SimpleApp).
How much ZEN do I have on the mainchain? I use the getbalance call via zen-cli to query zendoo.
$ zen-cli -regtest getbalance
936.49992873
I see I have 936.49992873ZEN on the mainchain.
How much do I have on the sidechain? I use the /wallet/balance API call. It doesn’t take a parameter. The headers are useless here but I might as well put them each time.
$ curl -X POST “http://127.0.0.1:9085/wallet/balance” -H “accept: application/json” -H “Content-Type: application/json”
{
“result” : {
“balance” : 40000000000
}
}
I see I have 400 ZEN on the sidechain. The amounts on the sidechain are expressed in satoshis (or in zennies, if we refer to the faucet vocabulary, which I personally find nicer). So the answer returned is 40000000000 zennies (1 ZEN is worth 100 million zennies).
So I decided to send 120 ZEN from the mainchain to the sidechain. Here, I’m going to use sc_send which requires the parameters for an address of the sidechain (my public key used to generate the sidechain), an amount in ZEN and finally the SCID of my sidechain (I generated it in the previous article, the values are obviously to be adapted to your case).
$ zen-cli -regtest sc_send “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8” 120 “d40188abb42d6ba6302464a847ace23e52b0c7edcf433cd17c10ca008b5e8783”
c8ad35d8309dd53e621987f659771624c8ddd9911f06c0de72b068646b75de54
I get the transaction ID back from the mainchain.
I check the content of this transaction.
$ zen-cli -regtest gettransaction “c8ad35d8309dd53e621987f659771624c8ddd9911f06c0de72b068646b75de54”
{
“amount”: -120.00000000,
“fee”: -0.00001776,
“confirmations”: 0,
“txid”: “c8ad35d8309dd53e621987f659771624c8ddd9911f06c0de72b068646b75de54”,
“walletconflicts”: [
],
“time”: 1595631280,
“timereceived”: 1595631280,
“vsc_ccout”: [
],
“vft_ccout”: [
{
“scid”: “d40188abb42d6ba6302464a847ace23e52b0c7edcf433cd17c10ca008b5e8783”,
“value”: 120.00000000,
“n”: 0,
“address”: “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8”
}
],
“vjoinsplit”: [
],
“details”: [
{
“sc address”: “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8”,
“category”: “crosschain”,
“amount”: -120.00000000,
“fee”: -0.00001776,
“size”: 1775
}
],
“hex”: “fcffffff0b13872704dd23473066a19c78048b3c37dba09fcb436b8d0df9adf9d958cb6283000000006b483045022100a5a8a842975473def66a0fa192240373a66e33b2e2da3edfe86ba27baa01d87e02201306acde4868503925336738fde3e43c7d14ba2f4cd4598397cc51fa61e9b23b012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffeffffff417e5c87ef54b029b559775b736d1057360a066d39dcf46d99e9071da780708e000000006a473044022070a7b6ca8874e9b6ebeb1b73911bdec61a783810ec857bf5f571d0d07fbcad47022052a2e78a58030a0f5a41e52e365b3f7aa627fa69712af4646849e9c8048959dd012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffeffffff6b1cd4b29330b2b1810a28d743c119c799b5eb47321628123cddc5b1ad6cce15000000006b4830450221009f595295d0de99523a57759838505948c967a449efe21035111b3f0f22acba5e022015fb91589d07e8af23ac56f9725616eab0478925f8a36b29c4c5339758fcd849012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffeffffff82c9d7e6bc52909c285ea49e3ca18130a1607b3dd262835b62b64b917bdac1f800000000694630430220304095af95cff7f50e30e18c180a2c72bd62739f222b87b3c7194cc55683a385021f46158dd07fc0243fefb068b652b55a7d5e95883de90fb035c9b2c763be5e67012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffeffffff8d541be5234e9cd65b098e9685e3c77d83bcd6f72393bcc96e4d225bcbf848e9000000006a47304402204d5fca29d3f894d1c29a4faaec9f5faa045e07018504a42c71b7cb6e1d90e554022064812ea834d70ae6584fc11270df1c0ce595a3ccb287e0993f25f0a5c4a45a43012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffeffffff90bf63244b198c95bc1e623847d9a9659419a3f105882b30a895c29511d1502e000000006b483045022100d7827d2e55c83fedaf36a46d0bd131c80dae6d90887fbb1248abdde0df05cb110220497f2e2d17e74b876b90fe96023e1b6ab11de679993258a012eb2e08512cfa5d012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffeffffffbaced09b6e4f111663973a169eaf2cb82aea2ce82d7a650db62e15e7ff5fd0b9000000006a47304402205027064038ad3ae82ce83ff0c3f06b99b615b5330fef2c7dfaf596d484478c1802202bfdfee6aff9853e9ec8f23c1ff7be5ef9836e52a3a092436bd0ccc010221bad012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffeffffffefa6bf4ceba0b9ce9627332617a0be8a8951fb27d733943f569a1536288f0d5e000000006b483045022100bbe769e530804738ac7dacb0b15957b3fc088860fab8a36464199e2ba84c8661022004ed2fcc01d429a8c6768a38572beb41fc6f051302a4e7809988268e6ef54d87012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffefffffff213e6aa61669b103d02d655208260f01a4efa0da6cde48d5b92680c98ce0d7c000000006b483045022100dabb5c1c5c0390ea1eb395211bd5c18e2bb498f7554eaa362a6b4b39cd1cbec40220302a421c1cd42ce1eca11f5e6e17a3c6251a5b1f90033ee543762bb341879da8012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffefffffffb9c8f800ac845117ad63b4f1ffa7833fd3b734b06403e7f8cb558c62e1ef478000000006a47304402201986137cd180cc3ea6a50a952f06e8690d72acd6e6d3e1d76a58f9d2a2d65034022045deae88f6e7bb073bd8695cacb5a88860db435e172ee5aec592df692760d9c7012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffefffffffe16573603229c0a7d7c16956fd6cdfce887b3e5393dacde8e0b79c4eb839c98000000006b483045022100d3757a56d32d6653b4508e576228099d56649777520d6d295357da80b6663c4c022035219e5c868e7e5f77fadaebb211467707ad3f9b14aab2b6081548a14117d7cb012103cbe54819c6acf93d0fe91719b1b510922a000529aa132edef81a51a1322e3e7ffeffffff013058a012000000003c76a9142954edbc7caadad684590bebfe6045ff2b39c8fd88ac20bb1acf2c1fc1228967a611c7db30632098f0c641855180b5fe23793b72eea50d00b40001007841cb02000000f8d6a2f8db1e7f3cbba1f94c96da8dc3873da20b9b46260a063fb01291ee3ba083875e8b00ca107cd13c43cfedc7b0523ee2ac47a8642430a66b2db4ab8801d4d3000000”
}
The amount, the recipient address, and the sidechain identifier are clearly indicated.
So, I validate this by adding the transaction to the next sidechain block that I mine.
$ zen-cli -regtest generate 1
[
“027024f228b813d175aec0ea22412a065ff65d197611703a1499a6ec11a903ea”
]
$ zen-cli -regtest getblock “027024f228b813d175aec0ea22412a065ff65d197611703a1499a6ec11a903ea”
{
“hash”: “027024f228b813d175aec0ea22412a065ff65d197611703a1499a6ec11a903ea”,
“confirmations”: 1,
“size”: 2140,
“height”: 222,
“version”: 3,
“merkleroot”: “5d4518fb1a4972d513f125657fae52e62ce841e5f0ed3bfbd78d08d16d35f103”,
“scTxsCommitment”: “f610e3f1b60e5769534b7a49f3101dd29b7d7389775d64560b617e2cca0b9ffe”,
“tx”: [
“7205cb1b8ae8bedd6298889d1873d23ee76b4e4dc3758deae6fb221057a2594c”,
“c8ad35d8309dd53e621987f659771624c8ddd9911f06c0de72b068646b75de54”
],
“cert”: [
],
“time”: 1595462378,
“nonce”: “0000f9f1905d2926a6aeec0e2bd234f67c8445e2b6be76c7fc615a6fceea0034”,
“solution”: “0e354cac11009db9f8180fded782af2bade325c4a4b9e2a6062b9454459c55675eb6d1de”,
“bits”: “200f0f02”,
“difficulty”: 1.000013172800801,
“chainwork”: “0000000000000000000000000000000000000000000000000000000000000ecf”,
“anchor”: “59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7”,
“valuePools”: [
{
“id”: “sprout”,
“monitored”: true,
“chainValue”: 0.00000000,
“chainValueZat”: 0,
“valueDelta”: 0.00000000,
“valueDeltaZat”: 0
}
],
“previousblockhash”: “04852dabaace286308c2ff9a8ba4968d2e3cf17b7079594b8dff756eb0e0f7f6”
}
$ zen-cli -regtest getbalance
825.24991099
The block is mined. I check the contents and I check my scale. It has been amputated by 120 ZEN but I have won a mining reward for my 7.5 block and the fees are added (0.0001776 ZEN). The fees are canceled because I pay them and then receive them as a mining reward. In short, I’m back on my feet.
The ZEN left the mainchain. So I go to check my scale on the sidechain:
$ curl -X POST “http://127.0.0.1:9085/wallet/balance” -H “accept: application/json” -H “Content-Type: application/json”
{
“result” : {
“balance” : 40000000000
}
}
This one hasn’t moved yet. Logically, as with the mainchain, an additional block must be generated for the modification to be taken into account.
I check the block generation parameters and the current state.
./block/forginginfo
With the call of the PLC.
$ curl -X POST “http://127.0.0.1:9085/block/forgingInfo” -H “accept: applicn” -H “Content-Type: application/json”
{
ation/jso “result” : {
“consensusSecondsInSlot” : 120,
“consensusSlotsInEpoch” : 720,
“bestEpochNumber” : 1,
“bestSlotNumber” : 720
}
We can place 720 blocks in an epoch. We are currently at slot 720 of epoch 1. So the next block will be block 1 of epoch 2.
I generate it through the API, by calling /block/generate and the parameters in JSON format (“epochNumber”:2, “slotNumber”:1) protecting the quotes.
$ curl -X POST “http://127.0.0.1:9085/block/generate” -H “accept: application/json” -H “Content-Type: application/json” -d “{“epochNumber”:2,”slotNumber”:1}”
{
“result”: {
“blockId”: “c0537b32906ada53582ba2f65c58fd9067d12024d4216a6c11cede30490dfd5f”
}
}
In return, I get the ID of the mined block that I can explore by calling /block/findById by passing the blockID as a parameter (always in JSON format).
$ curl -X POST “http://127.0.0.1:9085/block/findById” -H “accept: application/json” -H “Content-Type: application/json” -d “{“blockId”:”c0537b32906ada53582ba2f65c58fd9067d12024d4216a6c11cede30490dfd5f”}”
{
“result” : {
“blockHex” : “018bbc8219cab8b9b1f68513f89d3489bf950635a2ee90192237c9da6ca5fb9c8fbca3c1f10ba204e933f41dc86ca654a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f800000009502f9000a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f80ed74aa4afda5ffb358ba4906d0a5429f9840805e1fcc9ea71fca62afb5e97d779d0d2d3dd1bd9a3563166eff9d12b9ab9b6f11baf5639606689c72e16e2577ee338229e015697c8d174782b4caa04af9902eca2f3c384c6f558cf685b11010084a8436bbb18f7ccd039c249afa69f868c79939923ee3fc3ec437b998246db5b4907881702641ec6b41fdc6de644087713115fa2548121280fe8ac85fe31387aee6465767d8ba2189fab2ee8bf702beda6af018b4d68f890176bf2ab599e0000000800000000c3acce7d6d69a5434c6d4934ba19bfcaa07e9002638341d51b4cca039c077f7b03c0ea810446c20887d0b2e5cbaff30254b79e8102d1fb5f27471eedc897a53fa220d865d8a0b76a5f1acf582747953523c1fcb10dd44859fb1c422d31b2000064d16b94ddc62142d53e5634afc04633a8ffd5950b2596f8887219a0af4610819b452d4b8af5d9b3efaf65a8b9ce2a89599f3ff96e6383122d22974f7dec78964a72b37136fba57ef3ddc049f7702cf2dda921037bfa1bb8329f3fe87e020100007dc6c4e190e185761195b14e7ffbc94184357adfccfed1bd6279dbd32dc3e969440cbd2feffe87d7e88455e6ce157c32eda6cfde45c5f8901869cf9640a3643890100f5157452a4428b34464d6b3f3bb70cb56cc2822bedf97ac41a26cca0000dfb3656e9aee97158d5a48558edb4b01e8278442f83a5ef28f5d1983ecdffb0a93146dbc3604c79a988c58dfbb0758027007899b919cababcde21cd0c9e6ee366a65b22ba12466039e86d4ca7f84cf0ac61bbb46905e728004466421fd6e00000000000000000000000000000000000000000000000000000000000000000000eed2f0bae7e5055070673932300c4804041ea95ba78b76b0681ff4f7cdb45675000000000000000000000000000000000000000000000000000000000000000000800163cb74562c998def3a503c9490540a54269932e439b8e98ca9353d6d3eaf6ab972a289cdeb47d08296f1b092d6c760fc61fc833980c4501311f36411f5bb16030002cc02027024f228b813d175aec0ea22412a065ff65d197611703a1499a6ec11a903eaf801000000005f18d2ea0000007002da0101007841cb02000000f8d6a2f8db1e7f3cbba1f94c96da8dc3873da20b9b46260a063fb01291ee3ba083875e8b00ca107cd13c43cfedc7b0523ee2ac47a8642430a66b2db4ab8801d4c8ad35d8309dd53e621987f659771624c8ddd9911f06c0de72b068646b75de5400000000080000000000000002e20203000000f6f7e0b06e75ff8d4b5979707bf13c2e8d96a48b9affc2086328ceaaab2d850403f1356dd1088dd7fb3bedf0e541e82ce652ae7f6525f113d572491afb18455dfe9f0bca2c7e610b56645d7789737d9bd21d10f3497a4b5369570eb6f1e310f6ead2185f020f0f203400eace6f5a61fcc776beb6e245847cf634d22b0eecaea626295d90f1f90000240e354cac11009db9f8180fded782af2bade325c4a4b9e2a6062b9454459c55675eb6d1de00”,
“block” : {
“header” : {
“version” : 1,
“parentId” : “8bbc8219cab8b9b1f68513f89d3489bf950635a2ee90192237c9da6ca5fb9c8f”,
“timestamp” : 1595418846,
“forgerBox” : {
“nonce” : -1642701030306306476,
“id” : “7006b227eaa723e4afffb404383fd07166959275ec9c8f7e6665314c85ff1b03”,
“vrfPubKey” : {
“valid” : true,
“publicKey” : “0ed74aa4afda5ffb358ba4906d0a5429f9840805e1fcc9ea71fca62afb5e97d779d0d2d3dd1bd9a3563166eff9d12b9ab9b6f11baf5639606689c72e16e2577ee338229e015697c8d174782b4caa04af9902eca2f3c384c6f558cf685b11010084a8436bbb18f7ccd039c249afa69f868c79939923ee3fc3ec437b998246db5b4907881702641ec6b41fdc6de644087713115fa2548121280fe8ac85fe31387aee6465767d8ba2189fab2ee8bf702beda6af018b4d68f890176bf2ab599e000000”
},
“typeId” : 3,
“blockSignProposition” : {
“publicKey” : “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8”
},
“proposition” : {
“publicKey” : “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8”
},
“value” : 40000000000
},
“forgerBoxMerklePath” : “00000000”,
“vrfProof” : {
“vrfProof” : “c3acce7d6d69a5434c6d4934ba19bfcaa07e9002638341d51b4cca039c077f7b03c0ea810446c20887d0b2e5cbaff30254b79e8102d1fb5f27471eedc897a53fa220d865d8a0b76a5f1acf582747953523c1fcb10dd44859fb1c422d31b2000064d16b94ddc62142d53e5634afc04633a8ffd5950b2596f8887219a0af4610819b452d4b8af5d9b3efaf65a8b9ce2a89599f3ff96e6383122d22974f7dec78964a72b37136fba57ef3ddc049f7702cf2dda921037bfa1bb8329f3fe87e020100007dc6c4e190e185761195b14e7ffbc94184357adfccfed1bd6279dbd32dc3e969440cbd2feffe87d7e88455e6ce157c32eda6cfde45c5f8901869cf9640a3643890100f5157452a4428b34464d6b3f3bb70cb56cc2822bedf97ac41a26cca0000dfb3656e9aee97158d5a48558edb4b01e8278442f83a5ef28f5d1983ecdffb0a93146dbc3604c79a988c58dfbb0758027007899b919cababcde21cd0c9e6ee366a65b22ba12466039e86d4ca7f84cf0ac61bbb46905e728004466421fd6e0000”
},
“sidechainTransactionsMerkleRootHash” : “0000000000000000000000000000000000000000000000000000000000000000”,
“mainchainMerkleRootHash” : “eed2f0bae7e5055070673932300c4804041ea95ba78b76b0681ff4f7cdb45675”,
“ommersMerkleRootHash” : “0000000000000000000000000000000000000000000000000000000000000000”,
“ommersCumulativeScore” : 0,
“signature” : {
“signature” : “63cb74562c998def3a503c9490540a54269932e439b8e98ca9353d6d3eaf6ab972a289cdeb47d08296f1b092d6c760fc61fc833980c4501311f36411f5bb1603”,
“typeId” : 1
},
“id” : “c0537b32906ada53582ba2f65c58fd9067d12024d4216a6c11cede30490dfd5f”
},
“sidechainTransactions” : [ ],
“mainchainBlockReferencesData” : [ {
“headerHash” : “027024f228b813d175aec0ea22412a065ff65d197611703a1499a6ec11a903ea”,
“sidechainRelatedAggregatedTransaction” : {
“modifierTypeId” : 2,
“id” : “09b52d358c46a68cd43013591d39e34ecf606736f28d3a30441e3dd948a862c7”,
“timestamp” : 1595462378,
“newBoxes” : [ {
“nonce” : 5518227575416507090,
“id” : “5d7e803f4dbdcb24d0f4ebb1913f6e47b1d9ae00320509d470df7b90206ef764”,
“typeId” : 1,
“proposition” : {
“publicKey” : “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8”
},
“value” : 12000000000
} ],
“mc2scTransactionsMerkleRootHash” : “09b52d358c46a68cd43013591d39e34ecf606736f28d3a30441e3dd948a862c7”,
“fee” : 0,
“typeId” : 2,
“unlockers” : [ ]
},
“mProof” : [ ],
“proofOfNoData” : [ null, null ]
} ],
“mainchainHeaders” : [ {
“version” : 3,
“hashPrevBlock” : “04852dabaace286308c2ff9a8ba4968d2e3cf17b7079594b8dff756eb0e0f7f6”,
“hashMerkleRoot” : “5d4518fb1a4972d513f125657fae52e62ce841e5f0ed3bfbd78d08d16d35f103”,
“hashScTxsCommitment” : “f610e3f1b60e5769534b7a49f3101dd29b7d7389775d64560b617e2cca0b9ffe”,
“time” : 1595462378,
“bits” : 537857794,
“nonce” : “0000f9f1905d2926a6aeec0e2bd234f67c8445e2b6be76c7fc615a6fceea0034”,
“solution” : “0e354cac11009db9f8180fded782af2bade325c4a4b9e2a6062b9454459c55675eb6d1de”,
“hash” : “027024f228b813d175aec0ea22412a065ff65d197611703a1499a6ec11a903ea”
} ],
“ommers” : [ ],
“timestamp” : 1595418846,
“parentId” : “8bbc8219cab8b9b1f68513f89d3489bf950635a2ee90192237c9da6ca5fb9c8f”,
“id” : “c0537b32906ada53582ba2f65c58fd9067d12024d4216a6c11cede30490dfd5f”
}
}
}
You can find the 12000000000 destination at my address.
Let’s keep it simple. Did I receive the ZEN? Yes! I’ve got 520 ZEN now.
$ curl -X POST “http://127.0.0.1:9085/wallet/balance” -H “accept: application/json”
{
“result” : {
“balance” : 52000000000
}
}
Transfers Within the Sidechain
I did a transfer from the mainchain to the sidechain. Now I’ll quickly show you how to do a transfer inside the sidechain.
First, I need a destination address. I could do it on another node of the sidechain, but to make it simple, I’ll just create a new address on this one. The process remains the same. To create a new address on the sidechain, I use the API and its call /wallet/createPrivateKey25519, which returns a public key that we can transfer tokens to.
$ curl -X POST “http://127.0.0.1:9085/wallet/createPrivateKey25519” -H “accept: application/json”
{
“result” : {
“proposition” : {
“publicKey” : “ccc4f785ba27abd41fb4fc8c378f25024dce4007ad2ecc8e974f6e8aaf7a6021”
}
}
}
I have a new address now. I will send 100 ZEN to ccc4f785ba27abd41fb4fc8c378f25024dce4007ad2ecc8e974f6e8aaf7a6021.
The send is done by calling the API /transaction/sendCoinsToAddressesin. The parameters are an output array containing the recipient address publicKey and the amount in zennies, the value, and the fees fee. The attention fee is well out of the outputs array. For this example, we don’t pay any fees.
{
“outputs”: [
{
“publicKey”: “ccc4f785ba27abd41fb4fc8c378f25024dce4007ad2ecc8e974f6e8aaf7a6021”,
“value”: 10000000000
}
],
“fee”: 0
}
Here’s the full call, which returns a transaction ID:
$ curl -X POST “http://127.0.0.1:9085/transaction/sendCoinsToAddress” -H “accept: application/json” -H “Content-Type: application/json” -d “{“outputs”:[{“publicKey”:”ccc4f785ba27abd41fb4fc8c378f25024dce4007ad2ecc8e974f6e8aaf7a6021″,”value”:10000000000}],”fee”:0}”
{
“result”: {
“transactionId”: “56d0c09c0f1a0977ee44a27a1902d749c6e889e40b1e3547625652ed07509711”
}
}
I check pending transactions through the API by calling /transaction/allTransactions. This method takes a format parameter. If it is true, the transaction content is displayed. If it is false, the command returns an array of identifiers of the pending transactions.
$ curl -X POST “http://127.0.0.1:9085/transaction/allTransactions” -H “accept: application/json” -H “Content-Type: application/json” -d “{“format”:true}”
{
“result” : {
“transactions” : [ {
“modifierTypeId” : 2,
“id” : “56d0c09c0f1a0977ee44a27a1902d749c6e889e40b1e3547625652ed07509711”,
“fee” : 0,
“timestamp” : 1595635064137,
“newBoxes” : [ {
“nonce” : 9217280667005346328,
“id” : “a6ef1bf988117546920125e57c6e62d7d6e1d587e072cf7c3941a991dd5e391b”,
“typeId” : 1,
“proposition” : {
“publicKey” : “ccc4f785ba27abd41fb4fc8c378f25024dce4007ad2ecc8e974f6e8aaf7a6021”
},
“value” : 10000000000
}, {
“nonce” : 9099696201179751615,
“id” : “86af78e454b3e2725f3aec0f1036dd7368c81d8744bd4c5d521f8110b34fda0d”,
“typeId” : 1,
“proposition” : {
“publicKey” : “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8”
},
“value” : 2000000000
} ],
“unlockers” : [ {
“boxKey” : {
“signature” : “7bf9b0b240f6073c144db424094a1eefd77344913c8b7dd6bb035600e094477225608adf570b6722077448ad6956e94bbfad7a8ca7644b5316f9d20b187e250b”,
“typeId” : 1
},
“closedBoxId” : “5d7e803f4dbdcb24d0f4ebb1913f6e47b1d9ae00320509d470df7b90206ef764”
} ],
“typeId” : 3
} ]
}
}
Now to generate the next block (/block/generate). I check that there are no more pending transactions (transaction/allTransactions) and finally I check my “boxes” (/wallet/allBoxes).
Important Note: With 2 different nodes, it would be enough to check the balance on each one.
$ curl -X POST “http://127.0.0.1:9085/block/generate” -H “accept: application/json” -H “Content-Type: application/json” -d “{“epochNumber”:2,”slotNumber”:2}”
{
“result”: {
“blockId”: “8d2b3c5ce124296a001cf413e4ef4249fb57ca24ec721531aa2a13201f92d321”
}
}
$ curl -X POST “http://127.0.0.1:9085/transaction/allTransactions” -H “accept: application/json” -H “Content-Type: application/json” -d “{“format”:true}”
{
“result” : {
“transactions” : [ ]
}
}
$ curl -X POST “http://127.0.0.1:9085/wallet/allBoxes” -H “accept: application/json” -H “Content-Type: application/json”
{
“result” : {
“boxes” : [ {
“nonce” : -1642701030306306476,
“id” : “7006b227eaa723e4afffb404383fd07166959275ec9c8f7e6665314c85ff1b03”,
“vrfPubKey” : {
“valid” : true,
“publicKey” : “0ed74aa4afda5ffb358ba4906d0a5429f9840805e1fcc9ea71fca62afb5e97d779d0d2d3dd1bd9a3563166eff9d12b9ab9b6f11baf5639606689c72e16e2577ee338229e015697c8d174782b4caa04af9902eca2f3c384c6f558cf685b11010084a8436bbb18f7ccd039c249afa69f868c79939923ee3fc3ec437b998246db5b4907881702641ec6b41fdc6de644087713115fa2548121280fe8ac85fe31387aee6465767d8ba2189fab2ee8bf702beda6af018b4d68f890176bf2ab599e000000”
},
“typeId” : 3,
“blockSignProposition” : {
“publicKey” : “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8”
},
“proposition” : {
“publicKey” : “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8”
},
“value” : 40000000000
}, {
“nonce” : 9217280667005346328,
“id” : “a6ef1bf988117546920125e57c6e62d7d6e1d587e072cf7c3941a991dd5e391b”,
“typeId” : 1,
“proposition” : {
“publicKey” : “ccc4f785ba27abd41fb4fc8c378f25024dce4007ad2ecc8e974f6e8aaf7a6021”
},
“value” : 10000000000
}, {
“nonce” : 9099696201179751615,
“id” : “86af78e454b3e2725f3aec0f1036dd7368c81d8744bd4c5d521f8110b34fda0d”,
“typeId” : 1,
“proposition” : {
“publicKey” : “a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8”
},
“value” : 2000000000
} ]
}
}
As expected, the list of pending transactions is empty after the block generation and I am back to my 400 ZEN from the chain creation. 100 ZEN on ccc4f785ba27abd41fb4fc8c378f25024dce4007ad2ecc8e974f6e8aaf7a6021 and the remaining 20 ZEN on a03bee9112b03f060a26469b0ba23d87c38dda964cf9a1bb3c7f1edbf8a2d6f8.
Backward Transfer: From Sidechain to Mainchain
All the ZEN on the sidechain are not necessarily useful to me. I’m going to bring 84 of them back to the mainchain to make two secure nodes in the future.
There’s a method in the API that takes care of that for me.
/transaction/withdrawCoins.
The parameters are the same as for /transaction/sendCoinsToAddress, except that the destination address must be an address on the Horizen mainchain.
I’m going to create a dedicated address to receive the ZEN with the getnewaddress call thanks to zen-cli.
$ zen-cli -regtest getnewaddress
ztgGE5xq1cx71HnQpTgnoz8Jg3DoZMZnMjf
I’m making my withdrawal request at this new address. As a reminder, the amount in the calls to the sidechain are to be entered in zennies, not ZEN:
$ curl -X POST “http://127.0.0.1:9085/transaction/withdrawCoins” -H “accept: application/json” -H “Content-Type: application/json” -d “{“outputs”:[{“publicKey”:”ztgGE5xq1cx71HnQpTgnoz8Jg3DoZMZnMjf”,”value”:8400000000}],”fee”:0}”
{
“result” : {
“transactionId” : “98645fdf38e98e200a58306866c83ad9ff0742c6fc37114d27d42c097b13f0ff”
}
I get my transaction ID, and check that it’s on hold:
$ curl -X POST “http://127.0.0.1:9085/transaction/allTransactions” -H “accept: application/json” -H “Content-Type: application/json” -d “{“format”:false}”
{
“result” : {
“transactionIds” : [ “98645fdf38e98e200a58306866c83ad9ff0742c6fc37114d27d42c097b13f0ff” ]
}
}
I generate one block in the sidechain and one in the mainchain and check my balances:
$ curl -X POST “http://127.0.0.1:9085/block/generate” -H “accept: application/json” -d “{“epochNumber”:2,”slotNumber”:5}”
{
“result” : {
“blockId” : “2b68e8297213eab66048e6ae9576cead42081b4b24ed5e01bb369df54340678e”
}
}
$ zen-cli -regtest generate 1
[
“06ae9a87a00a780c7dd105d0cb89bbbce65961ad65a9148c31f84324839605e6”
]
$ zen-cli -regtest listaddressgroupings
[
[
[
“ztWvWCsBC18VY7RDWL1fMYnkgTm4vw1eMM8”,
3.12498224
],
[
“zte2BTFk6GQLy8Lwb4HdnB8P5HWVuWPwpf1”,
0.31242237
],
[
“ztf4LHNHXeXfDVVaBwhJd8WwKweHt2U8HTm”,
839.31250000
]
],
[
[
“ztgGE5xq1cx71HnQpTgnoz8Jg3DoZMZnMjf”,
0.00000000,
“”
]
]
]
$ curl -X POST “http://127.0.0.1:9085/wallet/balance” -H “accept: application/json”
{
“result” : {
“balance” : 43600000000
}
}
Darn … My address ztgGE5xqq1cx71HnQpTgnoz8Jg3DoZMZnMjf is always at 0, even though the amount was taken from my sidechain account.
Indeed, the backward transfer process is much more complex than the forward transfer. We have to respect epoch withdrawals. There are a number of blocks separating the account of withdrawals. Remember, this was the “withdrawalEpochLength” parameter: 10 that I used when I created the sidechain.
While monitoring the debug messages when generating the blocks, you may have noticed these messages for example:
[2-Hop-akka.actor.default-dispatcher-5] INFO com.horizen.certificatesubmitter.CertificateSubmitter – Can’t submit certificate, withdrawal epoch info = WithdrawalEpochInfo(0,2)
The numbers in brackets indicate the current epoch as well as the block number in the epoch. The transfer remains pending until block 1 of the epoch following the request.
Tip: From here to synchronize block creations between the mainchain and the test sidechain, I use a variable nbloc initialized to 5 and then used in this command which generates a mainchain block and a sidechain block, while incrementing the block counter. (As long as we stay below 720 blocks, it works).
zen-cli -regtest generate 1 ; nbloc=$((${nbloc}+1)) ; curl -X POST “http://127.0.0.1:9085/block/generate” -H “accept: application/json” -H “Content-Type: application/json” -d “{“epochNumber”:2,”slotNumber”:${nbloc}}”
WARNING: the epochNumber of the sidechain used in the block generation has nothing to do with the epoch of the WithdrawalEpochInfo.
After several generations of blocks, the following message appears, validating the attempt to transfer the sidechain to the mainchain (block n°1 of the next epoch):
[2-Hop-akka.actor.default-dispatcher-4] INFO com.horizen.certificatesubmitter.CertificateSubmitter – Can submit certificate, withdrawal epoch info = WithdrawalEpochInfo(1,1)
2-Hop-scorex.executionContext-582] INFO com.horizen.certificatesubmitter.CertificateSubmitter – Start generating proof for 1 withdrawal epoch number, with parameters: withdrawalRequests=(), endWithdrawalEpochBlockHash=099e56f2bc2800dfd49cf52b25e6b303e568ed1fe531387d74a188d54ecc0c26, prevEndWithdrawalEpochBlockHash=01f4b681be7f7af5fef263e20ab59e44d2e570b47be71e940a57ef96267f1533, signersThreshold=5.
It can take awhile and it does last a long time. Don’t lose patience, it’s counted in minutes on a basic VPS. Once the transfer container certificate is generated, it is transferred to the mainchain.
You get a debug message looking like this in the SimpleApp console, with the amount listed in ZEN in the second line.
INFO com.horizen.certificatesubmitter.CertificateSubmitter – Backward transfer certificate request was successfully created for epoch number 1, with proof […] with quality 7 try to send it to mainchain
[zen-cli, -regtest, send_certificate, […] [{“pubkeyhash”:”fb24e8fffcb006b507f5ba5b83b5ff6eaaecc88f”,”amount”:”84″}], 0.00001]
[2-Hop-scorex.executionContext-422] INFO com.horizen.certificatesubmitter.CertificateSubmitter – Backward transfer certificate response had been received. Cert hash = 8ab21a52e428510a1fee07b8161ac4d04c6c199a60713e8abc6730edcf2fe7b7
The mainchain’s answer is obtained in the next block (block 2, of the epoch following the transfer initiation). It is validated in the terminal by this message:
[2-Hop-akka.actor.default-dispatcher-273] INFO com.horizen.SidechainState – Block contains successfully verified backward transfer certificate for epoch %d
But the funds are still not on my address. Indeed, the transfer has yet to be validated. I have to wait for the beginning of the next epoch and the validation in return of the mainchain in block 2 of the next epoch. You have to continue to generate blocks until the 84 ZEN have arrived on your address:
$ zen-cli -regtest listaddressgroupings
[
[
[
“ztUJbTaAecFBy4r3xTAF6kPW8TPMFmGvHAV”,
0.31240876
],
[
“ztcyjVXDKicvdojoUBQRAkNUhvDtWhsSri9”,
1005.56250000
],
[
“ztdB5fiDNpvZD8nr4W69uiU8wRfB6qFvHcZ”,
3.12498225
]
],
[
[
“ztgGE5xq1cx71HnQpTgnoz8Jg3DoZMZnMjf”,
84.00000000,
“”
]
]
]
To summarize, in the case of synchronized blocks between the mainchain and the sidechain :
- Transfer request in epoch 0, block 3
- The sidechain informs the mainchain in epoch 1, block 1
- The upright arrives on the mainchain in epoch 2, block 2
Well, that’s it for the Horizen Sidechains presentation.
If you followed the file, you know now, from a blank VPS Debian or Ubuntu:
- Prepare your environment and install the prerequisites
- Compile the Mainchain and Sidechain nodes.
- Declare a sidechain on the mainchain
- Transfer from mainchain to sidechain
- Make transfers between sidechain addresses
- Transfer from sidechain to mainchain
There is still a lot to be said and done, but I hope this overview will help you test the waters of the Sidechains of Horizen.
Read the other articles in this series!
Links
Crypto Mania
August 18, 2020 @ 8:14 am
Learning for the failing in the sake of education for to learn one has to learn to lose . Lets grow perls as a perks when instead a fails of a victories. But how one to know, if other is good enough with fails presented as victories 😎