From 2a5d9155e839d20a047fc8a9b424a2ac6aff1c2a Mon Sep 17 00:00:00 2001 From: ACStoneCL Date: Tue, 13 Feb 2024 15:15:33 +0000 Subject: [PATCH] deploy: 1da3f0fb2472fe17aca579088fd634e786469a1a --- 404.html | 4 ++-- Demo/Demo/index.html | 4 ++-- Home/Home/index.html | 4 ++-- Playground/Playground/index.html | 4 ++-- assets/js/000be755.0ead002c.js | 1 + assets/js/000be755.41e2af7c.js | 1 - assets/js/007245cc.88ca756d.js | 1 + assets/js/007245cc.c09728ad.js | 1 - assets/js/0082beea.4b90d5ee.js | 1 + assets/js/0082beea.637680be.js | 1 - assets/js/03b7b368.2f8210cf.js | 1 + assets/js/03b7b368.e47e9670.js | 1 - assets/js/04253889.be4ad2e6.js | 1 - assets/js/04253889.efcb9c95.js | 1 + assets/js/043e2a1e.21c0d9db.js | 1 - assets/js/043e2a1e.3c76adb8.js | 1 + assets/js/04e20c99.1fca0c7b.js | 1 - assets/js/04e20c99.8d925a8d.js | 1 + assets/js/0501e40c.8c53aa8d.js | 1 - assets/js/0501e40c.9a467141.js | 1 + assets/js/08478d9e.22b0cd6e.js | 1 + assets/js/08478d9e.97b2823f.js | 1 - assets/js/08ab7f39.82a7d3bb.js | 1 - assets/js/08ab7f39.cda8d9b9.js | 1 + assets/js/09666a94.648e341f.js | 1 + assets/js/09666a94.cad4ab5c.js | 1 - assets/js/09f38b0b.1b642723.js | 1 - assets/js/09f38b0b.d87933eb.js | 1 + assets/js/0b24d6cd.c015e882.js | 1 - assets/js/0b24d6cd.d99584cd.js | 1 + assets/js/0b57706a.1b8230b0.js | 1 + assets/js/0b57706a.c6dbfeef.js | 1 - assets/js/0b7d75ea.0bcdbdf3.js | 1 - assets/js/{5bab3e27.97f36cb8.js => 0b7d75ea.7ebe5b4d.js} | 2 +- assets/js/0c853d41.4481642e.js | 1 + assets/js/0c853d41.ac8422df.js | 1 - assets/js/0f636bcb.181aaf5d.js | 1 + assets/js/0f636bcb.9bd1c5e0.js | 1 - assets/js/{1011242d.d5ca8fbc.js => 1011242d.b6dad235.js} | 2 +- assets/js/105579ae.947c9778.js | 1 - assets/js/105579ae.e985d36f.js | 1 + assets/js/{11199349.ad99a74a.js => 11199349.f70bed30.js} | 2 +- assets/js/11fbf07d.1244be9d.js | 1 + assets/js/11fbf07d.7996dc0e.js | 1 - assets/js/14c517c6.1da3d9fd.js | 1 - assets/js/{2289c829.3c70e4cd.js => 14c517c6.ade39fcb.js} | 2 +- assets/js/18ef2b36.1f2fff83.js | 1 + assets/js/18ef2b36.2efa4826.js | 1 - assets/js/19dcc625.35a709c4.js | 1 - assets/js/19dcc625.ad773672.js | 1 + assets/js/1afb40fe.b74d0572.js | 1 + assets/js/1afb40fe.fa9ecae2.js | 1 - assets/js/1b581919.189083f6.js | 1 + assets/js/1b581919.482f87ce.js | 1 - assets/js/1c22d3ad.8cf6a072.js | 1 - assets/js/1c22d3ad.a70828b6.js | 1 + assets/js/1c7bd663.c551adb9.js | 1 - assets/js/1c7bd663.d78af67e.js | 1 + assets/js/{3f68fb95.641fdb93.js => 1d7d8775.133e6378.js} | 2 +- assets/js/1d7d8775.9099df44.js | 1 - assets/js/1ddf2da6.08a6a6d6.js | 1 - assets/js/1ddf2da6.e21bb536.js | 1 + assets/js/{1ea27aee.ba6f0332.js => 1ea27aee.97ba152e.js} | 2 +- assets/js/1ef5bb94.7c281eb7.js | 1 + assets/js/1ef5bb94.ff73c783.js | 1 - assets/js/21770712.0cb59f88.js | 1 - assets/js/21770712.91865cf0.js | 1 + assets/js/2289c829.557d1d42.js | 1 + assets/js/22bbf3ab.43841de7.js | 1 + assets/js/22bbf3ab.9823a93f.js | 1 - assets/js/23dd64d8.3771aca1.js | 1 + assets/js/23dd64d8.c2310e27.js | 1 - assets/js/2747ce3a.aec386e3.js | 1 - assets/js/2747ce3a.f2ba58ef.js | 1 + assets/js/{27a494b1.33c693e7.js => 27a494b1.43fa8b10.js} | 2 +- assets/js/298ce658.4fb05371.js | 1 - assets/js/298ce658.9028325a.js | 1 + assets/js/2a99fafe.528c3d19.js | 1 - assets/js/2a99fafe.d2eb3836.js | 1 + assets/js/2bee511f.5f6d74f7.js | 1 - assets/js/2bee511f.7e5892e8.js | 1 + assets/js/{2c99ca03.fac42c78.js => 2c99ca03.bab7db00.js} | 2 +- assets/js/2d6bc0fd.a57abebc.js | 1 + assets/js/2d6bc0fd.f04f4469.js | 1 - assets/js/{2f093b46.0235d9de.js => 2f093b46.feda5c6e.js} | 2 +- assets/js/303f2c49.05dcabb8.js | 1 - assets/js/303f2c49.38a128da.js | 1 + assets/js/{35a30807.18a52ef5.js => 35a30807.332ce4d9.js} | 2 +- assets/js/3668a89e.a88e61a9.js | 1 + assets/js/3668a89e.bd3a0e18.js | 1 - assets/js/38517b34.07f96590.js | 1 + assets/js/38517b34.9f8aa3d4.js | 1 - assets/js/39b6f026.988988d0.js | 1 + assets/js/39b6f026.c0b2dde4.js | 1 - assets/js/3b05c439.ca8c75d2.js | 1 + assets/js/3b05c439.e61c2b37.js | 1 - assets/js/3e3fb99e.48b0b1fc.js | 1 - assets/js/3e3fb99e.913b371c.js | 1 + assets/js/3e7c0396.79843fa2.js | 1 + assets/js/3e7c0396.c615062c.js | 1 - assets/js/3f68fb95.f818d031.js | 1 + assets/js/3fe59759.b28dc0c6.js | 1 + assets/js/3fe59759.e776ea84.js | 1 - assets/js/401abd7a.f21f56e0.js | 1 + assets/js/401abd7a.f39345fb.js | 1 - assets/js/41afe816.5118bf09.js | 1 - assets/js/41afe816.519480b3.js | 1 + assets/js/4636fedf.b2a570c8.js | 1 + assets/js/4636fedf.f9d193a0.js | 1 - assets/js/463fc8b8.1fe31a4c.js | 1 + assets/js/463fc8b8.f7eb6dea.js | 1 - assets/js/46ca92b5.4dcf13f1.js | 1 + assets/js/46ca92b5.8ec9abc4.js | 1 - assets/js/{474a98da.3c5b93aa.js => 474a98da.d53e36e3.js} | 2 +- assets/js/48b3ccc5.01b83366.js | 1 - assets/js/48b3ccc5.a3a74fc2.js | 1 + assets/js/49c9a6f7.6f4000e2.js | 1 - assets/js/49c9a6f7.ff2f0b69.js | 1 + assets/js/{49d6b5ce.f0ad73af.js => 49d6b5ce.61d44850.js} | 2 +- assets/js/50ce38df.3d598a4b.js | 1 + assets/js/50ce38df.af0a1cb4.js | 1 - assets/js/516aae92.0aeaced8.js | 1 - assets/js/516aae92.4742a34c.js | 1 + assets/js/{51cfcb69.0ba1530f.js => 51cfcb69.eb2ceac7.js} | 2 +- assets/js/576aa6a1.c66f0c4f.js | 1 + assets/js/576aa6a1.cb1b71f3.js | 1 - assets/js/5879a27f.6e4bc834.js | 1 + assets/js/5879a27f.f5f63d72.js | 1 - assets/js/590178a5.1405868f.js | 1 + assets/js/590178a5.1efa8f67.js | 1 - assets/js/5bab3e27.68b11943.js | 1 + assets/js/5c51aefb.8eec2d6b.js | 1 - assets/js/5c51aefb.e516abdd.js | 1 + assets/js/5c5ab968.d4b1a01c.js | 1 - assets/js/5c5ab968.e5b57295.js | 1 + assets/js/5c6c4a57.56ceb458.js | 1 + assets/js/5c6c4a57.8779d977.js | 1 - assets/js/5e4971e3.a84bc526.js | 1 - assets/js/5e4971e3.afb2f7d6.js | 1 + assets/js/625db580.3767bcfa.js | 1 + assets/js/625db580.a2a8263e.js | 1 - assets/js/653a68bf.108fafc5.js | 1 + assets/js/653a68bf.213acf0d.js | 1 - assets/js/6a8ad950.54fc340f.js | 1 + assets/js/6a8ad950.c929fd73.js | 1 - assets/js/6a94474d.1c861f2c.js | 1 + assets/js/6a94474d.2d199c18.js | 1 - assets/js/6af03f69.4fa3e838.js | 1 - assets/js/6af03f69.a30d487c.js | 1 + assets/js/6b354c4b.b2e7f776.js | 1 + assets/js/6b354c4b.f5e8b6c6.js | 1 - assets/js/6eee94da.2730ca09.js | 1 + assets/js/6eee94da.a6e1f425.js | 1 - assets/js/6faae04c.3f306220.js | 1 + assets/js/6faae04c.f9e4da13.js | 1 - assets/js/6fc855ed.0d43a718.js | 1 - assets/js/6fc855ed.1d44d10a.js | 1 + assets/js/7157e7af.47128814.js | 1 - assets/js/7157e7af.8c7a2f2d.js | 1 + assets/js/{71c4e358.4e82d2d4.js => 71c4e358.6a76edb9.js} | 2 +- assets/js/71e073ea.c166d7d3.js | 1 - assets/js/71e073ea.e55ea1bc.js | 1 + assets/js/72301f79.00a85676.js | 1 - assets/js/72301f79.47a57eba.js | 1 + assets/js/725b7e74.58efa18c.js | 1 - assets/js/725b7e74.ef17b217.js | 1 + assets/js/73a8655d.bf27603b.js | 1 - assets/js/73a8655d.e03e7db6.js | 1 + assets/js/74bbf90e.6e0cee92.js | 1 - assets/js/74bbf90e.b7a90c5c.js | 1 + assets/js/74ff8362.809c279a.js | 1 - assets/js/74ff8362.b4646ff4.js | 1 + assets/js/{77f905e9.1847015d.js => 77f905e9.da79b5a8.js} | 2 +- assets/js/78143ba1.0d0f02a1.js | 1 + assets/js/78143ba1.4c3cf503.js | 1 - assets/js/796e8b5d.3841f31f.js | 1 - assets/js/796e8b5d.b35a5fde.js | 1 + assets/js/7adc1d42.2f67eb3e.js | 1 + assets/js/7adc1d42.a69324a3.js | 1 - assets/js/7c09a624.6d653f8c.js | 1 + assets/js/7c09a624.9fc3f656.js | 1 - assets/js/7d846783.42c2fcea.js | 1 - assets/js/7d846783.e1e79c9c.js | 1 + assets/js/7dc1264b.07eb0592.js | 1 + assets/js/7dc1264b.0823d86e.js | 1 - assets/js/80eab72b.0a8d9c72.js | 1 - assets/js/80eab72b.d3aee779.js | 1 + assets/js/{81637ed9.698309df.js => 81637ed9.637b21ae.js} | 2 +- assets/js/82798d79.77634979.js | 1 + assets/js/82798d79.da8c57f9.js | 1 - assets/js/84229592.7f659a23.js | 1 - assets/js/84229592.f0ce099a.js | 1 + assets/js/86a6526c.a1b6b5d6.js | 1 - assets/js/86a6526c.da72e427.js | 1 + assets/js/87ec732b.108a03b1.js | 1 - assets/js/87ec732b.439ed684.js | 1 + assets/js/{891ef04a.3663c192.js => 891ef04a.93307222.js} | 2 +- assets/js/8b4531bd.6251ff31.js | 1 + assets/js/8b4531bd.705829c2.js | 1 - assets/js/8c2276de.9d5e5770.js | 1 - assets/js/8c2276de.bff6feb3.js | 1 + assets/js/8f925d60.a0b95ce7.js | 1 - assets/js/8f925d60.a4d99eef.js | 1 + assets/js/92692c02.16df54f2.js | 1 + assets/js/92692c02.3a26c825.js | 1 - assets/js/956d710b.8469ddd6.js | 1 - assets/js/956d710b.ed13cd24.js | 1 + assets/js/963db545.25eb7fe6.js | 1 - assets/js/963db545.f7c0fcf5.js | 1 + assets/js/{9755a710.a7300428.js => 9755a710.b1d3d828.js} | 2 +- assets/js/9800de81.0851b4be.js | 1 + assets/js/9800de81.415f2370.js | 1 - assets/js/99756d1f.c3953897.js | 1 - assets/js/99756d1f.d2ce0dcd.js | 1 + assets/js/9ae83eb2.19122969.js | 1 + assets/js/9ae83eb2.4df50365.js | 1 - assets/js/{9b4bb048.4e65eeef.js => 9b4bb048.a6783ade.js} | 2 +- assets/js/9c5b046c.401fc3c4.js | 1 + assets/js/9c5b046c.47890976.js | 1 - assets/js/9df8dea5.0d854a46.js | 1 - assets/js/9df8dea5.26dae446.js | 1 + assets/js/{9ea0190f.eb6410e9.js => 9ea0190f.6bb53897.js} | 2 +- assets/js/9ebdaa52.133f9c6c.js | 1 + assets/js/9ebdaa52.36cf61be.js | 1 - assets/js/9ff556dd.61db54d6.js | 1 + assets/js/9ff556dd.aa8b8800.js | 1 - assets/js/a27f3afe.1685f38a.js | 1 + assets/js/a27f3afe.ab134fd8.js | 1 - assets/js/a2831d13.7c52010a.js | 1 - assets/js/a2831d13.c42a8c60.js | 1 + assets/js/a45056cf.1c475a77.js | 1 - assets/js/a45056cf.6482f7f0.js | 1 + assets/js/a4f33ee0.7707e13a.js | 1 + assets/js/a4f33ee0.d0c75230.js | 1 - assets/js/{a5ab1e83.ab421cb5.js => a5ab1e83.9ce6cacd.js} | 2 +- assets/js/a628b5be.14695ec9.js | 1 - assets/js/a628b5be.f98fca22.js | 1 + assets/js/a6d4c72e.8da8528a.js | 1 - assets/js/a6d4c72e.d9f9eacc.js | 1 + assets/js/a6f4e53a.273888e4.js | 1 - assets/js/a6f4e53a.8ba03a22.js | 1 + assets/js/a71eff7a.5141f7ca.js | 1 + assets/js/a71eff7a.c6cfce43.js | 1 - assets/js/a75f1f06.07acbe4a.js | 1 - assets/js/a75f1f06.86a51af4.js | 1 + assets/js/{a86c8182.798ff254.js => a86c8182.afaa631f.js} | 2 +- assets/js/ac7d7524.0f843ebe.js | 1 + assets/js/ac7d7524.fae12a2c.js | 1 - assets/js/ad025532.bdaa0f24.js | 1 + assets/js/ad025532.be21ba9f.js | 1 - assets/js/{ad774662.b207f44c.js => ad774662.367848aa.js} | 2 +- assets/js/ae44828e.7d30e0d8.js | 1 + assets/js/ae44828e.f3054247.js | 1 - assets/js/b0120e2d.d0f04cdc.js | 1 - assets/js/b0120e2d.d0f70710.js | 1 + assets/js/b161625a.6fb73e78.js | 1 - assets/js/b161625a.b3b21cd9.js | 1 + assets/js/b244b0e9.86cd11f8.js | 1 + assets/js/b244b0e9.efe68502.js | 1 - assets/js/b2eb857f.28d03f2e.js | 1 + assets/js/b2eb857f.ed3247eb.js | 1 - assets/js/b53d104f.b653a47f.js | 1 - assets/js/b53d104f.c11cd0e0.js | 1 + assets/js/b5850dcd.e1209bc5.js | 1 + assets/js/b5850dcd.f0924895.js | 1 - assets/js/b643e154.6b17dc67.js | 1 + assets/js/b643e154.6e1cc05f.js | 1 - assets/js/b74af8d8.7bb584bc.js | 1 - assets/js/b74af8d8.eed0a88b.js | 1 + assets/js/b9da5eb7.245a3758.js | 1 + assets/js/b9da5eb7.abad192b.js | 1 - assets/js/{bb301b4e.eaced0f6.js => bb301b4e.d4819f92.js} | 2 +- assets/js/bb9efa25.0ce98b96.js | 1 - assets/js/bb9efa25.78664f78.js | 1 + assets/js/{bbb7efd1.113b15d7.js => bbb7efd1.3ad5f031.js} | 2 +- assets/js/bc69d55a.7b421405.js | 1 + assets/js/bc69d55a.d418ff48.js | 1 - assets/js/bcd2a870.07e2751a.js | 1 + assets/js/bcd2a870.91f12037.js | 1 - assets/js/bd4f9aad.0d6ea978.js | 1 + assets/js/bd4f9aad.7bdf90a9.js | 1 - assets/js/{be8830cf.a2f80fe3.js => be8830cf.d854ceaf.js} | 2 +- assets/js/c2a85b60.39ed60e3.js | 1 + assets/js/c2a85b60.71642d54.js | 1 - assets/js/c305f31a.43db811a.js | 1 + assets/js/c305f31a.66b93372.js | 1 - assets/js/c5563497.290bd4c4.js | 1 - assets/js/c5563497.4e4e7f6c.js | 1 + assets/js/c7849882.3991c7ed.js | 1 + assets/js/c7849882.dab5ef44.js | 1 - assets/js/{c860f7f3.e0b57804.js => c860f7f3.7f2139bc.js} | 2 +- assets/js/ca0cd80e.71611a49.js | 1 + assets/js/ca0cd80e.b8bf9164.js | 1 - assets/js/cb836585.538140a7.js | 1 - assets/js/cb836585.69f934b6.js | 1 + assets/js/cc2b34bc.1d3f4cf7.js | 1 - assets/js/cc2b34bc.7e0061f9.js | 1 + assets/js/d044d178.48e3f2a4.js | 1 - assets/js/d044d178.cdb51ab3.js | 1 + assets/js/d2361378.8bc0121b.js | 1 - assets/js/d2361378.c78f5bed.js | 1 + assets/js/d45ad3b6.00942bb0.js | 1 - assets/js/d45ad3b6.8b90874a.js | 1 + assets/js/db0e1f9a.56848ffd.js | 1 - assets/js/db0e1f9a.c940cb9f.js | 1 + assets/js/dc0ad5f4.05dc6932.js | 1 + assets/js/dc0ad5f4.76607654.js | 1 - assets/js/dd0f338d.1add7a81.js | 1 + assets/js/dd0f338d.b2499a9b.js | 1 - assets/js/de7cb1a1.66494672.js | 1 - assets/js/de7cb1a1.9816e830.js | 1 + assets/js/e00654fa.08fe7795.js | 1 + assets/js/e00654fa.8a326d03.js | 1 - assets/js/e2fa8c79.5ab5ac7c.js | 1 - assets/js/e2fa8c79.c9a19ee9.js | 1 + assets/js/e2ffc27a.0a9a921a.js | 1 - assets/js/e2ffc27a.9220c9f9.js | 1 + assets/js/{e6ce8647.0c6000c5.js => e6ce8647.d7eb5eda.js} | 2 +- assets/js/{e7ae6dc5.b81c2649.js => e7ae6dc5.365d2fbc.js} | 2 +- assets/js/ea7bfaa8.ca694eb3.js | 1 - assets/js/ea7bfaa8.eafd168a.js | 1 + assets/js/ed14c6f0.8fee890c.js | 1 - assets/js/ed14c6f0.b35d8d71.js | 1 + assets/js/eda26e2d.5e2b7029.js | 1 + assets/js/eda26e2d.abd31ebf.js | 1 - assets/js/ef563e2a.16d112f1.js | 1 + assets/js/ef563e2a.d7592e9f.js | 1 - assets/js/efa2c7c1.1485b3ad.js | 1 + assets/js/efa2c7c1.a1e3c8eb.js | 1 - assets/js/{f12850af.88a1f821.js => f12850af.e9eb2c4f.js} | 2 +- assets/js/f14292ab.13ce6f4b.js | 1 - assets/js/f14292ab.381607da.js | 1 + assets/js/f5187c73.4407ea82.js | 1 - assets/js/f5187c73.cd338982.js | 1 + assets/js/f70cc67e.27d9ccca.js | 1 - assets/js/f70cc67e.b9f0f563.js | 1 + assets/js/{f8b123d7.1e1ecee7.js => f8b123d7.e93bf379.js} | 2 +- assets/js/f8f33652.61267410.js | 1 + assets/js/f8f33652.97f1dcda.js | 1 - assets/js/fa593e9e.0d6b2eb1.js | 1 + assets/js/fa593e9e.24fabd1c.js | 1 - assets/js/fcd43aac.93142dc7.js | 1 + assets/js/fcd43aac.c0cb9b58.js | 1 - assets/js/fec0de85.d09ce572.js | 1 - assets/js/fec0de85.df3d6a30.js | 1 + .../{runtime~main.be4395c0.js => runtime~main.4c0d1c15.js} | 2 +- concepts/accounts-and-keys/index.html | 6 +++--- concepts/callstack/index.html | 6 +++--- concepts/design/casper-design/index.html | 6 +++--- concepts/design/highway/index.html | 6 +++--- concepts/design/networking-protocol/index.html | 6 +++--- concepts/design/p2p/index.html | 6 +++--- .../design/reading-and-writing-to-the-blockchain/index.html | 6 +++--- concepts/dictionaries/index.html | 6 +++--- concepts/economics/concepts/index.html | 6 +++--- concepts/economics/consensus/index.html | 6 +++--- concepts/economics/delegation/index.html | 6 +++--- concepts/economics/gas-concepts/index.html | 6 +++--- concepts/global-state/index.html | 6 +++--- concepts/glossary/A/index.html | 6 +++--- concepts/glossary/B/index.html | 6 +++--- concepts/glossary/C/index.html | 6 +++--- concepts/glossary/D/index.html | 6 +++--- concepts/glossary/E/index.html | 6 +++--- concepts/glossary/F/index.html | 6 +++--- concepts/glossary/G/index.html | 6 +++--- concepts/glossary/H/index.html | 6 +++--- concepts/glossary/I/index.html | 6 +++--- concepts/glossary/J/index.html | 6 +++--- concepts/glossary/K/index.html | 6 +++--- concepts/glossary/L/index.html | 6 +++--- concepts/glossary/M/index.html | 6 +++--- concepts/glossary/N/index.html | 6 +++--- concepts/glossary/O/index.html | 6 +++--- concepts/glossary/P/index.html | 6 +++--- concepts/glossary/Q/index.html | 6 +++--- concepts/glossary/R/index.html | 6 +++--- concepts/glossary/S/index.html | 6 +++--- concepts/glossary/T/index.html | 6 +++--- concepts/glossary/U/index.html | 6 +++--- concepts/glossary/V/index.html | 6 +++--- concepts/glossary/W/index.html | 6 +++--- concepts/glossary/X/index.html | 6 +++--- concepts/glossary/Y/index.html | 6 +++--- concepts/glossary/Z/index.html | 6 +++--- concepts/hash-types/index.html | 6 +++--- concepts/index.html | 6 +++--- concepts/intro-to-dapps/index.html | 6 +++--- concepts/list-auth-keys/index.html | 6 +++--- concepts/serialization-standard/index.html | 6 +++--- concepts/smart-contracts/index.html | 6 +++--- counter-testnet/index.html | 6 +++--- counter/index.html | 6 +++--- deploy-and-deploy-lifecycle/index.html | 6 +++--- design/index.html | 6 +++--- developers/cli/calling-contracts/index.html | 6 +++--- developers/cli/delegate/index.html | 6 +++--- developers/cli/execution-error-codes/index.html | 6 +++--- developers/cli/index.html | 6 +++--- developers/cli/installing-contracts/index.html | 6 +++--- developers/cli/opcode-costs/index.html | 6 +++--- developers/cli/querying-global-state/index.html | 6 +++--- developers/cli/redelegate/index.html | 6 +++--- developers/cli/sending-deploys/index.html | 6 +++--- developers/cli/transfers/direct-token-transfer/index.html | 6 +++--- developers/cli/transfers/index.html | 6 +++--- .../cli/transfers/multisig-deploy-transfer/index.html | 6 +++--- developers/cli/transfers/verify-transfer/index.html | 6 +++--- developers/cli/undelegate/index.html | 6 +++--- developers/dapps/dapp/index.html | 6 +++--- developers/dapps/index.html | 6 +++--- developers/dapps/monitor-and-consume-events/index.html | 6 +++--- developers/dapps/nctl-test/index.html | 6 +++--- developers/dapps/prerequisites/index.html | 6 +++--- developers/dapps/sdk/client-library-usage/index.html | 6 +++--- developers/dapps/sdk/csharp-sdk/index.html | 6 +++--- developers/dapps/sdk/go-sdk/index.html | 6 +++--- developers/dapps/sdk/python-sdk/index.html | 6 +++--- developers/dapps/sdk/script-sdk/index.html | 6 +++--- developers/dapps/setup-nctl/index.html | 6 +++--- developers/dapps/signing-a-deploy/index.html | 6 +++--- developers/dapps/speculative-exec/index.html | 6 +++--- developers/dapps/technology-stack/index.html | 6 +++--- developers/dapps/template-frontend/index.html | 6 +++--- developers/dapps/uref-security/index.html | 6 +++--- developers/essential-crates/index.html | 6 +++--- developers/index.html | 6 +++--- developers/json-rpc/errors/index.html | 6 +++--- developers/json-rpc/guidance/index.html | 6 +++--- developers/json-rpc/index.html | 6 +++--- developers/json-rpc/json-rpc-informational/index.html | 6 +++--- developers/json-rpc/json-rpc-pos/index.html | 6 +++--- developers/json-rpc/json-rpc-transactional/index.html | 6 +++--- developers/json-rpc/minimal-compliance/index.html | 6 +++--- developers/json-rpc/types_chain/index.html | 6 +++--- developers/json-rpc/types_cl/index.html | 6 +++--- developers/prerequisites/index.html | 6 +++--- developers/writing-onchain-code/assembly-script/index.html | 6 +++--- developers/writing-onchain-code/best-practices/index.html | 6 +++--- .../writing-onchain-code/calling-contracts/index.html | 6 +++--- .../contract-hash-vs-package-hash/index.html | 6 +++--- .../writing-onchain-code/contract-vs-session/index.html | 6 +++--- developers/writing-onchain-code/getting-started/index.html | 6 +++--- developers/writing-onchain-code/simple-contract/index.html | 6 +++--- .../writing-onchain-code/testing-contracts/index.html | 6 +++--- .../writing-onchain-code/testing-session-code/index.html | 6 +++--- .../writing-onchain-code/upgrading-contracts/index.html | 6 +++--- .../writing-onchain-code/writing-session-code/index.html | 6 +++--- disclaimer/index.html | 6 +++--- economics/index.html | 6 +++--- glossary/index.html | 6 +++--- index.html | 6 +++--- operators/becoming-a-validator/bonding/index.html | 6 +++--- .../becoming-a-validator/inactive-vs-faulty/index.html | 6 +++--- operators/becoming-a-validator/index.html | 6 +++--- operators/becoming-a-validator/recovering/index.html | 6 +++--- operators/becoming-a-validator/unbonding/index.html | 6 +++--- operators/index.html | 6 +++--- operators/maintenance/archiving-and-restoring/index.html | 6 +++--- operators/maintenance/index.html | 6 +++--- operators/maintenance/moving-node/index.html | 6 +++--- operators/setup-network/chain-spec/index.html | 6 +++--- operators/setup-network/create-private/index.html | 6 +++--- operators/setup-network/genesis/index.html | 6 +++--- operators/setup-network/index.html | 6 +++--- .../setup-network/staging-files-for-new-network/index.html | 6 +++--- operators/setup/basic-node-configuration/index.html | 6 +++--- operators/setup/fast-sync/index.html | 6 +++--- operators/setup/hardware/index.html | 6 +++--- operators/setup/index.html | 6 +++--- operators/setup/install-node/index.html | 6 +++--- operators/setup/joining/index.html | 6 +++--- operators/setup/node-endpoints/index.html | 6 +++--- operators/setup/non-root-user/index.html | 6 +++--- operators/setup/open-files/index.html | 6 +++--- operators/setup/upgrade/index.html | 6 +++--- resources/advanced/list-auth-keys-tutorial/index.html | 6 +++--- resources/advanced/multi-sig/index.html | 6 +++--- resources/advanced/multi-sig/multi-sig-workflow/index.html | 6 +++--- resources/advanced/multi-sig/other-scenarios/index.html | 6 +++--- resources/beginner/counter-testnet/commands/index.html | 6 +++--- resources/beginner/counter-testnet/overview/index.html | 6 +++--- resources/beginner/counter-testnet/walkthrough/index.html | 6 +++--- resources/beginner/counter/commands/index.html | 6 +++--- resources/beginner/counter/overview/index.html | 6 +++--- resources/beginner/counter/walkthrough/index.html | 6 +++--- .../build-on-casper/casper-open-source-software/index.html | 6 +++--- resources/build-on-casper/introduction/index.html | 6 +++--- resources/index.html | 6 +++--- resources/moving-to-casper/index.html | 6 +++--- resources/quick-start/index.html | 6 +++--- resources/tokens/cep18/full-tutorial/index.html | 6 +++--- resources/tokens/cep18/query/index.html | 6 +++--- resources/tokens/cep18/quickstart-guide/index.html | 6 +++--- resources/tokens/cep18/tests/index.html | 6 +++--- resources/tokens/cep18/transfer/index.html | 6 +++--- resources/tokens/cep78/introduction/index.html | 6 +++--- resources/tokens/cep78/js-tutorial/index.html | 6 +++--- resources/tokens/cep78/modalities/index.html | 6 +++--- resources/tokens/cep78/reverse-lookup/index.html | 6 +++--- resources/tokens/index.html | 6 +++--- resources/tokens/using-casper-client/index.html | 6 +++--- resources/tutorials/advanced/cross-contract/index.html | 6 +++--- resources/tutorials/advanced/index.html | 6 +++--- resources/tutorials/advanced/list-cspr/index.html | 6 +++--- .../tutorials/advanced/return-values-tutorial/index.html | 6 +++--- resources/tutorials/advanced/storage-workflow/index.html | 6 +++--- .../advanced/transfer-token-to-contract/index.html | 6 +++--- resources/tutorials/advanced/two-party-multi-sig/index.html | 6 +++--- resources/tutorials/beginner/aws-node/index.html | 6 +++--- resources/tutorials/beginner/cep18/index.html | 6 +++--- .../tutorials/beginner/getting-started-tutorial/index.html | 6 +++--- resources/tutorials/beginner/index.html | 6 +++--- resources/tutorials/beginner/querying-network/index.html | 6 +++--- resources/tutorials/beginner/upgrade-contract/index.html | 6 +++--- runtime/index.html | 6 +++--- sdk/index.html | 6 +++--- search/index.html | 4 ++-- staking/index.html | 6 +++--- users/block-explorer/index.html | 6 +++--- users/csprlive/index.html | 6 +++--- users/delegate-ui/index.html | 6 +++--- users/funding-from-exchanges/index.html | 6 +++--- users/index.html | 6 +++--- users/ledger/index.html | 6 +++--- users/ledger/ledger-cspr-live/index.html | 6 +++--- users/ledger/ledger-live/index.html | 6 +++--- users/staking-ledger/index.html | 6 +++--- users/testnet-faucet/index.html | 6 +++--- users/token-transfer/index.html | 6 +++--- users/undelegate-ui/index.html | 6 +++--- workflow/ledger-setup/index.html | 6 +++--- writing-contracts/index.html | 6 +++--- 533 files changed, 755 insertions(+), 755 deletions(-) create mode 100644 assets/js/000be755.0ead002c.js delete mode 100644 assets/js/000be755.41e2af7c.js create mode 100644 assets/js/007245cc.88ca756d.js delete mode 100644 assets/js/007245cc.c09728ad.js create mode 100644 assets/js/0082beea.4b90d5ee.js delete mode 100644 assets/js/0082beea.637680be.js create mode 100644 assets/js/03b7b368.2f8210cf.js delete mode 100644 assets/js/03b7b368.e47e9670.js delete mode 100644 assets/js/04253889.be4ad2e6.js create mode 100644 assets/js/04253889.efcb9c95.js delete mode 100644 assets/js/043e2a1e.21c0d9db.js create mode 100644 assets/js/043e2a1e.3c76adb8.js delete mode 100644 assets/js/04e20c99.1fca0c7b.js create mode 100644 assets/js/04e20c99.8d925a8d.js delete mode 100644 assets/js/0501e40c.8c53aa8d.js create mode 100644 assets/js/0501e40c.9a467141.js create mode 100644 assets/js/08478d9e.22b0cd6e.js delete mode 100644 assets/js/08478d9e.97b2823f.js delete mode 100644 assets/js/08ab7f39.82a7d3bb.js create mode 100644 assets/js/08ab7f39.cda8d9b9.js create mode 100644 assets/js/09666a94.648e341f.js delete mode 100644 assets/js/09666a94.cad4ab5c.js delete mode 100644 assets/js/09f38b0b.1b642723.js create mode 100644 assets/js/09f38b0b.d87933eb.js delete mode 100644 assets/js/0b24d6cd.c015e882.js create mode 100644 assets/js/0b24d6cd.d99584cd.js create mode 100644 assets/js/0b57706a.1b8230b0.js delete mode 100644 assets/js/0b57706a.c6dbfeef.js delete mode 100644 assets/js/0b7d75ea.0bcdbdf3.js rename assets/js/{5bab3e27.97f36cb8.js => 0b7d75ea.7ebe5b4d.js} (79%) create mode 100644 assets/js/0c853d41.4481642e.js delete mode 100644 assets/js/0c853d41.ac8422df.js create mode 100644 assets/js/0f636bcb.181aaf5d.js delete mode 100644 assets/js/0f636bcb.9bd1c5e0.js rename assets/js/{1011242d.d5ca8fbc.js => 1011242d.b6dad235.js} (50%) delete mode 100644 assets/js/105579ae.947c9778.js create mode 100644 assets/js/105579ae.e985d36f.js rename assets/js/{11199349.ad99a74a.js => 11199349.f70bed30.js} (71%) create mode 100644 assets/js/11fbf07d.1244be9d.js delete mode 100644 assets/js/11fbf07d.7996dc0e.js delete mode 100644 assets/js/14c517c6.1da3d9fd.js rename assets/js/{2289c829.3c70e4cd.js => 14c517c6.ade39fcb.js} (79%) create mode 100644 assets/js/18ef2b36.1f2fff83.js delete mode 100644 assets/js/18ef2b36.2efa4826.js delete mode 100644 assets/js/19dcc625.35a709c4.js create mode 100644 assets/js/19dcc625.ad773672.js create mode 100644 assets/js/1afb40fe.b74d0572.js delete mode 100644 assets/js/1afb40fe.fa9ecae2.js create mode 100644 assets/js/1b581919.189083f6.js delete mode 100644 assets/js/1b581919.482f87ce.js delete mode 100644 assets/js/1c22d3ad.8cf6a072.js create mode 100644 assets/js/1c22d3ad.a70828b6.js delete mode 100644 assets/js/1c7bd663.c551adb9.js create mode 100644 assets/js/1c7bd663.d78af67e.js rename assets/js/{3f68fb95.641fdb93.js => 1d7d8775.133e6378.js} (60%) delete mode 100644 assets/js/1d7d8775.9099df44.js delete mode 100644 assets/js/1ddf2da6.08a6a6d6.js create mode 100644 assets/js/1ddf2da6.e21bb536.js rename assets/js/{1ea27aee.ba6f0332.js => 1ea27aee.97ba152e.js} (50%) create mode 100644 assets/js/1ef5bb94.7c281eb7.js delete mode 100644 assets/js/1ef5bb94.ff73c783.js delete mode 100644 assets/js/21770712.0cb59f88.js create mode 100644 assets/js/21770712.91865cf0.js create mode 100644 assets/js/2289c829.557d1d42.js create mode 100644 assets/js/22bbf3ab.43841de7.js delete mode 100644 assets/js/22bbf3ab.9823a93f.js create mode 100644 assets/js/23dd64d8.3771aca1.js delete mode 100644 assets/js/23dd64d8.c2310e27.js delete mode 100644 assets/js/2747ce3a.aec386e3.js create mode 100644 assets/js/2747ce3a.f2ba58ef.js rename assets/js/{27a494b1.33c693e7.js => 27a494b1.43fa8b10.js} (51%) delete mode 100644 assets/js/298ce658.4fb05371.js create mode 100644 assets/js/298ce658.9028325a.js delete mode 100644 assets/js/2a99fafe.528c3d19.js create mode 100644 assets/js/2a99fafe.d2eb3836.js delete mode 100644 assets/js/2bee511f.5f6d74f7.js create mode 100644 assets/js/2bee511f.7e5892e8.js rename assets/js/{2c99ca03.fac42c78.js => 2c99ca03.bab7db00.js} (60%) create mode 100644 assets/js/2d6bc0fd.a57abebc.js delete mode 100644 assets/js/2d6bc0fd.f04f4469.js rename assets/js/{2f093b46.0235d9de.js => 2f093b46.feda5c6e.js} (63%) delete mode 100644 assets/js/303f2c49.05dcabb8.js create mode 100644 assets/js/303f2c49.38a128da.js rename assets/js/{35a30807.18a52ef5.js => 35a30807.332ce4d9.js} (72%) create mode 100644 assets/js/3668a89e.a88e61a9.js delete mode 100644 assets/js/3668a89e.bd3a0e18.js create mode 100644 assets/js/38517b34.07f96590.js delete mode 100644 assets/js/38517b34.9f8aa3d4.js create mode 100644 assets/js/39b6f026.988988d0.js delete mode 100644 assets/js/39b6f026.c0b2dde4.js create mode 100644 assets/js/3b05c439.ca8c75d2.js delete mode 100644 assets/js/3b05c439.e61c2b37.js delete mode 100644 assets/js/3e3fb99e.48b0b1fc.js create mode 100644 assets/js/3e3fb99e.913b371c.js create mode 100644 assets/js/3e7c0396.79843fa2.js delete mode 100644 assets/js/3e7c0396.c615062c.js create mode 100644 assets/js/3f68fb95.f818d031.js create mode 100644 assets/js/3fe59759.b28dc0c6.js delete mode 100644 assets/js/3fe59759.e776ea84.js create mode 100644 assets/js/401abd7a.f21f56e0.js delete mode 100644 assets/js/401abd7a.f39345fb.js delete mode 100644 assets/js/41afe816.5118bf09.js create mode 100644 assets/js/41afe816.519480b3.js create mode 100644 assets/js/4636fedf.b2a570c8.js delete mode 100644 assets/js/4636fedf.f9d193a0.js create mode 100644 assets/js/463fc8b8.1fe31a4c.js delete mode 100644 assets/js/463fc8b8.f7eb6dea.js create mode 100644 assets/js/46ca92b5.4dcf13f1.js delete mode 100644 assets/js/46ca92b5.8ec9abc4.js rename assets/js/{474a98da.3c5b93aa.js => 474a98da.d53e36e3.js} (55%) delete mode 100644 assets/js/48b3ccc5.01b83366.js create mode 100644 assets/js/48b3ccc5.a3a74fc2.js delete mode 100644 assets/js/49c9a6f7.6f4000e2.js create mode 100644 assets/js/49c9a6f7.ff2f0b69.js rename assets/js/{49d6b5ce.f0ad73af.js => 49d6b5ce.61d44850.js} (50%) create mode 100644 assets/js/50ce38df.3d598a4b.js delete mode 100644 assets/js/50ce38df.af0a1cb4.js delete mode 100644 assets/js/516aae92.0aeaced8.js create mode 100644 assets/js/516aae92.4742a34c.js rename assets/js/{51cfcb69.0ba1530f.js => 51cfcb69.eb2ceac7.js} (51%) create mode 100644 assets/js/576aa6a1.c66f0c4f.js delete mode 100644 assets/js/576aa6a1.cb1b71f3.js create mode 100644 assets/js/5879a27f.6e4bc834.js delete mode 100644 assets/js/5879a27f.f5f63d72.js create mode 100644 assets/js/590178a5.1405868f.js delete mode 100644 assets/js/590178a5.1efa8f67.js create mode 100644 assets/js/5bab3e27.68b11943.js delete mode 100644 assets/js/5c51aefb.8eec2d6b.js create mode 100644 assets/js/5c51aefb.e516abdd.js delete mode 100644 assets/js/5c5ab968.d4b1a01c.js create mode 100644 assets/js/5c5ab968.e5b57295.js create mode 100644 assets/js/5c6c4a57.56ceb458.js delete mode 100644 assets/js/5c6c4a57.8779d977.js delete mode 100644 assets/js/5e4971e3.a84bc526.js create mode 100644 assets/js/5e4971e3.afb2f7d6.js create mode 100644 assets/js/625db580.3767bcfa.js delete mode 100644 assets/js/625db580.a2a8263e.js create mode 100644 assets/js/653a68bf.108fafc5.js delete mode 100644 assets/js/653a68bf.213acf0d.js create mode 100644 assets/js/6a8ad950.54fc340f.js delete mode 100644 assets/js/6a8ad950.c929fd73.js create mode 100644 assets/js/6a94474d.1c861f2c.js delete mode 100644 assets/js/6a94474d.2d199c18.js delete mode 100644 assets/js/6af03f69.4fa3e838.js create mode 100644 assets/js/6af03f69.a30d487c.js create mode 100644 assets/js/6b354c4b.b2e7f776.js delete mode 100644 assets/js/6b354c4b.f5e8b6c6.js create mode 100644 assets/js/6eee94da.2730ca09.js delete mode 100644 assets/js/6eee94da.a6e1f425.js create mode 100644 assets/js/6faae04c.3f306220.js delete mode 100644 assets/js/6faae04c.f9e4da13.js delete mode 100644 assets/js/6fc855ed.0d43a718.js create mode 100644 assets/js/6fc855ed.1d44d10a.js delete mode 100644 assets/js/7157e7af.47128814.js create mode 100644 assets/js/7157e7af.8c7a2f2d.js rename assets/js/{71c4e358.4e82d2d4.js => 71c4e358.6a76edb9.js} (52%) delete mode 100644 assets/js/71e073ea.c166d7d3.js create mode 100644 assets/js/71e073ea.e55ea1bc.js delete mode 100644 assets/js/72301f79.00a85676.js create mode 100644 assets/js/72301f79.47a57eba.js delete mode 100644 assets/js/725b7e74.58efa18c.js create mode 100644 assets/js/725b7e74.ef17b217.js delete mode 100644 assets/js/73a8655d.bf27603b.js create mode 100644 assets/js/73a8655d.e03e7db6.js delete mode 100644 assets/js/74bbf90e.6e0cee92.js create mode 100644 assets/js/74bbf90e.b7a90c5c.js delete mode 100644 assets/js/74ff8362.809c279a.js create mode 100644 assets/js/74ff8362.b4646ff4.js rename assets/js/{77f905e9.1847015d.js => 77f905e9.da79b5a8.js} (51%) create mode 100644 assets/js/78143ba1.0d0f02a1.js delete mode 100644 assets/js/78143ba1.4c3cf503.js delete mode 100644 assets/js/796e8b5d.3841f31f.js create mode 100644 assets/js/796e8b5d.b35a5fde.js create mode 100644 assets/js/7adc1d42.2f67eb3e.js delete mode 100644 assets/js/7adc1d42.a69324a3.js create mode 100644 assets/js/7c09a624.6d653f8c.js delete mode 100644 assets/js/7c09a624.9fc3f656.js delete mode 100644 assets/js/7d846783.42c2fcea.js create mode 100644 assets/js/7d846783.e1e79c9c.js create mode 100644 assets/js/7dc1264b.07eb0592.js delete mode 100644 assets/js/7dc1264b.0823d86e.js delete mode 100644 assets/js/80eab72b.0a8d9c72.js create mode 100644 assets/js/80eab72b.d3aee779.js rename assets/js/{81637ed9.698309df.js => 81637ed9.637b21ae.js} (59%) create mode 100644 assets/js/82798d79.77634979.js delete mode 100644 assets/js/82798d79.da8c57f9.js delete mode 100644 assets/js/84229592.7f659a23.js create mode 100644 assets/js/84229592.f0ce099a.js delete mode 100644 assets/js/86a6526c.a1b6b5d6.js create mode 100644 assets/js/86a6526c.da72e427.js delete mode 100644 assets/js/87ec732b.108a03b1.js create mode 100644 assets/js/87ec732b.439ed684.js rename assets/js/{891ef04a.3663c192.js => 891ef04a.93307222.js} (65%) create mode 100644 assets/js/8b4531bd.6251ff31.js delete mode 100644 assets/js/8b4531bd.705829c2.js delete mode 100644 assets/js/8c2276de.9d5e5770.js create mode 100644 assets/js/8c2276de.bff6feb3.js delete mode 100644 assets/js/8f925d60.a0b95ce7.js create mode 100644 assets/js/8f925d60.a4d99eef.js create mode 100644 assets/js/92692c02.16df54f2.js delete mode 100644 assets/js/92692c02.3a26c825.js delete mode 100644 assets/js/956d710b.8469ddd6.js create mode 100644 assets/js/956d710b.ed13cd24.js delete mode 100644 assets/js/963db545.25eb7fe6.js create mode 100644 assets/js/963db545.f7c0fcf5.js rename assets/js/{9755a710.a7300428.js => 9755a710.b1d3d828.js} (74%) create mode 100644 assets/js/9800de81.0851b4be.js delete mode 100644 assets/js/9800de81.415f2370.js delete mode 100644 assets/js/99756d1f.c3953897.js create mode 100644 assets/js/99756d1f.d2ce0dcd.js create mode 100644 assets/js/9ae83eb2.19122969.js delete mode 100644 assets/js/9ae83eb2.4df50365.js rename assets/js/{9b4bb048.4e65eeef.js => 9b4bb048.a6783ade.js} (71%) create mode 100644 assets/js/9c5b046c.401fc3c4.js delete mode 100644 assets/js/9c5b046c.47890976.js delete mode 100644 assets/js/9df8dea5.0d854a46.js create mode 100644 assets/js/9df8dea5.26dae446.js rename assets/js/{9ea0190f.eb6410e9.js => 9ea0190f.6bb53897.js} (52%) create mode 100644 assets/js/9ebdaa52.133f9c6c.js delete mode 100644 assets/js/9ebdaa52.36cf61be.js create mode 100644 assets/js/9ff556dd.61db54d6.js delete mode 100644 assets/js/9ff556dd.aa8b8800.js create mode 100644 assets/js/a27f3afe.1685f38a.js delete mode 100644 assets/js/a27f3afe.ab134fd8.js delete mode 100644 assets/js/a2831d13.7c52010a.js create mode 100644 assets/js/a2831d13.c42a8c60.js delete mode 100644 assets/js/a45056cf.1c475a77.js create mode 100644 assets/js/a45056cf.6482f7f0.js create mode 100644 assets/js/a4f33ee0.7707e13a.js delete mode 100644 assets/js/a4f33ee0.d0c75230.js rename assets/js/{a5ab1e83.ab421cb5.js => a5ab1e83.9ce6cacd.js} (57%) delete mode 100644 assets/js/a628b5be.14695ec9.js create mode 100644 assets/js/a628b5be.f98fca22.js delete mode 100644 assets/js/a6d4c72e.8da8528a.js create mode 100644 assets/js/a6d4c72e.d9f9eacc.js delete mode 100644 assets/js/a6f4e53a.273888e4.js create mode 100644 assets/js/a6f4e53a.8ba03a22.js create mode 100644 assets/js/a71eff7a.5141f7ca.js delete mode 100644 assets/js/a71eff7a.c6cfce43.js delete mode 100644 assets/js/a75f1f06.07acbe4a.js create mode 100644 assets/js/a75f1f06.86a51af4.js rename assets/js/{a86c8182.798ff254.js => a86c8182.afaa631f.js} (62%) create mode 100644 assets/js/ac7d7524.0f843ebe.js delete mode 100644 assets/js/ac7d7524.fae12a2c.js create mode 100644 assets/js/ad025532.bdaa0f24.js delete mode 100644 assets/js/ad025532.be21ba9f.js rename assets/js/{ad774662.b207f44c.js => ad774662.367848aa.js} (55%) create mode 100644 assets/js/ae44828e.7d30e0d8.js delete mode 100644 assets/js/ae44828e.f3054247.js delete mode 100644 assets/js/b0120e2d.d0f04cdc.js create mode 100644 assets/js/b0120e2d.d0f70710.js delete mode 100644 assets/js/b161625a.6fb73e78.js create mode 100644 assets/js/b161625a.b3b21cd9.js create mode 100644 assets/js/b244b0e9.86cd11f8.js delete mode 100644 assets/js/b244b0e9.efe68502.js create mode 100644 assets/js/b2eb857f.28d03f2e.js delete mode 100644 assets/js/b2eb857f.ed3247eb.js delete mode 100644 assets/js/b53d104f.b653a47f.js create mode 100644 assets/js/b53d104f.c11cd0e0.js create mode 100644 assets/js/b5850dcd.e1209bc5.js delete mode 100644 assets/js/b5850dcd.f0924895.js create mode 100644 assets/js/b643e154.6b17dc67.js delete mode 100644 assets/js/b643e154.6e1cc05f.js delete mode 100644 assets/js/b74af8d8.7bb584bc.js create mode 100644 assets/js/b74af8d8.eed0a88b.js create mode 100644 assets/js/b9da5eb7.245a3758.js delete mode 100644 assets/js/b9da5eb7.abad192b.js rename assets/js/{bb301b4e.eaced0f6.js => bb301b4e.d4819f92.js} (56%) delete mode 100644 assets/js/bb9efa25.0ce98b96.js create mode 100644 assets/js/bb9efa25.78664f78.js rename assets/js/{bbb7efd1.113b15d7.js => bbb7efd1.3ad5f031.js} (52%) create mode 100644 assets/js/bc69d55a.7b421405.js delete mode 100644 assets/js/bc69d55a.d418ff48.js create mode 100644 assets/js/bcd2a870.07e2751a.js delete mode 100644 assets/js/bcd2a870.91f12037.js create mode 100644 assets/js/bd4f9aad.0d6ea978.js delete mode 100644 assets/js/bd4f9aad.7bdf90a9.js rename assets/js/{be8830cf.a2f80fe3.js => be8830cf.d854ceaf.js} (53%) create mode 100644 assets/js/c2a85b60.39ed60e3.js delete mode 100644 assets/js/c2a85b60.71642d54.js create mode 100644 assets/js/c305f31a.43db811a.js delete mode 100644 assets/js/c305f31a.66b93372.js delete mode 100644 assets/js/c5563497.290bd4c4.js create mode 100644 assets/js/c5563497.4e4e7f6c.js create mode 100644 assets/js/c7849882.3991c7ed.js delete mode 100644 assets/js/c7849882.dab5ef44.js rename assets/js/{c860f7f3.e0b57804.js => c860f7f3.7f2139bc.js} (50%) create mode 100644 assets/js/ca0cd80e.71611a49.js delete mode 100644 assets/js/ca0cd80e.b8bf9164.js delete mode 100644 assets/js/cb836585.538140a7.js create mode 100644 assets/js/cb836585.69f934b6.js delete mode 100644 assets/js/cc2b34bc.1d3f4cf7.js create mode 100644 assets/js/cc2b34bc.7e0061f9.js delete mode 100644 assets/js/d044d178.48e3f2a4.js create mode 100644 assets/js/d044d178.cdb51ab3.js delete mode 100644 assets/js/d2361378.8bc0121b.js create mode 100644 assets/js/d2361378.c78f5bed.js delete mode 100644 assets/js/d45ad3b6.00942bb0.js create mode 100644 assets/js/d45ad3b6.8b90874a.js delete mode 100644 assets/js/db0e1f9a.56848ffd.js create mode 100644 assets/js/db0e1f9a.c940cb9f.js create mode 100644 assets/js/dc0ad5f4.05dc6932.js delete mode 100644 assets/js/dc0ad5f4.76607654.js create mode 100644 assets/js/dd0f338d.1add7a81.js delete mode 100644 assets/js/dd0f338d.b2499a9b.js delete mode 100644 assets/js/de7cb1a1.66494672.js create mode 100644 assets/js/de7cb1a1.9816e830.js create mode 100644 assets/js/e00654fa.08fe7795.js delete mode 100644 assets/js/e00654fa.8a326d03.js delete mode 100644 assets/js/e2fa8c79.5ab5ac7c.js create mode 100644 assets/js/e2fa8c79.c9a19ee9.js delete mode 100644 assets/js/e2ffc27a.0a9a921a.js create mode 100644 assets/js/e2ffc27a.9220c9f9.js rename assets/js/{e6ce8647.0c6000c5.js => e6ce8647.d7eb5eda.js} (59%) rename assets/js/{e7ae6dc5.b81c2649.js => e7ae6dc5.365d2fbc.js} (55%) delete mode 100644 assets/js/ea7bfaa8.ca694eb3.js create mode 100644 assets/js/ea7bfaa8.eafd168a.js delete mode 100644 assets/js/ed14c6f0.8fee890c.js create mode 100644 assets/js/ed14c6f0.b35d8d71.js create mode 100644 assets/js/eda26e2d.5e2b7029.js delete mode 100644 assets/js/eda26e2d.abd31ebf.js create mode 100644 assets/js/ef563e2a.16d112f1.js delete mode 100644 assets/js/ef563e2a.d7592e9f.js create mode 100644 assets/js/efa2c7c1.1485b3ad.js delete mode 100644 assets/js/efa2c7c1.a1e3c8eb.js rename assets/js/{f12850af.88a1f821.js => f12850af.e9eb2c4f.js} (63%) delete mode 100644 assets/js/f14292ab.13ce6f4b.js create mode 100644 assets/js/f14292ab.381607da.js delete mode 100644 assets/js/f5187c73.4407ea82.js create mode 100644 assets/js/f5187c73.cd338982.js delete mode 100644 assets/js/f70cc67e.27d9ccca.js create mode 100644 assets/js/f70cc67e.b9f0f563.js rename assets/js/{f8b123d7.1e1ecee7.js => f8b123d7.e93bf379.js} (55%) create mode 100644 assets/js/f8f33652.61267410.js delete mode 100644 assets/js/f8f33652.97f1dcda.js create mode 100644 assets/js/fa593e9e.0d6b2eb1.js delete mode 100644 assets/js/fa593e9e.24fabd1c.js create mode 100644 assets/js/fcd43aac.93142dc7.js delete mode 100644 assets/js/fcd43aac.c0cb9b58.js delete mode 100644 assets/js/fec0de85.d09ce572.js create mode 100644 assets/js/fec0de85.df3d6a30.js rename assets/js/{runtime~main.be4395c0.js => runtime~main.4c0d1c15.js} (61%) diff --git a/404.html b/404.html index 3058892dc4..103ed2714f 100644 --- a/404.html +++ b/404.html @@ -17,7 +17,7 @@ - + @@ -100,7 +100,7 @@
- + \ No newline at end of file diff --git a/Demo/Demo/index.html b/Demo/Demo/index.html index 568747f739..4650f15341 100644 --- a/Demo/Demo/index.html +++ b/Demo/Demo/index.html @@ -17,7 +17,7 @@ - + @@ -100,7 +100,7 @@
- + \ No newline at end of file diff --git a/Home/Home/index.html b/Home/Home/index.html index dae89fff9c..f12abc42db 100644 --- a/Home/Home/index.html +++ b/Home/Home/index.html @@ -17,7 +17,7 @@ - + @@ -100,7 +100,7 @@
- + \ No newline at end of file diff --git a/Playground/Playground/index.html b/Playground/Playground/index.html index 3103a4da6b..ba1376a92e 100644 --- a/Playground/Playground/index.html +++ b/Playground/Playground/index.html @@ -17,7 +17,7 @@ - + @@ -100,7 +100,7 @@
- + \ No newline at end of file diff --git a/assets/js/000be755.0ead002c.js b/assets/js/000be755.0ead002c.js new file mode 100644 index 0000000000..c5e8e1be15 --- /dev/null +++ b/assets/js/000be755.0ead002c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6688],{3905:function(e,t,r){r.d(t,{Zo:function(){return u},kt:function(){return f}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),c=l(r),m=a,f=c["".concat(s,".").concat(m)]||c[m]||d[m]||o;return r?n.createElement(f,i(i({ref:t},u),{},{components:r})):n.createElement(f,i({ref:t},u))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[c]="string"==typeof e?e:a,i[1]=p;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),l=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),c=l(r),m=a,f=c["".concat(s,".").concat(m)]||c[m]||d[m]||o;return r?n.createElement(f,i(i({ref:t},u),{},{components:r})):n.createElement(f,i({ref:t},u))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[c]="string"==typeof e?e:a,i[1]=p;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),u=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=u(e.components);return a.createElement(c.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),h=u(n),d=r,y=h["".concat(c,".").concat(d)]||h[d]||p[d]||o;return n?a.createElement(y,i(i({ref:t},l),{},{components:n})):a.createElement(y,i({ref:t},l))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[h]="string"==typeof e?e:r,i[1]=s;for(var u=2;u=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),u=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=u(e.components);return a.createElement(c.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),h=u(n),d=r,y=h["".concat(c,".").concat(d)]||h[d]||p[d]||o;return n?a.createElement(y,i(i({ref:t},l),{},{components:n})):a.createElement(y,i({ref:t},l))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[h]="string"==typeof e?e:r,i[1]=s;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=s(e,["components","mdxType","originalType","parentName"]),u=l(r),m=a,y=u["".concat(p,".").concat(m)]||u[m]||f[m]||o;return r?n.createElement(y,c(c({ref:t},i),{},{components:r})):n.createElement(y,c({ref:t},i))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:a,c[1]=s;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=s(e,["components","mdxType","originalType","parentName"]),u=l(r),m=a,y=u["".concat(p,".").concat(m)]||u[m]||f[m]||o;return r?n.createElement(y,c(c({ref:t},i),{},{components:r})):n.createElement(y,c({ref:t},i))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:a,c[1]=s;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),i=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=i(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},k=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=i(n),k=r,m=u["".concat(l,".").concat(k)]||u[k]||d[k]||o;return n?a.createElement(m,s(s({ref:t},p),{},{components:n})):a.createElement(m,s({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=k;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:r,s[1]=c;for(var i=2;icep18_test_contract Contract Package",id:"install-the-cep18_test_contract-contract-package",level:2},{value:"Next Steps",id:"next-steps",level:3}],d={toc:u},k="wrapper";function m(e){var t=e.components,n=(0,r.Z)(e,s);return(0,o.kt)(k,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"installing-and-interacting-with-a-cep-18-contract"},"Installing and Interacting with a CEP-18 Contract"),(0,o.kt)("p",null,"This quick start guide introduces you to the Casper client commands and Wasm files necessary to deploy a CEP-18 Casper Fungible Token contract to a ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live"},"Casper network"),"."),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"https://eips.ethereum.org/EIPS/eip-20#specification"},"Ethereum Request for Comment (ERC-20)")," standard defines a set of rules that dictate the total supply of tokens, how the tokens are transferred, how transactions are approved, and how token data is accessed. These fungible tokens are blockchain-based assets that have value and can be transferred or recorded."),(0,o.kt)("p",null,"To execute transactions on a Casper network (involving fungible tokens), you will need some CSPR tokens to pay for the transactions."),(0,o.kt)("p",null,"For greater detail into the creation and mechanics of the Casper fungible token contract, see the full ",(0,o.kt)("a",{parentName:"p",href:"/resources/tokens/cep18/full-tutorial"},"Casper Fungible Token Tutorial"),"."),(0,o.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,o.kt)("p",null,"Before using this guide, ensure you meet the following requirements:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Set up your machine as per the ",(0,o.kt)("a",{parentName:"li",href:"/developers/prerequisites/"},"prerequisites")),(0,o.kt)("li",{parentName:"ul"},"Use the ","[Casper command-line client]"),(0,o.kt)("li",{parentName:"ul"},"Get a valid ",(0,o.kt)("a",{parentName:"li",href:"https://cspr.live/tools/peers"},(0,o.kt)("inlineCode",{parentName:"a"},"node-address"))),(0,o.kt)("li",{parentName:"ul"},"Know how to deploy a ",(0,o.kt)("a",{parentName:"li",href:"/developers/cli/sending-deploys/"},"smart contract")," to a Casper network"),(0,o.kt)("li",{parentName:"ul"},"Hold enough CSPR tokens to pay for transactions")),(0,o.kt)("h1",{id:"setup"},"Setup"),(0,o.kt)("p",null,"Clone the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18"},"fungible token (CEP-18) contract repository")," and run the ",(0,o.kt)("inlineCode",{parentName:"p"},"make build-contract")," command. This will create the ",(0,o.kt)("inlineCode",{parentName:"p"},"cep18.wasm")," and the ",(0,o.kt)("inlineCode",{parentName:"p"},"cep18_test_contract.wasm"),". The token Wasm is the main contract. We will use the ",(0,o.kt)("inlineCode",{parentName:"p"},"cep18_test_contract")," Wasm to query the balances and allowances of the fungible token balances throughout this workflow."),(0,o.kt)("h2",{id:"install-the-main-fungible-token-contract"},"Install the Main Fungible Token Contract"),(0,o.kt)("p",null,"The following command will create a deploy containing the CEP-18 contract instance using your supplied arguments as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Name")," - The name of your CEP-18 token"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Symbol")," - The symbol used to refer to your CEP-18 token"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Total_supply")," - The total supply of the CEP-18 token to be minted"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Decimals")," - The number of spaces after the decimal. (As an example, a total supply of 1000000 with a ",(0,o.kt)("inlineCode",{parentName:"li"},"decimals")," setting of 3 would be 1,000.000 tokens)")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy -n http://: \\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-path ~/casper/demo/cep18.wasm \\\n--session-arg \"name:string='CEP18'\" \\\n--session-arg \"symbol:string='gris'\" \\\n--session-arg \"total_supply:u256='100'\" \\\n--session-arg \"decimals:u8='1'\" \\\n--payment-amount 150000000000\n")),(0,o.kt)("h2",{id:"install-the-cep18_test_contract-contract-package"},"Install the ",(0,o.kt)("inlineCode",{parentName:"h2"},"cep18_test_contract")," Contract Package"),(0,o.kt)("p",null,"The following command will install the CEP-18 helper contract that allows you to check balances and access approval features."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy -n http://: \\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-path ~/casper/demo/cep18_test_contract.wasm \\\n--payment-amount 50000000000\n")),(0,o.kt)("p",null,"At this point, the account that installed both the main contract and the helper contract will look like this."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "src": {\n "Account": {\n "_accountHash": "account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd",\n "namedKeys": [\n {\n "name": "cep18_test_contract",\n "key": "hash-999326ca8408dfd37da023eb6fd82f174151be64f83f9fb837632a0d69fd4c7e"\n },\n {\n "name": "cep18_token_contract",\n "key": "hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180"\n },\n ],\n "mainPurse": "uref-6c062525debdee18d5cad083ca530fcb65ef8741574fba4c97673f4ed00093f7-007",\n "associatedKeys": [\n {\n "accountHash": "account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd",\n "weight": 1\n }\n ],\n "actionThresholds": {\n "deployment": 1,\n "keyManagement": 1\n }\n }\n }\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},(0,o.kt)("em",{parentName:"strong"},"Note:"))),(0,o.kt)("blockquote",null,(0,o.kt)("ol",{parentName:"blockquote"},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"cep18_token_contract")," is the main contract, and is a stored contract, record its hash"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"cep18_test_call")," is a contract package which contains the utility contract required to read the balances and allowances of users within the fungible token state."))),(0,o.kt)("h3",{id:"next-steps"},"Next Steps"),(0,o.kt)("p",null,"In the following sections, the sample guide explains the querying of the contract package, token transfers, and approvals."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/query"},"Exploring the CEP18 Contracts")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/transfer"},"CEP-18 Token Transfers and Allowances")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/tests"},"Testing Framework for CEP-18"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/03b7b368.e47e9670.js b/assets/js/03b7b368.e47e9670.js deleted file mode 100644 index 90a425fdd5..0000000000 --- a/assets/js/03b7b368.e47e9670.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1598],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),i=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=i(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},k=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=i(n),k=r,m=u["".concat(l,".").concat(k)]||u[k]||d[k]||o;return n?a.createElement(m,s(s({ref:t},p),{},{components:n})):a.createElement(m,s({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=k;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:r,s[1]=c;for(var i=2;icep18_test_contract Contract Package",id:"install-the-cep18_test_contract-contract-package",level:2},{value:"Next Steps",id:"next-steps",level:3}],d={toc:u},k="wrapper";function m(e){var t=e.components,n=(0,r.Z)(e,s);return(0,o.kt)(k,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"installing-and-interacting-with-a-cep-18-contract"},"Installing and Interacting with a CEP-18 Contract"),(0,o.kt)("p",null,"This quick start guide introduces you to the Casper client commands and Wasm files necessary to deploy a CEP-18 Casper Fungible Token contract to a ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live"},"Casper network"),"."),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"https://eips.ethereum.org/EIPS/eip-20#specification"},"Ethereum Request for Comment (ERC-20)")," standard defines a set of rules that dictate the total supply of tokens, how the tokens are transferred, how transactions are approved, and how token data is accessed. These fungible tokens are blockchain-based assets that have value and can be transferred or recorded."),(0,o.kt)("p",null,"To execute transactions on a Casper network (involving fungible tokens), you will need some CSPR tokens to pay for the transactions."),(0,o.kt)("p",null,"For greater detail into the creation and mechanics of the Casper fungible token contract, see the full ",(0,o.kt)("a",{parentName:"p",href:"/resources/tokens/cep18/full-tutorial"},"Casper Fungible Token Tutorial"),"."),(0,o.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,o.kt)("p",null,"Before using this guide, ensure you meet the following requirements:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Set up your machine as per the ",(0,o.kt)("a",{parentName:"li",href:"/developers/prerequisites/"},"prerequisites")),(0,o.kt)("li",{parentName:"ul"},"Use the ","[Casper command-line client]"),(0,o.kt)("li",{parentName:"ul"},"Get a valid ",(0,o.kt)("a",{parentName:"li",href:"https://cspr.live/tools/peers"},(0,o.kt)("inlineCode",{parentName:"a"},"node-address"))),(0,o.kt)("li",{parentName:"ul"},"Know how to deploy a ",(0,o.kt)("a",{parentName:"li",href:"/developers/cli/sending-deploys/"},"smart contract")," to a Casper network"),(0,o.kt)("li",{parentName:"ul"},"Hold enough CSPR tokens to pay for transactions")),(0,o.kt)("h1",{id:"setup"},"Setup"),(0,o.kt)("p",null,"Clone the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18"},"fungible token (CEP-18) contract repository")," and run the ",(0,o.kt)("inlineCode",{parentName:"p"},"make build-contract")," command. This will create the ",(0,o.kt)("inlineCode",{parentName:"p"},"cep18.wasm")," and the ",(0,o.kt)("inlineCode",{parentName:"p"},"cep18_test_contract.wasm"),". The token Wasm is the main contract. We will use the ",(0,o.kt)("inlineCode",{parentName:"p"},"cep18_test_contract")," Wasm to query the balances and allowances of the fungible token balances throughout this workflow."),(0,o.kt)("h2",{id:"install-the-main-fungible-token-contract"},"Install the Main Fungible Token Contract"),(0,o.kt)("p",null,"The following command will create a deploy containing the CEP-18 contract instance using your supplied arguments as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Name")," - The name of your CEP-18 token"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Symbol")," - The symbol used to refer to your CEP-18 token"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Total_supply")," - The total supply of the CEP-18 token to be minted"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Decimals")," - The number of spaces after the decimal. (As an example, a total supply of 1000000 with a ",(0,o.kt)("inlineCode",{parentName:"li"},"decimals")," setting of 3 would be 1,000.000 tokens)")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy -n http://: \\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-path ~/casper/demo/cep18.wasm \\\n--session-arg \"name:string='CEP18'\" \\\n--session-arg \"symbol:string='gris'\" \\\n--session-arg \"total_supply:u256='100'\" \\\n--session-arg \"decimals:u8='1'\" \\\n--payment-amount 150000000000\n")),(0,o.kt)("h2",{id:"install-the-cep18_test_contract-contract-package"},"Install the ",(0,o.kt)("inlineCode",{parentName:"h2"},"cep18_test_contract")," Contract Package"),(0,o.kt)("p",null,"The following command will install the CEP-18 helper contract that allows you to check balances and access approval features."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy -n http://: \\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-path ~/casper/demo/cep18_test_contract.wasm \\\n--payment-amount 50000000000\n")),(0,o.kt)("p",null,"At this point, the account that installed both the main contract and the helper contract will look like this."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "src": {\n "Account": {\n "_accountHash": "account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd",\n "namedKeys": [\n {\n "name": "cep18_test_contract",\n "key": "hash-999326ca8408dfd37da023eb6fd82f174151be64f83f9fb837632a0d69fd4c7e"\n },\n {\n "name": "cep18_token_contract",\n "key": "hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180"\n },\n ],\n "mainPurse": "uref-6c062525debdee18d5cad083ca530fcb65ef8741574fba4c97673f4ed00093f7-007",\n "associatedKeys": [\n {\n "accountHash": "account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd",\n "weight": 1\n }\n ],\n "actionThresholds": {\n "deployment": 1,\n "keyManagement": 1\n }\n }\n }\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},(0,o.kt)("em",{parentName:"strong"},"Note:"))),(0,o.kt)("blockquote",null,(0,o.kt)("ol",{parentName:"blockquote"},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"cep18_token_contract")," is the main contract, and is a stored contract, record its hash"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"cep18_test_call")," is a contract package which contains the utility contract required to read the balances and allowances of users within the fungible token state."))),(0,o.kt)("h3",{id:"next-steps"},"Next Steps"),(0,o.kt)("p",null,"In the following sections, the sample guide explains the querying of the contract package, token transfers, and approvals."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/query"},"Exploring the CEP18 Contracts")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/transfer"},"CEP-18 Token Transfers and Allowances")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/tests"},"Testing Framework for CEP-18"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/04253889.be4ad2e6.js b/assets/js/04253889.be4ad2e6.js deleted file mode 100644 index b11e741715..0000000000 --- a/assets/js/04253889.be4ad2e6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9415],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=o.createContext({}),u=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=u(e.components);return o.createElement(i.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),h=a,m=c["".concat(i,".").concat(h)]||c[h]||d[h]||r;return n?o.createElement(m,s(s({ref:t},p),{},{components:n})):o.createElement(m,s({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,s=new Array(r);s[0]=h;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[c]="string"==typeof e?e:a,s[1]=l;for(var u=2;ucasper-client (Optional)",id:"enable-bash-auto-completion-for-casper-client-optional",level:2},{value:"Installing All Protocols",id:"installing-all-protocols",level:2},{value:"Validator Keys",id:"validator-keys",level:2},{value:"Getting a Trusted Hash",id:"getting-a-trusted-hash",level:2},{value:"Node Address",id:"node-address",level:3},{value:"Protocol Version",id:"protocol-version",level:3},{value:"Load trusted_hash in Config.toml of the Protocol Version",id:"load-trusted_hash-in-configtoml-of-the-protocol-version",level:3},{value:"Syncing to Genesis",id:"syncing-to-genesis",level:2},{value:"Starting the Node",id:"starting-the-node",level:2},{value:"Monitoring the Synchronization Process",id:"monitoring-the-synchronization-process",level:3},{value:"Monitoring the Running Node",id:"monitoring-the-running-node",level:3},{value:"A Note on Speculative Execution",id:"a-note-on-speculative-execution",level:2}],d={toc:c},h="wrapper";function m(e){var t=e.components,n=(0,a.Z)(e,s);return(0,r.kt)(h,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"installing-a-node"},"Installing a Node"),(0,r.kt)("p",null,"Ensure the requirements listed in the following sections are met before you start setting up the node on the network, either on Mainnet or Testnet."),(0,r.kt)("h2",{id:"network-requirements"},"Network Requirements"),(0,r.kt)("p",null,"The following ports are used by the node:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"35000 (required to be externally visible)"),(0,r.kt)("li",{parentName:"ul"},"7777 RPC endpoint for interaction with JSON-RPC API"),(0,r.kt)("li",{parentName:"ul"},"8888 REST endpoint for status and metrics (having this accessible allows your node to be part of network status)"),(0,r.kt)("li",{parentName:"ul"},"9999 SSE endpoint for event stream")),(0,r.kt)("p",null,"Of these ",(0,r.kt)("inlineCode",{parentName:"p"},"35000")," is the only port required to be open for your node to function, however, opening ",(0,r.kt)("inlineCode",{parentName:"p"},"8888")," will allow others to know general network health. For more details, see the additional information on ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/node-endpoints"},"Node Endpoints"),"."),(0,r.kt)("h2",{id:"operating-system-requirements"},"Operating System Requirements"),(0,r.kt)("p",null,"The recommended OS version is Ubuntu 20.04."),(0,r.kt)("h3",{id:"using-ubuntu-2204"},"Using Ubuntu 22.04"),(0,r.kt)("p",null,"Installing using Ubuntu 22.04 follows the same instructions as 20.04 with one exception:"),(0,r.kt)("p",null,"If you try to install packages, you will receive:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"casper-client : Depends: libssl1.1 (>= 1.1.0) but it is not installable\n")),(0,r.kt)("p",null,"This message is due to the default ",(0,r.kt)("inlineCode",{parentName:"p"},"openssl")," moving to 3.",(0,r.kt)("em",{parentName:"p"}," with Ubuntu 22.04. You need to install OpenSSL 1.")," for prior versions of Ubuntu to use the Casper binaries with the following command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"curl -f -JLO http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.20_amd64.deb\nsudo apt install ./libssl1.1_1.1.1f-1ubuntu2.19_amd64.deb\n")),(0,r.kt)("h2",{id:"required-number-of-open-files"},"Required Number of Open Files"),(0,r.kt)("p",null,"Before beginning, ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/open-files"},"update the maximum open files limit")," for your system. Specifically, update the node's ",(0,r.kt)("inlineCode",{parentName:"p"},"/etc/security/limits.conf")," file as described ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/open-files#updating-limits-conf"},"here"),", to ensure proper node operation."),(0,r.kt)("h2",{id:"required-clean-up"},"Required Clean Up"),(0,r.kt)("p",null,"If you were running a previous node on this box, this will clean up state. If packages are not installed, the ",(0,r.kt)("inlineCode",{parentName:"p"},"apt remove")," may give errors, but this is not a problem."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo systemctl stop casper-node-launcher.service\nsudo apt remove -y casper-client\nsudo apt remove -y casper-node\nsudo apt remove -y casper-node-launcher\nsudo rm /etc/casper/casper-node-launcher-state.toml\nsudo rm -rf /etc/casper/1_*\nsudo rm -rf /var/lib/casper/*\n")),(0,r.kt)("h2",{id:"required-packages"},"Required Packages"),(0,r.kt)("p",null,"The following commands will set up the Casper Labs repository for packages:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'echo "deb [arch=amd64] https://repo.casperlabs.io/releases focal main" | sudo tee -a /etc/apt/sources.list.d/casper.list\ncurl -O https://repo.casperlabs.io/casper-repo-pubkey.asc\nsudo apt-key add casper-repo-pubkey.asc\nsudo apt update\n')),(0,r.kt)("h2",{id:"required-tools"},"Required Tools"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install -y casper-client casper-node-launcher jq\n")),(0,r.kt)("h2",{id:"enable-bash-auto-completion-for-casper-client-optional"},"Enable Bash Auto-Completion for ",(0,r.kt)("inlineCode",{parentName:"h2"},"casper-client")," (Optional)"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo casper-client generate-completion\n")),(0,r.kt)("p",null,"It defaults to ",(0,r.kt)("inlineCode",{parentName:"p"},"bash")," but can be changed with the ",(0,r.kt)("inlineCode",{parentName:"p"},"--shell")," argument:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"--shell The type of shell to generate the completion script for [default: bash] [possible values:\n zsh, bash, fish, powershell, elvish]\n\nsudo casper-client generate-completion --shell powershell\n")),(0,r.kt)("p",null,"You need to source the new auto completion script or log out and log in again to activate it for the current shell:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"source /usr/share/bash-completion/completions/casper-client\n")),(0,r.kt)("p",null,"Now you can use ",(0,r.kt)("inlineCode",{parentName:"p"},"casper-client")," and press the ",(0,r.kt)("inlineCode",{parentName:"p"},"tab")," key to get auto completion for your commands."),(0,r.kt)("h2",{id:"installing-all-protocols"},"Installing All Protocols"),(0,r.kt)("p",null,"On ",(0,r.kt)("strong",{parentName:"p"},"Mainnet"),", run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols casper.conf\n")),(0,r.kt)("p",null,"On ",(0,r.kt)("strong",{parentName:"p"},"Testnet"),", run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols casper-test.conf\n")),(0,r.kt)("h2",{id:"validator-keys"},"Validator Keys"),(0,r.kt)("p",null,"If you do not have keys yet, you can create them using the following command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client keygen /etc/casper/validator_keys\n")),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/basic-node-configuration#create-fund-keys"},"Node Setup")," page."),(0,r.kt)("h2",{id:"getting-a-trusted-hash"},"Getting a Trusted Hash"),(0,r.kt)("p",null,"In the past, we have used a lower ",(0,r.kt)("inlineCode",{parentName:"p"},"trusted_hash"),". Connecting at the tip, we now use as high of a ",(0,r.kt)("inlineCode",{parentName:"p"},"trusted_hash")," as possible. Find out more about ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/fast-sync"},"Fast Sync"),"."),(0,r.kt)("h3",{id:"node-address"},"Node Address"),(0,r.kt)("p",null,"NODE_ADDR can be set to an IP of a trusted node, or to Casper Labs' public nodes"),(0,r.kt)("p",null,"You can find active peers at ",(0,r.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"https://cspr.live/tools/peers")," or use the following Casper Labs public nodes:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Testnet - NODE_ADDR=",(0,r.kt)("a",{parentName:"p",href:"https://rpc.testnet.casperlabs.io"},"https://rpc.testnet.casperlabs.io"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Mainnet - NODE_ADDR=",(0,r.kt)("a",{parentName:"p",href:"https://rpc.mainnet.casperlabs.io"},"https://rpc.mainnet.casperlabs.io")))),(0,r.kt)("h3",{id:"protocol-version"},"Protocol Version"),(0,r.kt)("p",null,"Protocol version should be set to the largest available protocol version you see in ",(0,r.kt)("inlineCode",{parentName:"p"},"ls /etc/casper"),". As of writing this, it was 1_5_2:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"PROTOCOL=1_5_2\n")),(0,r.kt)("h3",{id:"load-trusted_hash-in-configtoml-of-the-protocol-version"},"Load ",(0,r.kt)("inlineCode",{parentName:"h3"},"trusted_hash")," in Config.toml of the Protocol Version"),(0,r.kt)("p",null,"The following command uses the previously established NODE_ADDR and PROTOCOL to load the ",(0,r.kt)("inlineCode",{parentName:"p"},"trusted_hash"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NODE_ADDR=https://rpc.mainnet.casperlabs.io\nPROTOCOL=1_5_2\nsudo sed -i \"/trusted_hash =/c\\trusted_hash = '$(casper-client get-block --node-address $NODE_ADDR | jq -r .result.block.hash | tr -d '\\n')'\" /etc/casper/$PROTOCOL/config.toml\n")),(0,r.kt)("h2",{id:"syncing-to-genesis"},"Syncing to Genesis"),(0,r.kt)("p",null,"In the latest protocol version's ",(0,r.kt)("em",{parentName:"p"},"Config.toml"),", you will find the option ",(0,r.kt)("inlineCode",{parentName:"p"},"sync_to_genesis"),". By default, this value will be set to ",(0,r.kt)("inlineCode",{parentName:"p"},"true"),"."),(0,r.kt)("p",null,"If you are planning to run a validator node, it is better to not sync your node to genesis. This will increase node performance. In this case, the option should be changed to:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sync_to_genesis = false\n")),(0,r.kt)("p",null,"If you are using the node for historical data and want to query back to genesis, you can leave the default value in place."),(0,r.kt)("h2",{id:"starting-the-node"},"Starting the Node"),(0,r.kt)("p",null,"Start the node using the following commands:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo /etc/casper/node_util.py rotate_logs\nsudo /etc/casper/node_util.py start\n")),(0,r.kt)("h3",{id:"monitoring-the-synchronization-process"},"Monitoring the Synchronization Process"),(0,r.kt)("p",null,"The following command will display the node synchronization details:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"/etc/casper/node_util.py watch\n")),(0,r.kt)("p",null,"When you first run the watch command, you may see the message ",(0,r.kt)("inlineCode",{parentName:"p"},"RPC: Not Ready"),". Once the node is synchronized, the status will change to ",(0,r.kt)("inlineCode",{parentName:"p"},"RPC: Ready")," and a similar output:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"Last Block: 630151 (Era: 4153)\nPeer Count: 297\nUptime: 4days 6h 40m 18s 553ms\nBuild: 1.4.5-a7f6a648d-casper-mainnet\nKey: 0147b4cae09d64ab6acd02dd0868722be9a9bcc355c2fdff7c2c244cbfcd30f158\nNext Upgrade: None\n\nRPC: Ready\n\n\u25cf casper-node-launcher.service - Casper Node Launcher\n Loaded: loaded (/lib/systemd/system/casper-node-launcher.service; enabled; vendor preset: enabled)\n Active: active (running) since Wed 2022-03-16 21:08:50 UTC; 4 days ago\n Docs: https://docs.casper.network\n Main PID: 2934 (casper-node-lau)\n Tasks: 12 (limit: 4915)\n CGroup: /system.slice/casper-node-launcher.service\n \u251c\u2500 2934 /usr/bin/casper-node-launcher\n \u2514\u250016842 /var/lib/casper/bin/1_4_5/casper-node validator /etc/casper/1_4_5/config.toml\n")),(0,r.kt)("p",null,"The reactor state will be in CatchUp mode until it acquires the full tip state, at which point it will shift to KeepUp mode. If you left ",(0,r.kt)("inlineCode",{parentName:"p"},"sync_to_genesis")," as ",(0,r.kt)("inlineCode",{parentName:"p"},"true"),", it will begin syncing back history at this time."),(0,r.kt)("p",null,"Seeing available block range - Low: 0 High: 0 is normal until the fill tip is downloaded. You can see download progress with a look at metrics:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$ curl -s 127.0.0.1:8888/metrics | grep trie_or_chunk\n# HELP trie_or_chunk_fetch_total number of trie_or_chunk all fetch requests made\n# TYPE trie_or_chunk_fetch_total counter\ntrie_or_chunk_fetch_total 102647\n# HELP trie_or_chunk_found_in_storage number of fetch requests that found trie_or_chunk in local storage\n# TYPE trie_or_chunk_found_in_storage counter\ntrie_or_chunk_found_in_storage 0\n# HELP trie_or_chunk_found_on_peer number of fetch requests that fetched trie_or_chunk from peer\n# TYPE trie_or_chunk_found_on_peer counter\ntrie_or_chunk_found_on_peer 102263\n# HELP trie_or_chunk_timeouts number of trie_or_chunk fetch requests that timed out\n# TYPE trie_or_chunk_timeouts counter\ntrie_or_chunk_timeouts 0\n")),(0,r.kt)("p",null,"If the node is not showing active (running) status, it is either stopped or in the process of restarting."),(0,r.kt)("h3",{id:"monitoring-the-running-node"},"Monitoring the Running Node"),(0,r.kt)("p",null,"The community has created a few tools to monitor your node once it is running, such as:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Status.py: ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/RapidMark/casper-tools"},"https://github.com/RapidMark/casper-tools")),(0,r.kt)("li",{parentName:"ul"},"Grafana: ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/matsuro-hadouken/casper-tools"},"https://github.com/matsuro-hadouken/casper-tools"))),(0,r.kt)("h2",{id:"a-note-on-speculative-execution"},"A Note on Speculative Execution"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"speculative_exec_server")," defaults to off and can be enabled in your ",(0,r.kt)("em",{parentName:"p"},"Config.toml")," file."),(0,r.kt)("p",null,"While this is a useful tool, understand that it is also an attack vector for a node. The intent is for someone to run on their node as a tool. You ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("em",{parentName:"strong"},"should not"))," use this if you are an active validator, as requests into this port can block execution_engine processing for legitimate network traffic."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/04253889.efcb9c95.js b/assets/js/04253889.efcb9c95.js new file mode 100644 index 0000000000..d6f27fe084 --- /dev/null +++ b/assets/js/04253889.efcb9c95.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9415],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=o.createContext({}),u=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=u(e.components);return o.createElement(i.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=u(n),h=a,m=c["".concat(i,".").concat(h)]||c[h]||d[h]||r;return n?o.createElement(m,s(s({ref:t},p),{},{components:n})):o.createElement(m,s({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,s=new Array(r);s[0]=h;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[c]="string"==typeof e?e:a,s[1]=l;for(var u=2;ucasper-client (Optional)",id:"enable-bash-auto-completion-for-casper-client-optional",level:2},{value:"Installing All Protocols",id:"installing-all-protocols",level:2},{value:"Validator Keys",id:"validator-keys",level:2},{value:"Getting a Trusted Hash",id:"getting-a-trusted-hash",level:2},{value:"Node Address",id:"node-address",level:3},{value:"Protocol Version",id:"protocol-version",level:3},{value:"Load trusted_hash in Config.toml of the Protocol Version",id:"load-trusted_hash-in-configtoml-of-the-protocol-version",level:3},{value:"Syncing to Genesis",id:"syncing-to-genesis",level:2},{value:"Starting the Node",id:"starting-the-node",level:2},{value:"Monitoring the Synchronization Process",id:"monitoring-the-synchronization-process",level:3},{value:"Monitoring the Running Node",id:"monitoring-the-running-node",level:3},{value:"A Note on Speculative Execution",id:"a-note-on-speculative-execution",level:2}],d={toc:c},h="wrapper";function m(e){var t=e.components,n=(0,a.Z)(e,s);return(0,r.kt)(h,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"installing-a-node"},"Installing a Node"),(0,r.kt)("p",null,"Ensure the requirements listed in the following sections are met before you start setting up the node on the network, either on Mainnet or Testnet."),(0,r.kt)("h2",{id:"network-requirements"},"Network Requirements"),(0,r.kt)("p",null,"The following ports are used by the node:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"35000 (required to be externally visible)"),(0,r.kt)("li",{parentName:"ul"},"7777 RPC endpoint for interaction with JSON-RPC API"),(0,r.kt)("li",{parentName:"ul"},"8888 REST endpoint for status and metrics (having this accessible allows your node to be part of network status)"),(0,r.kt)("li",{parentName:"ul"},"9999 SSE endpoint for event stream")),(0,r.kt)("p",null,"Of these ",(0,r.kt)("inlineCode",{parentName:"p"},"35000")," is the only port required to be open for your node to function, however, opening ",(0,r.kt)("inlineCode",{parentName:"p"},"8888")," will allow others to know general network health. For more details, see the additional information on ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/node-endpoints"},"Node Endpoints"),"."),(0,r.kt)("h2",{id:"operating-system-requirements"},"Operating System Requirements"),(0,r.kt)("p",null,"The recommended OS version is Ubuntu 20.04."),(0,r.kt)("h3",{id:"using-ubuntu-2204"},"Using Ubuntu 22.04"),(0,r.kt)("p",null,"Installing using Ubuntu 22.04 follows the same instructions as 20.04 with one exception:"),(0,r.kt)("p",null,"If you try to install packages, you will receive:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"casper-client : Depends: libssl1.1 (>= 1.1.0) but it is not installable\n")),(0,r.kt)("p",null,"This message is due to the default ",(0,r.kt)("inlineCode",{parentName:"p"},"openssl")," moving to 3.",(0,r.kt)("em",{parentName:"p"}," with Ubuntu 22.04. You need to install OpenSSL 1.")," for prior versions of Ubuntu to use the Casper binaries with the following command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"curl -f -JLO http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.20_amd64.deb\nsudo apt install ./libssl1.1_1.1.1f-1ubuntu2.19_amd64.deb\n")),(0,r.kt)("h2",{id:"required-number-of-open-files"},"Required Number of Open Files"),(0,r.kt)("p",null,"Before beginning, ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/open-files"},"update the maximum open files limit")," for your system. Specifically, update the node's ",(0,r.kt)("inlineCode",{parentName:"p"},"/etc/security/limits.conf")," file as described ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/open-files#updating-limits-conf"},"here"),", to ensure proper node operation."),(0,r.kt)("h2",{id:"required-clean-up"},"Required Clean Up"),(0,r.kt)("p",null,"If you were running a previous node on this box, this will clean up state. If packages are not installed, the ",(0,r.kt)("inlineCode",{parentName:"p"},"apt remove")," may give errors, but this is not a problem."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo systemctl stop casper-node-launcher.service\nsudo apt remove -y casper-client\nsudo apt remove -y casper-node\nsudo apt remove -y casper-node-launcher\nsudo rm /etc/casper/casper-node-launcher-state.toml\nsudo rm -rf /etc/casper/1_*\nsudo rm -rf /var/lib/casper/*\n")),(0,r.kt)("h2",{id:"required-packages"},"Required Packages"),(0,r.kt)("p",null,"The following commands will set up the Casper Labs repository for packages:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'echo "deb [arch=amd64] https://repo.casperlabs.io/releases focal main" | sudo tee -a /etc/apt/sources.list.d/casper.list\ncurl -O https://repo.casperlabs.io/casper-repo-pubkey.asc\nsudo apt-key add casper-repo-pubkey.asc\nsudo apt update\n')),(0,r.kt)("h2",{id:"required-tools"},"Required Tools"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install -y casper-client casper-node-launcher jq\n")),(0,r.kt)("h2",{id:"enable-bash-auto-completion-for-casper-client-optional"},"Enable Bash Auto-Completion for ",(0,r.kt)("inlineCode",{parentName:"h2"},"casper-client")," (Optional)"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo casper-client generate-completion\n")),(0,r.kt)("p",null,"It defaults to ",(0,r.kt)("inlineCode",{parentName:"p"},"bash")," but can be changed with the ",(0,r.kt)("inlineCode",{parentName:"p"},"--shell")," argument:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"--shell The type of shell to generate the completion script for [default: bash] [possible values:\n zsh, bash, fish, powershell, elvish]\n\nsudo casper-client generate-completion --shell powershell\n")),(0,r.kt)("p",null,"You need to source the new auto completion script or log out and log in again to activate it for the current shell:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"source /usr/share/bash-completion/completions/casper-client\n")),(0,r.kt)("p",null,"Now you can use ",(0,r.kt)("inlineCode",{parentName:"p"},"casper-client")," and press the ",(0,r.kt)("inlineCode",{parentName:"p"},"tab")," key to get auto completion for your commands."),(0,r.kt)("h2",{id:"installing-all-protocols"},"Installing All Protocols"),(0,r.kt)("p",null,"On ",(0,r.kt)("strong",{parentName:"p"},"Mainnet"),", run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols casper.conf\n")),(0,r.kt)("p",null,"On ",(0,r.kt)("strong",{parentName:"p"},"Testnet"),", run:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols casper-test.conf\n")),(0,r.kt)("h2",{id:"validator-keys"},"Validator Keys"),(0,r.kt)("p",null,"If you do not have keys yet, you can create them using the following command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client keygen /etc/casper/validator_keys\n")),(0,r.kt)("p",null,"For more details, see the ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/basic-node-configuration#create-fund-keys"},"Node Setup")," page."),(0,r.kt)("h2",{id:"getting-a-trusted-hash"},"Getting a Trusted Hash"),(0,r.kt)("p",null,"In the past, we have used a lower ",(0,r.kt)("inlineCode",{parentName:"p"},"trusted_hash"),". Connecting at the tip, we now use as high of a ",(0,r.kt)("inlineCode",{parentName:"p"},"trusted_hash")," as possible. Find out more about ",(0,r.kt)("a",{parentName:"p",href:"/operators/setup/fast-sync"},"Fast Sync"),"."),(0,r.kt)("h3",{id:"node-address"},"Node Address"),(0,r.kt)("p",null,"NODE_ADDR can be set to an IP of a trusted node, or to Casper Labs' public nodes"),(0,r.kt)("p",null,"You can find active peers at ",(0,r.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"https://cspr.live/tools/peers")," or use the following Casper Labs public nodes:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Testnet - NODE_ADDR=",(0,r.kt)("a",{parentName:"p",href:"https://rpc.testnet.casperlabs.io"},"https://rpc.testnet.casperlabs.io"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Mainnet - NODE_ADDR=",(0,r.kt)("a",{parentName:"p",href:"https://rpc.mainnet.casperlabs.io"},"https://rpc.mainnet.casperlabs.io")))),(0,r.kt)("h3",{id:"protocol-version"},"Protocol Version"),(0,r.kt)("p",null,"Protocol version should be set to the largest available protocol version you see in ",(0,r.kt)("inlineCode",{parentName:"p"},"ls /etc/casper"),". As of writing this, it was 1_5_2:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"PROTOCOL=1_5_2\n")),(0,r.kt)("h3",{id:"load-trusted_hash-in-configtoml-of-the-protocol-version"},"Load ",(0,r.kt)("inlineCode",{parentName:"h3"},"trusted_hash")," in Config.toml of the Protocol Version"),(0,r.kt)("p",null,"The following command uses the previously established NODE_ADDR and PROTOCOL to load the ",(0,r.kt)("inlineCode",{parentName:"p"},"trusted_hash"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"NODE_ADDR=https://rpc.mainnet.casperlabs.io\nPROTOCOL=1_5_2\nsudo sed -i \"/trusted_hash =/c\\trusted_hash = '$(casper-client get-block --node-address $NODE_ADDR | jq -r .result.block.hash | tr -d '\\n')'\" /etc/casper/$PROTOCOL/config.toml\n")),(0,r.kt)("h2",{id:"syncing-to-genesis"},"Syncing to Genesis"),(0,r.kt)("p",null,"In the latest protocol version's ",(0,r.kt)("em",{parentName:"p"},"Config.toml"),", you will find the option ",(0,r.kt)("inlineCode",{parentName:"p"},"sync_to_genesis"),". By default, this value will be set to ",(0,r.kt)("inlineCode",{parentName:"p"},"true"),"."),(0,r.kt)("p",null,"If you are planning to run a validator node, it is better to not sync your node to genesis. This will increase node performance. In this case, the option should be changed to:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sync_to_genesis = false\n")),(0,r.kt)("p",null,"If you are using the node for historical data and want to query back to genesis, you can leave the default value in place."),(0,r.kt)("h2",{id:"starting-the-node"},"Starting the Node"),(0,r.kt)("p",null,"Start the node using the following commands:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo /etc/casper/node_util.py rotate_logs\nsudo /etc/casper/node_util.py start\n")),(0,r.kt)("h3",{id:"monitoring-the-synchronization-process"},"Monitoring the Synchronization Process"),(0,r.kt)("p",null,"The following command will display the node synchronization details:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"/etc/casper/node_util.py watch\n")),(0,r.kt)("p",null,"When you first run the watch command, you may see the message ",(0,r.kt)("inlineCode",{parentName:"p"},"RPC: Not Ready"),". Once the node is synchronized, the status will change to ",(0,r.kt)("inlineCode",{parentName:"p"},"RPC: Ready")," and a similar output:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"Last Block: 630151 (Era: 4153)\nPeer Count: 297\nUptime: 4days 6h 40m 18s 553ms\nBuild: 1.4.5-a7f6a648d-casper-mainnet\nKey: 0147b4cae09d64ab6acd02dd0868722be9a9bcc355c2fdff7c2c244cbfcd30f158\nNext Upgrade: None\n\nRPC: Ready\n\n\u25cf casper-node-launcher.service - Casper Node Launcher\n Loaded: loaded (/lib/systemd/system/casper-node-launcher.service; enabled; vendor preset: enabled)\n Active: active (running) since Wed 2022-03-16 21:08:50 UTC; 4 days ago\n Docs: https://docs.casper.network\n Main PID: 2934 (casper-node-lau)\n Tasks: 12 (limit: 4915)\n CGroup: /system.slice/casper-node-launcher.service\n \u251c\u2500 2934 /usr/bin/casper-node-launcher\n \u2514\u250016842 /var/lib/casper/bin/1_4_5/casper-node validator /etc/casper/1_4_5/config.toml\n")),(0,r.kt)("p",null,"The reactor state will be in CatchUp mode until it acquires the full tip state, at which point it will shift to KeepUp mode. If you left ",(0,r.kt)("inlineCode",{parentName:"p"},"sync_to_genesis")," as ",(0,r.kt)("inlineCode",{parentName:"p"},"true"),", it will begin syncing back history at this time."),(0,r.kt)("p",null,"Seeing available block range - Low: 0 High: 0 is normal until the fill tip is downloaded. You can see download progress with a look at metrics:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"$ curl -s 127.0.0.1:8888/metrics | grep trie_or_chunk\n# HELP trie_or_chunk_fetch_total number of trie_or_chunk all fetch requests made\n# TYPE trie_or_chunk_fetch_total counter\ntrie_or_chunk_fetch_total 102647\n# HELP trie_or_chunk_found_in_storage number of fetch requests that found trie_or_chunk in local storage\n# TYPE trie_or_chunk_found_in_storage counter\ntrie_or_chunk_found_in_storage 0\n# HELP trie_or_chunk_found_on_peer number of fetch requests that fetched trie_or_chunk from peer\n# TYPE trie_or_chunk_found_on_peer counter\ntrie_or_chunk_found_on_peer 102263\n# HELP trie_or_chunk_timeouts number of trie_or_chunk fetch requests that timed out\n# TYPE trie_or_chunk_timeouts counter\ntrie_or_chunk_timeouts 0\n")),(0,r.kt)("p",null,"If the node is not showing active (running) status, it is either stopped or in the process of restarting."),(0,r.kt)("h3",{id:"monitoring-the-running-node"},"Monitoring the Running Node"),(0,r.kt)("p",null,"The community has created a few tools to monitor your node once it is running, such as:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Status.py: ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/RapidMark/casper-tools"},"https://github.com/RapidMark/casper-tools")),(0,r.kt)("li",{parentName:"ul"},"Grafana: ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/matsuro-hadouken/casper-tools"},"https://github.com/matsuro-hadouken/casper-tools"))),(0,r.kt)("h2",{id:"a-note-on-speculative-execution"},"A Note on Speculative Execution"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"speculative_exec_server")," defaults to off and can be enabled in your ",(0,r.kt)("em",{parentName:"p"},"Config.toml")," file."),(0,r.kt)("p",null,"While this is a useful tool, understand that it is also an attack vector for a node. The intent is for someone to run on their node as a tool. You ",(0,r.kt)("strong",{parentName:"p"},(0,r.kt)("em",{parentName:"strong"},"should not"))," use this if you are an active validator, as requests into this port can block execution_engine processing for legitimate network traffic."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/043e2a1e.21c0d9db.js b/assets/js/043e2a1e.21c0d9db.js deleted file mode 100644 index b13b5a20ff..0000000000 --- a/assets/js/043e2a1e.21c0d9db.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8699],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return u}});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function p(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=o.createContext({}),c=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):p(p({},t),e)),n},l=function(e){var t=c(e.components);return o.createElement(i.Provider,{value:t},e.children)},d="mdxType",_={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},y=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=c(n),y=a,u=d["".concat(i,".").concat(y)]||d[y]||_[y]||r;return n?o.createElement(u,p(p({ref:t},l),{},{components:n})):o.createElement(u,p({ref:t},l))}));function u(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,p=new Array(r);p[0]=y;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[d]="string"==typeof e?e:a,p[1]=s;for(var c=2;c NodeClient:\n """Returns a pycspr client instance.\n """\n return NodeClient(NodeConnectionInfo(\n host=node_host,\n port_rpc=node_port_rpc,\n ))\n\n\n def _get_counter_parties(path_to_cp1_secret_key, type_of_cp1_secret_key,path_to_cp2_account_key) -> typing.Tuple[PrivateKey, PublicKey]:\n """Returns the 2 counter-parties participating in the transfer.\n """\n cp1 = pycspr.parse_private_key(\n path_to_cp1_secret_key,\n type_of_cp1_secret_key,\n )\n cp2 = pycspr.parse_public_key(\n path_to_cp2_account_key\n )\n\n return cp1, cp2\n\n\n def _get_deploy(chain_name, cp1: PrivateKey, cp2: PublicKey) -> Deploy:\n """Returns transfer deploy to be dispatched to a node.\n """\n # Set standard deploy parameters.\n deploy_params = pycspr.create_deploy_parameters(\n account = cp1,\n chain_name = chain_name\n )\n\n # Set deploy.\n deploy = pycspr.create_native_transfer(\n params = deploy_params,\n amount = int(2.5e9),\n target = cp2.account_hash,\n correlation_id = random.randint(1, 1e6)\n )\n\n return deploy\n\n\n # Entry point.\n if __name__ == \'__main__\':\n _main(node_host, node_port_rpc, path_to_cp1_secret_key, type_of_cp1_secret_key, path_to_cp2_account_key, chain_name)\n')),(0,r.kt)("h3",{id:"staking"},"Staking"),(0,r.kt)("p",null,"This example shows you how to define and stake funds with a validator."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'\n import os\n import pathlib\n\n import pycspr\n from pycspr.client import NodeClient\n from pycspr.client import NodeConnectionInfo\n from pycspr.crypto import KeyAlgorithm\n from pycspr.types import Deploy\n from pycspr.types import PrivateKey\n\n # path to cp1 secret key - defaults to NCTL user 1.\n path_to_validator_secret_key = pathlib.Path(os.getenv("NCTL")) / "assets" / "net-1" / "users" / "user-1" / "secret_key.pem"\n\n # type of cp1 secret key - defaults to ED25519.\n type_of_validator_secret_key = KeyAlgorithm.ED25519.name\n\n # path to session code wasm binary - defaults to NCTL bin/eco/add_bid.wasm.\n path_to_wasm = pathlib.Path(os.getenv("NCTL")) / "assets" / "net-1" / "bin" / "auction" / "add_bid.wasm"\n\n # amount to stake, i.e. bond, into the network.\n amount = int(2.5e9)\n\n # amount to charge delegators for service provision.\n delegation_rate = 2\n\n # name of target chain - defaults to NCTL chain.\n chain_name = "casper-net-1"\n\n # host address of target node - defaults to NCTL node 1.\n node_host = "localhost"\n\n # Node API JSON-RPC port - defaults to 11101 @ NCTL node 1.\n node_port_rpc = 11101\n\n def _main(node_host, node_port_rpc, path_to_validator_secret_key, type_of_validator_secret_key, chain_name, amount, delegation_rate, path_to_wasm):\n """Main entry point.\n :param args: Parsed command line arguments.\n """\n # Set node client.\n client: NodeClient = _get_client(node_host, node_port_rpc)\n\n # Set validator key.\n validator: PrivateKey = pycspr.parse_private_key(\n path_to_validator_secret_key,\n type_of_validator_secret_key,\n )\n\n # Set deploy.\n deploy: Deploy = _get_deploy(validator, chain_name, amount, delegation_rate, path_to_wasm)\n\n # Approve deploy.\n deploy.approve(validator)\n\n # Dispatch deploy to a node.\n client.deploys.send(deploy)\n\n print(f"Deploy dispatched to node [{node_host}]: {deploy.hash.hex()}")\n\n\n def _get_client(node_host, node_port_rpc) -> NodeClient:\n """Returns a pycspr client instance.\n """\n return NodeClient(NodeConnectionInfo(\n host = node_host,\n port_rpc = node_port_rpc,\n ))\n\n\n def _get_deploy(validator: PrivateKey, chain_name, amount, delegation_rate, path_to_wasm) -> Deploy:\n """Returns delegation deploy to be dispatched to a node.\n """\n # Set standard deploy parameters.\n deploy_params = pycspr.create_deploy_parameters(\n account = validator,\n chain_name = chain_name\n )\n\n # Set deploy.\n deploy = pycspr.create_validator_auction_bid(\n params = deploy_params,\n amount = amount,\n delegation_rate = delegation_rate,\n public_key = validator.as_public_key(),\n path_to_wasm = path_to_wasm\n )\n\n return deploy\n\n\n # Entry point.\n if __name__ == \'__main__\':\n _main(node_host, node_port_rpc, path_to_validator_secret_key, type_of_validator_secret_key, chain_name, amount, delegation_rate, path_to_wasm)\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/043e2a1e.3c76adb8.js b/assets/js/043e2a1e.3c76adb8.js new file mode 100644 index 0000000000..5d80f59c7d --- /dev/null +++ b/assets/js/043e2a1e.3c76adb8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8699],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return u}});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function p(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=o.createContext({}),c=function(e){var t=o.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):p(p({},t),e)),n},l=function(e){var t=c(e.components);return o.createElement(i.Provider,{value:t},e.children)},d="mdxType",_={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},y=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,i=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=c(n),y=a,u=d["".concat(i,".").concat(y)]||d[y]||_[y]||r;return n?o.createElement(u,p(p({ref:t},l),{},{components:n})):o.createElement(u,p({ref:t},l))}));function u(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,p=new Array(r);p[0]=y;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[d]="string"==typeof e?e:a,p[1]=s;for(var c=2;c NodeClient:\n """Returns a pycspr client instance.\n """\n return NodeClient(NodeConnectionInfo(\n host=node_host,\n port_rpc=node_port_rpc,\n ))\n\n\n def _get_counter_parties(path_to_cp1_secret_key, type_of_cp1_secret_key,path_to_cp2_account_key) -> typing.Tuple[PrivateKey, PublicKey]:\n """Returns the 2 counter-parties participating in the transfer.\n """\n cp1 = pycspr.parse_private_key(\n path_to_cp1_secret_key,\n type_of_cp1_secret_key,\n )\n cp2 = pycspr.parse_public_key(\n path_to_cp2_account_key\n )\n\n return cp1, cp2\n\n\n def _get_deploy(chain_name, cp1: PrivateKey, cp2: PublicKey) -> Deploy:\n """Returns transfer deploy to be dispatched to a node.\n """\n # Set standard deploy parameters.\n deploy_params = pycspr.create_deploy_parameters(\n account = cp1,\n chain_name = chain_name\n )\n\n # Set deploy.\n deploy = pycspr.create_native_transfer(\n params = deploy_params,\n amount = int(2.5e9),\n target = cp2.account_hash,\n correlation_id = random.randint(1, 1e6)\n )\n\n return deploy\n\n\n # Entry point.\n if __name__ == \'__main__\':\n _main(node_host, node_port_rpc, path_to_cp1_secret_key, type_of_cp1_secret_key, path_to_cp2_account_key, chain_name)\n')),(0,r.kt)("h3",{id:"staking"},"Staking"),(0,r.kt)("p",null,"This example shows you how to define and stake funds with a validator."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-python"},'\n import os\n import pathlib\n\n import pycspr\n from pycspr.client import NodeClient\n from pycspr.client import NodeConnectionInfo\n from pycspr.crypto import KeyAlgorithm\n from pycspr.types import Deploy\n from pycspr.types import PrivateKey\n\n # path to cp1 secret key - defaults to NCTL user 1.\n path_to_validator_secret_key = pathlib.Path(os.getenv("NCTL")) / "assets" / "net-1" / "users" / "user-1" / "secret_key.pem"\n\n # type of cp1 secret key - defaults to ED25519.\n type_of_validator_secret_key = KeyAlgorithm.ED25519.name\n\n # path to session code wasm binary - defaults to NCTL bin/eco/add_bid.wasm.\n path_to_wasm = pathlib.Path(os.getenv("NCTL")) / "assets" / "net-1" / "bin" / "auction" / "add_bid.wasm"\n\n # amount to stake, i.e. bond, into the network.\n amount = int(2.5e9)\n\n # amount to charge delegators for service provision.\n delegation_rate = 2\n\n # name of target chain - defaults to NCTL chain.\n chain_name = "casper-net-1"\n\n # host address of target node - defaults to NCTL node 1.\n node_host = "localhost"\n\n # Node API JSON-RPC port - defaults to 11101 @ NCTL node 1.\n node_port_rpc = 11101\n\n def _main(node_host, node_port_rpc, path_to_validator_secret_key, type_of_validator_secret_key, chain_name, amount, delegation_rate, path_to_wasm):\n """Main entry point.\n :param args: Parsed command line arguments.\n """\n # Set node client.\n client: NodeClient = _get_client(node_host, node_port_rpc)\n\n # Set validator key.\n validator: PrivateKey = pycspr.parse_private_key(\n path_to_validator_secret_key,\n type_of_validator_secret_key,\n )\n\n # Set deploy.\n deploy: Deploy = _get_deploy(validator, chain_name, amount, delegation_rate, path_to_wasm)\n\n # Approve deploy.\n deploy.approve(validator)\n\n # Dispatch deploy to a node.\n client.deploys.send(deploy)\n\n print(f"Deploy dispatched to node [{node_host}]: {deploy.hash.hex()}")\n\n\n def _get_client(node_host, node_port_rpc) -> NodeClient:\n """Returns a pycspr client instance.\n """\n return NodeClient(NodeConnectionInfo(\n host = node_host,\n port_rpc = node_port_rpc,\n ))\n\n\n def _get_deploy(validator: PrivateKey, chain_name, amount, delegation_rate, path_to_wasm) -> Deploy:\n """Returns delegation deploy to be dispatched to a node.\n """\n # Set standard deploy parameters.\n deploy_params = pycspr.create_deploy_parameters(\n account = validator,\n chain_name = chain_name\n )\n\n # Set deploy.\n deploy = pycspr.create_validator_auction_bid(\n params = deploy_params,\n amount = amount,\n delegation_rate = delegation_rate,\n public_key = validator.as_public_key(),\n path_to_wasm = path_to_wasm\n )\n\n return deploy\n\n\n # Entry point.\n if __name__ == \'__main__\':\n _main(node_host, node_port_rpc, path_to_validator_secret_key, type_of_validator_secret_key, chain_name, amount, delegation_rate, path_to_wasm)\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/04e20c99.1fca0c7b.js b/assets/js/04e20c99.1fca0c7b.js deleted file mode 100644 index d4bc4f7332..0000000000 --- a/assets/js/04e20c99.1fca0c7b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4455],{3905:function(e,t,r){r.d(t,{Zo:function(){return p},kt:function(){return f}});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=c(r),k=o,f=u["".concat(l,".").concat(k)]||u[k]||h[k]||a;return r?n.createElement(f,s(s({ref:t},p),{},{components:r})):n.createElement(f,s({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=k;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var c=2;c=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),c=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=c(r),k=o,f=u["".concat(l,".").concat(k)]||u[k]||h[k]||a;return r?n.createElement(f,s(s({ref:t},p),{},{components:r})):n.createElement(f,s({ref:t},p))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=k;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var c=2;c=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var p=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var i=n.createContext({}),d=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},s=function(e){var t=d(e.components);return n.createElement(i.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,p=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),c=d(r),m=a,f=c["".concat(i,".").concat(m)]||c[m]||u[m]||p;return r?n.createElement(f,o(o({ref:t},s),{},{components:r})):n.createElement(f,o({ref:t},s))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var p=r.length,o=new Array(p);o[0]=m;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var d=2;d=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var p=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var i=n.createContext({}),d=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},s=function(e){var t=d(e.components);return n.createElement(i.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,p=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),c=d(r),m=a,f=c["".concat(i,".").concat(m)]||c[m]||u[m]||p;return r?n.createElement(f,o(o({ref:t},s),{},{components:r})):n.createElement(f,o({ref:t},s))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var p=r.length,o=new Array(p);o[0]=m;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var d=2;d=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(a),h=i,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||r;return a?n.createElement(m,o(o({ref:t},p),{},{components:a})):n.createElement(m,o({ref:t},p))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var c=2;c> global_state.toml\n")),(0,r.kt)("p",null,"By using ",(0,r.kt)("inlineCode",{parentName:"p"},">>")," shell redirection you will always append contents to existing file without overwriting it. This is helpful when you need to chain multiple operations in a single upgrade."),(0,r.kt)("p",null,"Common options:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--data-dir")," path to a global state directory where ",(0,r.kt)("inlineCode",{parentName:"li"},"data.lmdb")," can be found"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--state-hash")," is the state root hash at the latest block. You should use the client to obtain the most recent state root hash to generate the ",(0,r.kt)("inlineCode",{parentName:"li"},"global_state.toml"),".")),(0,r.kt)("h3",{id:"rotating-validators"},"Rotating validators"),(0,r.kt)("p",null,"The following command rotates the validator set. Perform a network upgrade with a ",(0,r.kt)("inlineCode",{parentName:"p"},"global_state.toml")," with the new entries generated by the ",(0,r.kt)("inlineCode",{parentName:"p"},"global-state-update-gen")," command."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sh"},"global-state-update-gen validators \\\n --data-dir $DATA_DIR \\\n --state-hash $STATE_ROOT_HASH \\\n --validator NEW_PUBLIC_KEY,NEW_STAKE \\\n --validator NEW_PUBLIC_KEY2,NEW_STAKE2\n")),(0,r.kt)("h3",{id:"adding-new-administrators"},"Adding new administrators"),(0,r.kt)("p",null,"The following command produces the administrator content in the ",(0,r.kt)("inlineCode",{parentName:"p"},"global_state.toml")," file."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sh"},"global-state-update-gen generate-admins --admin NEW_PUBLIC_KEY,NEW_BALANCE --data-dir $DATA_DIR --state-hash $STATE_ROOT_HASH\n")),(0,r.kt)("p",null,"Remember that new administrators can be created, and the validator set can also be rotated in a single update."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"chainspec.toml")," file should contain the following entries that include new administrators as well as existing ones for an upgrade:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'[core]\nadministrators = ["NEW_PUBLIC_KEY"]\n')),(0,r.kt)("p",null,"After this step, the private network would be ready for use."),(0,r.kt)("h2",{id:"setting-up-a-block-explorer"},"Setting up a Block Explorer"),(0,r.kt)("p",null,"Private and hybrid blockchains can find information on how to set up and operate our free version of a block explorer ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-blockexplorer-frontend"},"here"),"."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/08478d9e.97b2823f.js b/assets/js/08478d9e.97b2823f.js deleted file mode 100644 index 0713dffd1f..0000000000 --- a/assets/js/08478d9e.97b2823f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7156],{3905:function(e,t,a){a.d(t,{Zo:function(){return p},kt:function(){return m}});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(a),h=i,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||r;return a?n.createElement(m,o(o({ref:t},p),{},{components:a})):n.createElement(m,o({ref:t},p))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,o[1]=s;for(var c=2;c> global_state.toml\n")),(0,r.kt)("p",null,"By using ",(0,r.kt)("inlineCode",{parentName:"p"},">>")," shell redirection you will always append contents to existing file without overwriting it. This is helpful when you need to chain multiple operations in a single upgrade."),(0,r.kt)("p",null,"Common options:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--data-dir")," path to a global state directory where ",(0,r.kt)("inlineCode",{parentName:"li"},"data.lmdb")," can be found"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"--state-hash")," is the state root hash at the latest block. You should use the client to obtain the most recent state root hash to generate the ",(0,r.kt)("inlineCode",{parentName:"li"},"global_state.toml"),".")),(0,r.kt)("h3",{id:"rotating-validators"},"Rotating validators"),(0,r.kt)("p",null,"The following command rotates the validator set. Perform a network upgrade with a ",(0,r.kt)("inlineCode",{parentName:"p"},"global_state.toml")," with the new entries generated by the ",(0,r.kt)("inlineCode",{parentName:"p"},"global-state-update-gen")," command."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sh"},"global-state-update-gen validators \\\n --data-dir $DATA_DIR \\\n --state-hash $STATE_ROOT_HASH \\\n --validator NEW_PUBLIC_KEY,NEW_STAKE \\\n --validator NEW_PUBLIC_KEY2,NEW_STAKE2\n")),(0,r.kt)("h3",{id:"adding-new-administrators"},"Adding new administrators"),(0,r.kt)("p",null,"The following command produces the administrator content in the ",(0,r.kt)("inlineCode",{parentName:"p"},"global_state.toml")," file."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-sh"},"global-state-update-gen generate-admins --admin NEW_PUBLIC_KEY,NEW_BALANCE --data-dir $DATA_DIR --state-hash $STATE_ROOT_HASH\n")),(0,r.kt)("p",null,"Remember that new administrators can be created, and the validator set can also be rotated in a single update."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"chainspec.toml")," file should contain the following entries that include new administrators as well as existing ones for an upgrade:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-toml"},'[core]\nadministrators = ["NEW_PUBLIC_KEY"]\n')),(0,r.kt)("p",null,"After this step, the private network would be ready for use."),(0,r.kt)("h2",{id:"setting-up-a-block-explorer"},"Setting up a Block Explorer"),(0,r.kt)("p",null,"Private and hybrid blockchains can find information on how to set up and operate our free version of a block explorer ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-blockexplorer-frontend"},"here"),"."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/08ab7f39.82a7d3bb.js b/assets/js/08ab7f39.82a7d3bb.js deleted file mode 100644 index 195a5b48fb..0000000000 --- a/assets/js/08ab7f39.82a7d3bb.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5614],{3905:function(e,n,t){t.d(n,{Zo:function(){return c},kt:function(){return m}});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function a(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),p=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},c=function(e){var n=p(e.components);return o.createElement(s.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},k=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(t),k=r,m=d["".concat(s,".").concat(k)]||d[k]||u[k]||i;return t?o.createElement(m,a(a({ref:n},c),{},{components:t})):o.createElement(m,a({ref:n},c))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,a=new Array(i);a[0]=k;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[d]="string"==typeof e?e:r,a[1]=l;for(var p=2;pprotocol_versions",id:"more-on-protocol_versions",level:3},{value:"Protocol Version",id:"protocol-version",level:2},{value:"Network Configuration File",id:"network-configuration-file",level:2},{value:"Setup Configuration Files",id:"setup-configuration-files",level:2},{value:"chainspec.toml",id:"chainspectoml",level:3},{value:"config-example.toml",id:"config-exampletoml",level:3},{value:"Staging a Protocol Version",id:"staging-a-protocol-version",level:2}],u={toc:d},k="wrapper";function m(e){var n=e.components,t=(0,r.Z)(e,a);return(0,i.kt)(k,(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"staging-files-for-a-new-network"},"Staging Files for a New Network"),(0,i.kt)("admonition",{type:"important"},(0,i.kt)("p",{parentName:"admonition"},"Staging files is not needed for already established running networks."),(0,i.kt)("p",{parentName:"admonition"},"Only use these instructions if you are creating a new Casper network and hosting protocol files for this network.")),(0,i.kt)("h2",{id:"hosting-server"},"Hosting Server"),(0,i.kt)("p",null,"Files for staging protocol versions are hosted on a typical HTTP(S) server."),(0,i.kt)("p",null,"Scripts included with the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," have network configurations for Mainnet and Testnet. These scripts point to the server hosting files and network name."),(0,i.kt)("p",null,"Since a given server can be used for multiple networks, a network named directory is used to hold files for that network."),(0,i.kt)("p",null,"This is a description of Mainnet protocol version hosting (with network name: ",(0,i.kt)("inlineCode",{parentName:"p"},"casper"),")."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"genesis.casperlab.io")," is the web server URL with the following directory structure:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"casper"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"protocol_versions")," - File listing active protocol versions so scripts know what directories to use"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"1_0_0")," - Genesis protocol version",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," - Configuration files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/etc/casper/1_0_0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," - Binary files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/bin/1_0_0")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"1_1_0")," - First upgrade",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," - Configuration files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/etc/casper/1_1_0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," - Binary files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/bin/1_1_0")))),(0,i.kt)("li",{parentName:"ul"},"... (skipping many other protocol versions)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"1_4_6")," - A later upgrade",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," - Configuration files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/etc/casper/1_4_6")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," - Binary files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/bin/1_4_6"))))))),(0,i.kt)("h3",{id:"more-on-protocol_versions"},"More on ",(0,i.kt)("inlineCode",{parentName:"h3"},"protocol_versions")),(0,i.kt)("p",null,"At the root of the hosting server directory for a given network, a ",(0,i.kt)("inlineCode",{parentName:"p"},"protocol_versions")," file exists. This holds the valid protocol versions for a network."),(0,i.kt)("p",null,"We can look at this manually on Mainnet using ",(0,i.kt)("em",{parentName:"p"},"curl"),". As of writing this, ",(0,i.kt)("inlineCode",{parentName:"p"},"1.4.6")," is the latest version and the contents of this file will change."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"\n$ curl -s genesis.casperlabs.io/casper/protocol_versions\n1_0_0\n1_1_0\n1_1_2\n1_2_0\n1_2_1\n1_3_2\n1_3_4\n1_4_1\n1_4_3\n1_4_4\n1_4_5\n1_4_6\n\n")),(0,i.kt)("p",null,"We should find ",(0,i.kt)("inlineCode",{parentName:"p"},"bin.tar.gz")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"config.tar.gz")," in those directories under ",(0,i.kt)("inlineCode",{parentName:"p"},"casper"),"."),(0,i.kt)("h2",{id:"protocol-version"},"Protocol Version"),(0,i.kt)("p",null,"The protocol version of a network is not related to the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," version. In Mainnet, these have often been the same. However, with a new network, you would use the latest ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," version for your ",(0,i.kt)("inlineCode",{parentName:"p"},"1.0.0")," protocol."),(0,i.kt)("h2",{id:"network-configuration-file"},"Network Configuration File"),(0,i.kt)("p",null,"When the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," package is installed, both ",(0,i.kt)("inlineCode",{parentName:"p"},"casper.conf")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-test.conf")," are installed in ",(0,i.kt)("inlineCode",{parentName:"p"},"/etc/casper/network_configs"),". Once a valid config file for a new network is copied to this location, all commands with ",(0,i.kt)("em",{parentName:"p"},"node_util.py")," will work as they do on existing networks."),(0,i.kt)("p",null,"By convention, we name the config file the same as the network. So Mainnet has a network name of ",(0,i.kt)("inlineCode",{parentName:"p"},"casper")," and we use ",(0,i.kt)("inlineCode",{parentName:"p"},"casper.conf")," for the config file."),(0,i.kt)("p",null,"For a new network using server ",(0,i.kt)("inlineCode",{parentName:"p"},"casper.mydomain.com")," to host files for ",(0,i.kt)("inlineCode",{parentName:"p"},"our-network")," network, we would have a ",(0,i.kt)("inlineCode",{parentName:"p"},"our-network.conf")," file that looks like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"SOURCE_URL=casper.mydomain.com\nNETWORK_NAME=our-network\n")),(0,i.kt)("p",null,"Host this ",(0,i.kt)("inlineCode",{parentName:"p"},"our-network.conf")," in the root of ",(0,i.kt)("inlineCode",{parentName:"p"},"casper.mydomain.com/our-network")," at the same level as ",(0,i.kt)("inlineCode",{parentName:"p"},"protocol_versions"),"."),(0,i.kt)("p",null,"This allows any node which wants to use the new network to run the following to install this configuration:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cd /etc/casper/network_configs\nsudo -u casper curl -JLO casper.mydomain.com/our-network/our-network.conf\n")),(0,i.kt)("p",null,"Any command needing a network config from ",(0,i.kt)("inlineCode",{parentName:"p"},"node_util.py")," can use ",(0,i.kt)("inlineCode",{parentName:"p"},"our-network.conf"),"."),(0,i.kt)("p",null,"Staging protocol versions for a new node with this network or staging an upcoming upgrade would just need this command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols our-network.conf\n")),(0,i.kt)("h2",{id:"setup-configuration-files"},"Setup Configuration Files"),(0,i.kt)("p",null,"For a network to be started, we to build the configuration files for a certain genesis time and with nodes that will be running. These files need to be configured in advanced, so a genesis time should be selected that allows packaging the files, loading onto nodes and starting nodes prior to the genesis time."),(0,i.kt)("h3",{id:"chainspectoml"},"chainspec.toml"),(0,i.kt)("p",null,"The ",(0,i.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml")," file is configuration for the network and must be exactly the same on all nodes."),(0,i.kt)("p",null,"The name for a network is specified ",(0,i.kt)("inlineCode",{parentName:"p"},"network.name"),"."),(0,i.kt)("p",null,"Each protocol will have a ",(0,i.kt)("inlineCode",{parentName:"p"},"version")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"activation_point"),". At genesis this is a date and time in format shown below. For future upgrades it would be an integer of the ",(0,i.kt)("inlineCode",{parentName:"p"},"era_id")," for activation of the upgrade."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"[protocol]\nversion = '1.0.0'\nactivation_point = '2022-08-01T10:00:00Z'\n\n[network]\nname = 'mynetwork'\n")),(0,i.kt)("h3",{id:"config-exampletoml"},"config-example.toml"),(0,i.kt)("p",null,"The config-example.toml is used to generate config.toml for a protocol after the node's IP is inserted. The ",(0,i.kt)("inlineCode",{parentName:"p"},"public_address")," is auto-detected with ",(0,i.kt)("inlineCode",{parentName:"p"},"node_util.py stage_protocols"),". If using a NAT environment, the public IP can be specified with the ",(0,i.kt)("inlineCode",{parentName:"p"},"--ip")," argument."),(0,i.kt)("p",null,"This file should have ",(0,i.kt)("inlineCode",{parentName:"p"},"known_addresses")," added that are relevant to the network. Nodes that will be genesis validators are added to this list in the form:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"[network]\nknown_addresses = [':35000',':35000',':35000']\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"config.toml")," can be setup to customized fields for a given node. ",(0,i.kt)("inlineCode",{parentName:"p"},"config-example.toml")," is a default configuration."),(0,i.kt)("h2",{id:"staging-a-protocol-version"},"Staging a Protocol Version"),(0,i.kt)("p",null,"For the initial genesis protocol version or future upgrade protocol versions, you will typically use prebuilt and tested ",(0,i.kt)("inlineCode",{parentName:"p"},"bin.tar.gz")," that have been tested and staged for existing networks. The ",(0,i.kt)("inlineCode",{parentName:"p"},"config.tar.gz")," file must be customized for the specific network with a network name, protocol version and activation point at the very least."),(0,i.kt)("p",null,"These archives should be created with no directory information stored. This is done by using ",(0,i.kt)("inlineCode",{parentName:"p"},"tar")," in the same directory as the files."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir config\ncd config\nmv [source of chainspec.toml] ./chainspec.toml\nmv [source of config-example.toml] ./config-example.toml\ntar -czvf ../config.tar.gz .\n")),(0,i.kt)("p",null,"You can test what was compressed with untar'ing the file."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir conftest\ncd conftest\ntar -xzvf ../config.tar.gz .\n")),(0,i.kt)("p",null,"This will expand files for verification."),(0,i.kt)("p",null,"For custom ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," builds, the minimum contents of ",(0,i.kt)("inlineCode",{parentName:"p"},"bin.tar.gz")," is the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," executable."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir bin\ncd bin\ncp [source of casper-node] ./casper-node\ntar -czvf ../bin.tar.gz .\n")),(0,i.kt)("p",null,"A directory for the protocol_version will be created on the server. For example: ",(0,i.kt)("inlineCode",{parentName:"p"},"1_1_0"),"."),(0,i.kt)("p",null,"We will copy ",(0,i.kt)("inlineCode",{parentName:"p"},"bin.tar.gz")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"config.tar.gz")," into ",(0,i.kt)("inlineCode",{parentName:"p"},"1_1_0"),". Once this is done, we are safe to update ",(0,i.kt)("inlineCode",{parentName:"p"},"protocol_versions")," by appending ",(0,i.kt)("inlineCode",{parentName:"p"},"1_1_0")," to the end of the file and uploading it into the root of the network directory."),(0,i.kt)("p",null,"Any node that runs the following command will get this new upgrade:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols \n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/08ab7f39.cda8d9b9.js b/assets/js/08ab7f39.cda8d9b9.js new file mode 100644 index 0000000000..89458629c9 --- /dev/null +++ b/assets/js/08ab7f39.cda8d9b9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5614],{3905:function(e,n,t){t.d(n,{Zo:function(){return c},kt:function(){return m}});var o=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);n&&(o=o.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,o)}return t}function a(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var s=o.createContext({}),p=function(e){var n=o.useContext(s),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},c=function(e){var n=p(e.components);return o.createElement(s.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return o.createElement(o.Fragment,{},n)}},k=o.forwardRef((function(e,n){var t=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(t),k=r,m=d["".concat(s,".").concat(k)]||d[k]||u[k]||i;return t?o.createElement(m,a(a({ref:n},c),{},{components:t})):o.createElement(m,a({ref:n},c))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var i=t.length,a=new Array(i);a[0]=k;var l={};for(var s in n)hasOwnProperty.call(n,s)&&(l[s]=n[s]);l.originalType=e,l[d]="string"==typeof e?e:r,a[1]=l;for(var p=2;pprotocol_versions",id:"more-on-protocol_versions",level:3},{value:"Protocol Version",id:"protocol-version",level:2},{value:"Network Configuration File",id:"network-configuration-file",level:2},{value:"Setup Configuration Files",id:"setup-configuration-files",level:2},{value:"chainspec.toml",id:"chainspectoml",level:3},{value:"config-example.toml",id:"config-exampletoml",level:3},{value:"Staging a Protocol Version",id:"staging-a-protocol-version",level:2}],u={toc:d},k="wrapper";function m(e){var n=e.components,t=(0,r.Z)(e,a);return(0,i.kt)(k,(0,o.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"staging-files-for-a-new-network"},"Staging Files for a New Network"),(0,i.kt)("admonition",{type:"important"},(0,i.kt)("p",{parentName:"admonition"},"Staging files is not needed for already established running networks."),(0,i.kt)("p",{parentName:"admonition"},"Only use these instructions if you are creating a new Casper network and hosting protocol files for this network.")),(0,i.kt)("h2",{id:"hosting-server"},"Hosting Server"),(0,i.kt)("p",null,"Files for staging protocol versions are hosted on a typical HTTP(S) server."),(0,i.kt)("p",null,"Scripts included with the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," have network configurations for Mainnet and Testnet. These scripts point to the server hosting files and network name."),(0,i.kt)("p",null,"Since a given server can be used for multiple networks, a network named directory is used to hold files for that network."),(0,i.kt)("p",null,"This is a description of Mainnet protocol version hosting (with network name: ",(0,i.kt)("inlineCode",{parentName:"p"},"casper"),")."),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"genesis.casperlab.io")," is the web server URL with the following directory structure:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"casper"),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"protocol_versions")," - File listing active protocol versions so scripts know what directories to use"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"1_0_0")," - Genesis protocol version",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," - Configuration files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/etc/casper/1_0_0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," - Binary files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/bin/1_0_0")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"1_1_0")," - First upgrade",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," - Configuration files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/etc/casper/1_1_0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," - Binary files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/bin/1_1_0")))),(0,i.kt)("li",{parentName:"ul"},"... (skipping many other protocol versions)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"1_4_6")," - A later upgrade",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," - Configuration files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/etc/casper/1_4_6")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," - Binary files to be expanded into ",(0,i.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/bin/1_4_6"))))))),(0,i.kt)("h3",{id:"more-on-protocol_versions"},"More on ",(0,i.kt)("inlineCode",{parentName:"h3"},"protocol_versions")),(0,i.kt)("p",null,"At the root of the hosting server directory for a given network, a ",(0,i.kt)("inlineCode",{parentName:"p"},"protocol_versions")," file exists. This holds the valid protocol versions for a network."),(0,i.kt)("p",null,"We can look at this manually on Mainnet using ",(0,i.kt)("em",{parentName:"p"},"curl"),". As of writing this, ",(0,i.kt)("inlineCode",{parentName:"p"},"1.4.6")," is the latest version and the contents of this file will change."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"\n$ curl -s genesis.casperlabs.io/casper/protocol_versions\n1_0_0\n1_1_0\n1_1_2\n1_2_0\n1_2_1\n1_3_2\n1_3_4\n1_4_1\n1_4_3\n1_4_4\n1_4_5\n1_4_6\n\n")),(0,i.kt)("p",null,"We should find ",(0,i.kt)("inlineCode",{parentName:"p"},"bin.tar.gz")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"config.tar.gz")," in those directories under ",(0,i.kt)("inlineCode",{parentName:"p"},"casper"),"."),(0,i.kt)("h2",{id:"protocol-version"},"Protocol Version"),(0,i.kt)("p",null,"The protocol version of a network is not related to the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," version. In Mainnet, these have often been the same. However, with a new network, you would use the latest ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," version for your ",(0,i.kt)("inlineCode",{parentName:"p"},"1.0.0")," protocol."),(0,i.kt)("h2",{id:"network-configuration-file"},"Network Configuration File"),(0,i.kt)("p",null,"When the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," package is installed, both ",(0,i.kt)("inlineCode",{parentName:"p"},"casper.conf")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-test.conf")," are installed in ",(0,i.kt)("inlineCode",{parentName:"p"},"/etc/casper/network_configs"),". Once a valid config file for a new network is copied to this location, all commands with ",(0,i.kt)("em",{parentName:"p"},"node_util.py")," will work as they do on existing networks."),(0,i.kt)("p",null,"By convention, we name the config file the same as the network. So Mainnet has a network name of ",(0,i.kt)("inlineCode",{parentName:"p"},"casper")," and we use ",(0,i.kt)("inlineCode",{parentName:"p"},"casper.conf")," for the config file."),(0,i.kt)("p",null,"For a new network using server ",(0,i.kt)("inlineCode",{parentName:"p"},"casper.mydomain.com")," to host files for ",(0,i.kt)("inlineCode",{parentName:"p"},"our-network")," network, we would have a ",(0,i.kt)("inlineCode",{parentName:"p"},"our-network.conf")," file that looks like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"SOURCE_URL=casper.mydomain.com\nNETWORK_NAME=our-network\n")),(0,i.kt)("p",null,"Host this ",(0,i.kt)("inlineCode",{parentName:"p"},"our-network.conf")," in the root of ",(0,i.kt)("inlineCode",{parentName:"p"},"casper.mydomain.com/our-network")," at the same level as ",(0,i.kt)("inlineCode",{parentName:"p"},"protocol_versions"),"."),(0,i.kt)("p",null,"This allows any node which wants to use the new network to run the following to install this configuration:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cd /etc/casper/network_configs\nsudo -u casper curl -JLO casper.mydomain.com/our-network/our-network.conf\n")),(0,i.kt)("p",null,"Any command needing a network config from ",(0,i.kt)("inlineCode",{parentName:"p"},"node_util.py")," can use ",(0,i.kt)("inlineCode",{parentName:"p"},"our-network.conf"),"."),(0,i.kt)("p",null,"Staging protocol versions for a new node with this network or staging an upcoming upgrade would just need this command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols our-network.conf\n")),(0,i.kt)("h2",{id:"setup-configuration-files"},"Setup Configuration Files"),(0,i.kt)("p",null,"For a network to be started, we to build the configuration files for a certain genesis time and with nodes that will be running. These files need to be configured in advanced, so a genesis time should be selected that allows packaging the files, loading onto nodes and starting nodes prior to the genesis time."),(0,i.kt)("h3",{id:"chainspectoml"},"chainspec.toml"),(0,i.kt)("p",null,"The ",(0,i.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml")," file is configuration for the network and must be exactly the same on all nodes."),(0,i.kt)("p",null,"The name for a network is specified ",(0,i.kt)("inlineCode",{parentName:"p"},"network.name"),"."),(0,i.kt)("p",null,"Each protocol will have a ",(0,i.kt)("inlineCode",{parentName:"p"},"version")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"activation_point"),". At genesis this is a date and time in format shown below. For future upgrades it would be an integer of the ",(0,i.kt)("inlineCode",{parentName:"p"},"era_id")," for activation of the upgrade."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"[protocol]\nversion = '1.0.0'\nactivation_point = '2022-08-01T10:00:00Z'\n\n[network]\nname = 'mynetwork'\n")),(0,i.kt)("h3",{id:"config-exampletoml"},"config-example.toml"),(0,i.kt)("p",null,"The config-example.toml is used to generate config.toml for a protocol after the node's IP is inserted. The ",(0,i.kt)("inlineCode",{parentName:"p"},"public_address")," is auto-detected with ",(0,i.kt)("inlineCode",{parentName:"p"},"node_util.py stage_protocols"),". If using a NAT environment, the public IP can be specified with the ",(0,i.kt)("inlineCode",{parentName:"p"},"--ip")," argument."),(0,i.kt)("p",null,"This file should have ",(0,i.kt)("inlineCode",{parentName:"p"},"known_addresses")," added that are relevant to the network. Nodes that will be genesis validators are added to this list in the form:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"[network]\nknown_addresses = [':35000',':35000',':35000']\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"config.toml")," can be setup to customized fields for a given node. ",(0,i.kt)("inlineCode",{parentName:"p"},"config-example.toml")," is a default configuration."),(0,i.kt)("h2",{id:"staging-a-protocol-version"},"Staging a Protocol Version"),(0,i.kt)("p",null,"For the initial genesis protocol version or future upgrade protocol versions, you will typically use prebuilt and tested ",(0,i.kt)("inlineCode",{parentName:"p"},"bin.tar.gz")," that have been tested and staged for existing networks. The ",(0,i.kt)("inlineCode",{parentName:"p"},"config.tar.gz")," file must be customized for the specific network with a network name, protocol version and activation point at the very least."),(0,i.kt)("p",null,"These archives should be created with no directory information stored. This is done by using ",(0,i.kt)("inlineCode",{parentName:"p"},"tar")," in the same directory as the files."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir config\ncd config\nmv [source of chainspec.toml] ./chainspec.toml\nmv [source of config-example.toml] ./config-example.toml\ntar -czvf ../config.tar.gz .\n")),(0,i.kt)("p",null,"You can test what was compressed with untar'ing the file."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir conftest\ncd conftest\ntar -xzvf ../config.tar.gz .\n")),(0,i.kt)("p",null,"This will expand files for verification."),(0,i.kt)("p",null,"For custom ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," builds, the minimum contents of ",(0,i.kt)("inlineCode",{parentName:"p"},"bin.tar.gz")," is the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," executable."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir bin\ncd bin\ncp [source of casper-node] ./casper-node\ntar -czvf ../bin.tar.gz .\n")),(0,i.kt)("p",null,"A directory for the protocol_version will be created on the server. For example: ",(0,i.kt)("inlineCode",{parentName:"p"},"1_1_0"),"."),(0,i.kt)("p",null,"We will copy ",(0,i.kt)("inlineCode",{parentName:"p"},"bin.tar.gz")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"config.tar.gz")," into ",(0,i.kt)("inlineCode",{parentName:"p"},"1_1_0"),". Once this is done, we are safe to update ",(0,i.kt)("inlineCode",{parentName:"p"},"protocol_versions")," by appending ",(0,i.kt)("inlineCode",{parentName:"p"},"1_1_0")," to the end of the file and uploading it into the root of the network directory."),(0,i.kt)("p",null,"Any node that runs the following command will get this new upgrade:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols \n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/09666a94.648e341f.js b/assets/js/09666a94.648e341f.js new file mode 100644 index 0000000000..cee34b84c2 --- /dev/null +++ b/assets/js/09666a94.648e341f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[716],{3905:function(e,t,a){a.d(t,{Zo:function(){return p},kt:function(){return m}});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),d=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(a),h=i,m=c["".concat(s,".").concat(h)]||c[h]||u[h]||r;return a?n.createElement(m,o(o({ref:t},p),{},{components:a})):n.createElement(m,o({ref:t},p))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,o[1]=l;for(var d=2;d \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point delegate \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"delegator:public_key=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entry point that will be used when calling the contract")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate")," entry point expects three arguments:"),(0,r.kt)("ol",{start:7},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"validator"),": The hexadecimal public key of the validator receiving the delegated tokens"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The number of tokens to be delegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"delegator"),": The hexadecimal public key of the account delegating tokens to a validator. ",(0,r.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the delegation"))),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate")," entry point on the auction contract has a fixed cost of 2.5 CSPR.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example shows an account delegating 500 CSPR:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key ~/KEYS/secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point delegate \\\n--session-arg \"validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'\" \\\n--session-arg \"amount:u512='500000000000'\" \\\n--session-arg \"delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'\"\n")),(0,r.kt)("p",null,"Next, ",(0,r.kt)("a",{parentName:"p",href:"#confirming-the-delegation"},"confirm the delegation"),"."),(0,r.kt)("h3",{id:"delegating-compiled-wasm"},"Method 2: Delegating with Compiled Wasm"),(0,r.kt)("p",null,"Another way to send a delegation is to compile the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate.wasm")," and send it to the network via a deploy. Here are the steps to compile the contract yourself."),(0,r.kt)("h4",{id:"building-the-delegation-wasm"},"Building the delegation Wasm"),(0,r.kt)("p",null,"Obtain the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate.wasm")," by cloning the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-network/casper-node\n")),(0,r.kt)("p",null,"Prepare the Rust environment and then build the contracts using the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/Makefile"},"Makefile")," provided in the repository."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd casper-node\nmake setup-rs\nmake build-contracts-rs\n")),(0,r.kt)("p",null,"Once you build the contracts, you can use the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate.wasm")," to create a deploy that will initiate the delegation process. The Wasm can be found in this directory: ",(0,r.kt)("inlineCode",{parentName:"p"},"target/wasm32-unknown-unknown/release/"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"ls target/wasm32-unknown-unknown/release/delegate.wasm\n")),(0,r.kt)("h4",{id:"sending-the-delegation-wasm-request"},"Sending the delegation request"),(0,r.kt)("p",null,"In this example, we use the Casper client to send a deploy containing the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate.wasm")," to the network to initiate the delegation process."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path /delegate.wasm \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"delegator:public_key=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to where the ",(0,r.kt)("inlineCode",{parentName:"li"},"delegate.wasm")," is located")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate")," entry point expects three arguments:"),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"validator"),": The hexadecimal public key of the validator receiving the delegated tokens"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The number of tokens to be delegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"delegator"),": The hexadecimal public key of the account delegating tokens to a validator. ",(0,r.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the delegation"))),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example command uses the Casper Testnet to delegate 500 CSPR, and the payment amount is 6 CSPR. The payment amount varies based on each deploy and network ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". However, notice that this method is more expensive than the previous one that calls the delegate entry point."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key ~/KEYS/secret_key.pem \\\n--payment-amount 20000000000 \\\n--session-path ~/delegate.wasm \\\n--session-arg \"validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'\" \\\n--session-arg \"amount:u512='500000000000'\" \\\n--session-arg \"delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'\"\n")),(0,r.kt)("p",null,"Next, ",(0,r.kt)("a",{parentName:"p",href:"#confirming-the-delegation"},"confirm the delegation"),"."),(0,r.kt)("h2",{id:"confirming-the-delegation"},"Confirming the Delegation"),(0,r.kt)("p",null,"A Casper network maintains an ",(0,r.kt)("em",{parentName:"p"},"auction")," where validators ",(0,r.kt)("em",{parentName:"p"},"bid")," on slots to become part of the active validator set. Delegation rewards are only earned for a validator who has won the auction and is part of the active set. Thus to ensure the delegated tokens can earn rewards, you must first check the foloowing:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Your delegation is part of the ",(0,r.kt)("em",{parentName:"li"},"bid")," to the ",(0,r.kt)("em",{parentName:"li"},"auction")),(0,r.kt)("li",{parentName:"ol"},"The validator is part of the ",(0,r.kt)("em",{parentName:"li"},"active")," validator set")),(0,r.kt)("p",null,"Once the deploy has been processed, you can query the auction for information to confirm our delegation. Use the Casper command-line client to create an RPC request with the following query:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info \\\n--node-address http://:7777\n")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Request fields"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"get-auction-info")," call will return all the bids currently in the auction contract and the list of active validators for ",(0,r.kt)("inlineCode",{parentName:"p"},"4")," future eras from the present era."),(0,r.kt)("p",null,"Below is a sample of the ",(0,r.kt)("inlineCode",{parentName:"p"},"bids")," structure:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"bids": [\n{\n "bid": {\n "bonding_purse": "uref-a5ce7dbc5f7e02ef52048e64b2ff4693a472a1a56fe71e83b180cd33271b2ed9-007",\n "delegation_rate": 1,\n "delegators": [\n {\n "bonding_purse": "uref-ca9247ad56a4d5be70484303133e2d6db97f7d7385772155763749af98ace0b0-007",\n "delegatee": "0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd",\n "public_key": "010c7fef89bf1fc38363bd2ec20bbfb5e1152d6a9579c8847615c59c7e461ece89",\n "staked_amount": "1"\n },\n {\n "bonding_purse": "uref-38a2e9cad51b380e478c9a325578f4bbdaa0337b99b9ab9bf1dc2a114eb948b9-007",\n "delegatee": "0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd",\n "public_key": "016ebb38d613f2550e7c21ff9d99f6249b4ae5fb9e30938f6ece2d84a22a36b035",\n "staked_amount": "478473232415318176495746923"\n }\n ],\n "inactive": false,\n "staked_amount": "493754513995516852173468935"\n },\n "public_key": "0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd"\n},\n')),(0,r.kt)("p",null,"The delegation request has been processed successfully if your public key and associated amount appear in the ",(0,r.kt)("inlineCode",{parentName:"p"},"bid")," data structure. However, this does not mean the associated validator is part of the validator set, so you must check the validator status recorded in the ",(0,r.kt)("inlineCode",{parentName:"p"},"era_validators")," structure."),(0,r.kt)("h4",{id:"checking-validator-status"},"Checking Validator Status"),(0,r.kt)("p",null,"The auction maintains a field called ",(0,r.kt)("inlineCode",{parentName:"p"},"era_validators"),", which contains the validator information for 4 future eras from the current era. An entry for a specific era lists the ",(0,r.kt)("inlineCode",{parentName:"p"},"PublicKeys")," of the active validators for that era, along with their stake in the network."),(0,r.kt)("p",null,"If a validator is part of the set, its public key will be in the ",(0,r.kt)("inlineCode",{parentName:"p"},"era_validators")," field as part of the ",(0,r.kt)("inlineCode",{parentName:"p"},"Auction")," data structure returned by ",(0,r.kt)("inlineCode",{parentName:"p"},"casper-client get-auction-info"),"."),(0,r.kt)("p",null,"In the response, check the ",(0,r.kt)("inlineCode",{parentName:"p"},'"auction_state"."era_validators"')," structure, which should contain the public key of the selected validator for the era in which the validator will be active."),(0,r.kt)("p",null,"Below is an example of the ",(0,r.kt)("inlineCode",{parentName:"p"},"era_validators")," structure:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"block_height":105,\n "era_validators":[\n {\n "era_id":9,\n "validator_weights":[\n {\n "public_key":"0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd",\n "weight":"648151805935226166098427654"\n },\n {\n "public_key":"01aa67009b37a23c7ad0ca632da5da239d5db46067d4b34125f61b04611f610baf",\n "weight":"648151805938466925128109996"\n },\n {\n "public_key":"01b7afa2beeddffd13458b763d7a00259f7dc0fa45498dfed05b4d7df4b7d65e2c",\n "weight":"648151805935226166098427656"\n },\n {\n "public_key":"01ca5463dac047cbd750d97ee42dd810cf1e081ece7d83ae4fc03b25a9ecad3b6a",\n "weight":"648151805938466925128109998"\n },\n {\n "public_key":"01f4a7644695aa129eba09fb3f11d0277b2bea1a3d5bc1933bcda93fdb4ad17e55",\n "weight":"648151805938466925128110000"\n }\n ]\n },\n')),(0,r.kt)("p",null,"In the above example, we see the public keys of the active validators in Era ",(0,r.kt)("inlineCode",{parentName:"p"},"9"),"."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note"),": Validators earn delegation rewards only when they are part of the active set. This information is time-sensitive; therefore, a validator selected today may not be part of the set tomorrow. Keep this in mind when creating a delegation request."),(0,r.kt)("p",null,"If your account is on the official Testnet or Mainnet, you can use the block explorer to look up your account balance and see that the tokens have been delegated:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"https://testnet.cspr.live/"},"Testnet explorer")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"https://cspr.live/"},"Mainnet explorer"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/09666a94.cad4ab5c.js b/assets/js/09666a94.cad4ab5c.js deleted file mode 100644 index 8f05501119..0000000000 --- a/assets/js/09666a94.cad4ab5c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[716],{3905:function(e,t,a){a.d(t,{Zo:function(){return p},kt:function(){return m}});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),d=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(a),h=i,m=c["".concat(s,".").concat(h)]||c[h]||u[h]||r;return a?n.createElement(m,o(o({ref:t},p),{},{components:a})):n.createElement(m,o({ref:t},p))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=a.length,o=new Array(r);o[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,o[1]=l;for(var d=2;d \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point delegate \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"delegator:public_key=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entry point that will be used when calling the contract")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate")," entry point expects three arguments:"),(0,r.kt)("ol",{start:7},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"validator"),": The hexadecimal public key of the validator receiving the delegated tokens"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The number of tokens to be delegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"delegator"),": The hexadecimal public key of the account delegating tokens to a validator. ",(0,r.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the delegation"))),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate")," entry point on the auction contract has a fixed cost of 2.5 CSPR.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example shows an account delegating 500 CSPR:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key ~/KEYS/secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point delegate \\\n--session-arg \"validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'\" \\\n--session-arg \"amount:u512='500000000000'\" \\\n--session-arg \"delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'\"\n")),(0,r.kt)("p",null,"Next, ",(0,r.kt)("a",{parentName:"p",href:"#confirming-the-delegation"},"confirm the delegation"),"."),(0,r.kt)("h3",{id:"delegating-compiled-wasm"},"Method 2: Delegating with Compiled Wasm"),(0,r.kt)("p",null,"Another way to send a delegation is to compile the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate.wasm")," and send it to the network via a deploy. Here are the steps to compile the contract yourself."),(0,r.kt)("h4",{id:"building-the-delegation-wasm"},"Building the delegation Wasm"),(0,r.kt)("p",null,"Obtain the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate.wasm")," by cloning the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-network/casper-node\n")),(0,r.kt)("p",null,"Prepare the Rust environment and then build the contracts using the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/Makefile"},"Makefile")," provided in the repository."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd casper-node\nmake setup-rs\nmake build-contracts-rs\n")),(0,r.kt)("p",null,"Once you build the contracts, you can use the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate.wasm")," to create a deploy that will initiate the delegation process. The Wasm can be found in this directory: ",(0,r.kt)("inlineCode",{parentName:"p"},"target/wasm32-unknown-unknown/release/"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"ls target/wasm32-unknown-unknown/release/delegate.wasm\n")),(0,r.kt)("h4",{id:"sending-the-delegation-wasm-request"},"Sending the delegation request"),(0,r.kt)("p",null,"In this example, we use the Casper client to send a deploy containing the ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate.wasm")," to the network to initiate the delegation process."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path /delegate.wasm \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"delegator:public_key=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to where the ",(0,r.kt)("inlineCode",{parentName:"li"},"delegate.wasm")," is located")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"delegate")," entry point expects three arguments:"),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"validator"),": The hexadecimal public key of the validator receiving the delegated tokens"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The number of tokens to be delegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"delegator"),": The hexadecimal public key of the account delegating tokens to a validator. ",(0,r.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the delegation"))),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example command uses the Casper Testnet to delegate 500 CSPR, and the payment amount is 6 CSPR. The payment amount varies based on each deploy and network ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". However, notice that this method is more expensive than the previous one that calls the delegate entry point."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key ~/KEYS/secret_key.pem \\\n--payment-amount 20000000000 \\\n--session-path ~/delegate.wasm \\\n--session-arg \"validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'\" \\\n--session-arg \"amount:u512='500000000000'\" \\\n--session-arg \"delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'\"\n")),(0,r.kt)("p",null,"Next, ",(0,r.kt)("a",{parentName:"p",href:"#confirming-the-delegation"},"confirm the delegation"),"."),(0,r.kt)("h2",{id:"confirming-the-delegation"},"Confirming the Delegation"),(0,r.kt)("p",null,"A Casper network maintains an ",(0,r.kt)("em",{parentName:"p"},"auction")," where validators ",(0,r.kt)("em",{parentName:"p"},"bid")," on slots to become part of the active validator set. Delegation rewards are only earned for a validator who has won the auction and is part of the active set. Thus to ensure the delegated tokens can earn rewards, you must first check the foloowing:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Your delegation is part of the ",(0,r.kt)("em",{parentName:"li"},"bid")," to the ",(0,r.kt)("em",{parentName:"li"},"auction")),(0,r.kt)("li",{parentName:"ol"},"The validator is part of the ",(0,r.kt)("em",{parentName:"li"},"active")," validator set")),(0,r.kt)("p",null,"Once the deploy has been processed, you can query the auction for information to confirm our delegation. Use the Casper command-line client to create an RPC request with the following query:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info \\\n--node-address http://:7777\n")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Request fields"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"get-auction-info")," call will return all the bids currently in the auction contract and the list of active validators for ",(0,r.kt)("inlineCode",{parentName:"p"},"4")," future eras from the present era."),(0,r.kt)("p",null,"Below is a sample of the ",(0,r.kt)("inlineCode",{parentName:"p"},"bids")," structure:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"bids": [\n{\n "bid": {\n "bonding_purse": "uref-a5ce7dbc5f7e02ef52048e64b2ff4693a472a1a56fe71e83b180cd33271b2ed9-007",\n "delegation_rate": 1,\n "delegators": [\n {\n "bonding_purse": "uref-ca9247ad56a4d5be70484303133e2d6db97f7d7385772155763749af98ace0b0-007",\n "delegatee": "0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd",\n "public_key": "010c7fef89bf1fc38363bd2ec20bbfb5e1152d6a9579c8847615c59c7e461ece89",\n "staked_amount": "1"\n },\n {\n "bonding_purse": "uref-38a2e9cad51b380e478c9a325578f4bbdaa0337b99b9ab9bf1dc2a114eb948b9-007",\n "delegatee": "0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd",\n "public_key": "016ebb38d613f2550e7c21ff9d99f6249b4ae5fb9e30938f6ece2d84a22a36b035",\n "staked_amount": "478473232415318176495746923"\n }\n ],\n "inactive": false,\n "staked_amount": "493754513995516852173468935"\n },\n "public_key": "0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd"\n},\n')),(0,r.kt)("p",null,"The delegation request has been processed successfully if your public key and associated amount appear in the ",(0,r.kt)("inlineCode",{parentName:"p"},"bid")," data structure. However, this does not mean the associated validator is part of the validator set, so you must check the validator status recorded in the ",(0,r.kt)("inlineCode",{parentName:"p"},"era_validators")," structure."),(0,r.kt)("h4",{id:"checking-validator-status"},"Checking Validator Status"),(0,r.kt)("p",null,"The auction maintains a field called ",(0,r.kt)("inlineCode",{parentName:"p"},"era_validators"),", which contains the validator information for 4 future eras from the current era. An entry for a specific era lists the ",(0,r.kt)("inlineCode",{parentName:"p"},"PublicKeys")," of the active validators for that era, along with their stake in the network."),(0,r.kt)("p",null,"If a validator is part of the set, its public key will be in the ",(0,r.kt)("inlineCode",{parentName:"p"},"era_validators")," field as part of the ",(0,r.kt)("inlineCode",{parentName:"p"},"Auction")," data structure returned by ",(0,r.kt)("inlineCode",{parentName:"p"},"casper-client get-auction-info"),"."),(0,r.kt)("p",null,"In the response, check the ",(0,r.kt)("inlineCode",{parentName:"p"},'"auction_state"."era_validators"')," structure, which should contain the public key of the selected validator for the era in which the validator will be active."),(0,r.kt)("p",null,"Below is an example of the ",(0,r.kt)("inlineCode",{parentName:"p"},"era_validators")," structure:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"block_height":105,\n "era_validators":[\n {\n "era_id":9,\n "validator_weights":[\n {\n "public_key":"0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd",\n "weight":"648151805935226166098427654"\n },\n {\n "public_key":"01aa67009b37a23c7ad0ca632da5da239d5db46067d4b34125f61b04611f610baf",\n "weight":"648151805938466925128109996"\n },\n {\n "public_key":"01b7afa2beeddffd13458b763d7a00259f7dc0fa45498dfed05b4d7df4b7d65e2c",\n "weight":"648151805935226166098427656"\n },\n {\n "public_key":"01ca5463dac047cbd750d97ee42dd810cf1e081ece7d83ae4fc03b25a9ecad3b6a",\n "weight":"648151805938466925128109998"\n },\n {\n "public_key":"01f4a7644695aa129eba09fb3f11d0277b2bea1a3d5bc1933bcda93fdb4ad17e55",\n "weight":"648151805938466925128110000"\n }\n ]\n },\n')),(0,r.kt)("p",null,"In the above example, we see the public keys of the active validators in Era ",(0,r.kt)("inlineCode",{parentName:"p"},"9"),"."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note"),": Validators earn delegation rewards only when they are part of the active set. This information is time-sensitive; therefore, a validator selected today may not be part of the set tomorrow. Keep this in mind when creating a delegation request."),(0,r.kt)("p",null,"If your account is on the official Testnet or Mainnet, you can use the block explorer to look up your account balance and see that the tokens have been delegated:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"https://testnet.cspr.live/"},"Testnet explorer")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"https://cspr.live/"},"Mainnet explorer"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/09f38b0b.1b642723.js b/assets/js/09f38b0b.1b642723.js deleted file mode 100644 index 4c29dd725b..0000000000 --- a/assets/js/09f38b0b.1b642723.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[972],{3905:function(e,t,r){r.d(t,{Zo:function(){return l},kt:function(){return d}});var o=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=o.createContext({}),i=function(e){var t=o.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},l=function(e){var t=i(e.components);return o.createElement(p.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var r=e.components,a=e.mdxType,n=e.originalType,p=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),h=i(r),f=a,d=h["".concat(p,".").concat(f)]||h[f]||u[f]||n;return r?o.createElement(d,s(s({ref:t},l),{},{components:r})):o.createElement(d,s({ref:t},l))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var n=r.length,s=new Array(n);s[0]=f;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[h]="string"==typeof e?e:a,s[1]=c;for(var i=2;i=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=o.createContext({}),i=function(e){var t=o.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},l=function(e){var t=i(e.components);return o.createElement(p.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var r=e.components,a=e.mdxType,n=e.originalType,p=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),h=i(r),f=a,d=h["".concat(p,".").concat(f)]||h[f]||u[f]||n;return r?o.createElement(d,s(s({ref:t},l),{},{components:r})):o.createElement(d,s({ref:t},l))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var n=r.length,s=new Array(n);s[0]=f;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[h]="string"==typeof e?e:a,s[1]=c;for(var i=2;i=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),i=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},p=function(e){var t=i(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=i(a),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||o;return a?n.createElement(m,l(l({ref:t},p),{},{components:a})):n.createElement(m,l({ref:t},p))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,l=new Array(o);l[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,l[1]=s;for(var i=2;i=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),i=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},p=function(e){var t=i(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=i(a),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||o;return a?n.createElement(m,l(l({ref:t},p),{},{components:a})):n.createElement(m,l({ref:t},p))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,l=new Array(o);l[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,l[1]=s;for(var i=2;i=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),i=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):c(c({},t),e)),a},u=function(e){var t=i(e.components);return n.createElement(l.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),h=i(a),p=r,f=h["".concat(l,".").concat(p)]||h[p]||d[p]||o;return a?n.createElement(f,c(c({ref:t},u),{},{components:a})):n.createElement(f,c({ref:t},u))}));function f(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,c=new Array(o);c[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:r,c[1]=s;for(var i=2;i=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),i=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):c(c({},t),e)),a},u=function(e){var t=i(e.components);return n.createElement(l.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),h=i(a),p=r,f=h["".concat(l,".").concat(p)]||h[p]||d[p]||o;return a?n.createElement(f,c(c({ref:t},u),{},{components:a})):n.createElement(f,c({ref:t},u))}));function f(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,c=new Array(o);c[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:r,c[1]=s;for(var i=2;i=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),l=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=l(n),u=a,h=m["".concat(p,".").concat(u)]||m[u]||d[u]||o;return n?r.createElement(h,i(i({ref:t},c),{},{components:n})):r.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=u;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[m]="string"==typeof e?e:a,i[1]=s;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),l=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=l(n),u=a,h=m["".concat(p,".").concat(u)]||m[u]||d[u]||o;return n?r.createElement(h,i(i({ref:t},c),{},{components:n})):r.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=u;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[m]="string"==typeof e?e:a,i[1]=s;for(var l=2;l=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=r.createContext({}),c=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=c(e.components);return r.createElement(u.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(n),h=o,A=p["".concat(u,".").concat(h)]||p[h]||g[h]||i;return n?r.createElement(A,a(a({ref:t},l),{},{components:n})):r.createElement(A,a({ref:t},l))}));function A(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=h;var s={};for(var u in t)hasOwnProperty.call(t,u)&&(s[u]=t[u]);s.originalType=e,s[p]="string"==typeof e?e:o,a[1]=s;for(var c=2;c=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=r.createContext({}),c=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=c(e.components);return r.createElement(u.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(n),h=o,A=p["".concat(u,".").concat(h)]||p[h]||g[h]||i;return n?r.createElement(A,a(a({ref:t},l),{},{components:n})):r.createElement(A,a({ref:t},l))}));function A(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=h;var s={};for(var u in t)hasOwnProperty.call(t,u)&&(s[u]=t[u]);s.originalType=e,s[p]="string"==typeof e?e:o,a[1]=s;for(var c=2;c=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),p=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(r),m=a,f=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return r?n.createElement(f,i(i({ref:t},c),{},{components:r})):n.createElement(f,i({ref:t},c))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var p=2;p=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),p=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(r),m=a,f=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return r?n.createElement(f,i(i({ref:t},c),{},{components:r})):n.createElement(f,i({ref:t},c))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var p=2;p=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),l=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),d=l(n),h=r,y=d["".concat(s,".").concat(h)]||d[h]||u[h]||o;return n?a.createElement(y,i(i({ref:t},c),{},{components:n})):a.createElement(y,i({ref:t},c))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=h;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[d]="string"==typeof e?e:r,i[1]=p;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),l=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),d=l(n),h=r,y=d["".concat(s,".").concat(h)]||d[h]||u[h]||o;return n?a.createElement(y,i(i({ref:t},c),{},{components:n})):a.createElement(y,i({ref:t},c))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=h;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[d]="string"==typeof e?e:r,i[1]=p;for(var l=2;l=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var a=n.createContext({}),s=function(e){var t=n.useContext(a),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(a.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(r),h=o,d=p["".concat(a,".").concat(h)]||p[h]||f[h]||i;return r?n.createElement(d,c(c({ref:t},l),{},{components:r})):n.createElement(d,c({ref:t},l))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,c=new Array(i);c[0]=h;var u={};for(var a in t)hasOwnProperty.call(t,a)&&(u[a]=t[a]);u.originalType=e,u[p]="string"==typeof e?e:o,c[1]=u;for(var s=2;s=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var a=n.createContext({}),s=function(e){var t=n.useContext(a),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(a.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(r),h=o,d=p["".concat(a,".").concat(h)]||p[h]||f[h]||i;return r?n.createElement(d,c(c({ref:t},l),{},{components:r})):n.createElement(d,c({ref:t},l))}));function d(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,c=new Array(i);c[0]=h;var u={};for(var a in t)hasOwnProperty.call(t,a)&&(u[a]=t[a]);u.originalType=e,u[p]="string"==typeof e?e:o,c[1]=u;for(var s=2;s=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),h=c(a),u=i,m=h["".concat(l,".").concat(u)]||h[u]||d[u]||o;return a?n.createElement(m,r(r({ref:t},p),{},{components:a})):n.createElement(m,r({ref:t},p))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=a.length,r=new Array(o);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:i,r[1]=s;for(var c=2;cURefs",id:"execution-semantics-urefs",level:4},{value:"Accounts",id:"accounts-head",level:2},{value:"Creating an account",id:"accounts-creating",level:3},{value:"Permissions Model",id:"accounts-permissions",level:3},{value:"Actions and Thresholds",id:"accounts-actions-thresholds",level:4},{value:"Associated Keys and Weights",id:"accounts-associated-keys-weights",level:4},{value:"Key Management Actions",id:"accounts-key-management",level:4},{value:"Account security and recovery using key management",id:"accounts-recovery",level:4},{value:"The Account Context",id:"accounts-context",level:3},{value:"Unforgeable Reference (URef)",id:"uref-head",level:2},{value:"Permissions for URefs",id:"uref-permissions",level:3},{value:"URefs and Purses",id:"urefs-and-purses",level:3},{value:"Block Structure",id:"block-structure-head",level:2},{value:"Data Fields",id:"block-structure-data",level:3},{value:"block_hash",id:"block_hash",level:4},{value:"Header",id:"header",level:4},{value:"Body",id:"body",level:4},{value:"Tokens",id:"tokens-head",level:2},{value:"Token Generation and Distribution",id:"token-generation-and-distribution",level:3},{value:"Divisibility of Tokens",id:"tokens-divisibility",level:3},{value:"Purses and Accounts",id:"tokens-purses-and-accounts",level:3},{value:"The Casper Mint Contract",id:"mint-contract",level:3},{value:"The mint Contract Interface",id:"tokens-mint-interface",level:2}],d={toc:h},u="wrapper";function m(e){var t=e.components,s=(0,i.Z)(e,r);return(0,o.kt)(u,(0,n.Z)({},d,s,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"casper-network-design"},"Casper Network Design"),(0,o.kt)("h2",{id:"introduction"},"Introduction"),(0,o.kt)("p",null,"Casper is a Proof-of-Stake blockchain platform with an account-based model that performs execution after ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#consensus"},"consensus"),". A Casper network stores data in a structure known as ",(0,o.kt)("a",{parentName:"p",href:"/concepts/global-state"},"Global State"),". Users interact with global state through session code sent in a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/D#deploy"},"Deploy"),". Deploys contain ",(0,o.kt)("a",{parentName:"p",href:"https://webassembly.org/"},"Wasm")," to be executed by the network, thus allowing developers to use their preferred programming language rather than a proprietary language."),(0,o.kt)("p",null,"A deploy executes in the context of the user's ",(0,o.kt)("a",{parentName:"p",href:"#accounts-head"},"Account")," but can call stored Wasm that will execute in its own context. User-related information other than an account is stored in global state as an ",(0,o.kt)("a",{parentName:"p",href:"#uref-head"},"Unforgeable Reference")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),". After a node accepts a deploy as valid, it places the deploy in a proposed ",(0,o.kt)("a",{parentName:"p",href:"#block-structure-head"},"Block")," and gossips it among nodes until the network reaches consensus. At this point, the network executes the Wasm included within the deploy."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#execution-semantics-head"},"Execution Semantics"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#accounts-head"},"Accounts"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#uref-head"},"Unforgeable Reference (URef)"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#block-structure-head"},"Block Structure"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#tokens-head"},"Tokens")))),(0,o.kt)("h2",{id:"execution-semantics-head"},"Execution Semantics"),(0,o.kt)("p",null,"A Casper network is a decentralized computation platform. This section describes aspects of the Casper computational model."),(0,o.kt)("h3",{id:"execution-semantics-gas"},"Measuring Computational Work"),(0,o.kt)("p",null,"Computation is done in a ",(0,o.kt)("a",{parentName:"p",href:"https://webassembly.org/"},"WebAssembly (Wasm)")," interpreter, allowing any programming language which compiles to Wasm to become a smart contract language for the Casper blockchain. Similar to Ethereum, Casper uses ",(0,o.kt)("a",{parentName:"p",href:"/concepts/economics/gas-concepts"},(0,o.kt)("inlineCode",{parentName:"a"},"Gas"))," to measure computational work in a way that is consistent from node to node in a Casper network. Each Wasm opcode is assigned a ",(0,o.kt)("inlineCode",{parentName:"p"},"Gas")," cost, and the amount of gas spent is tracked by the runtime with each opcode executed by the interpreter."),(0,o.kt)("p",null,"Costs for opcode instructions on the Casper Mainnet network can be found ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/resources/production/chainspec.toml#L115"},"here"),"."),(0,o.kt)("p",null,"All executions are finite because each has a finite ",(0,o.kt)("em",{parentName:"p"},"gas limit")," that specifies the maximum amount of gas available to spend before the runtime terminates the computation. The payment executable session determines how to pay for the deploy. The gas limit is set by executing the payment code specified within the deploy."),(0,o.kt)("p",null,"Although the network measures costs in ",(0,o.kt)("inlineCode",{parentName:"p"},"Gas"),", payment for computation occurs in ",(0,o.kt)("a",{parentName:"p",href:"#tokens-divisibility"},"motes"),". Therefore, there is a conversion rate between ",(0,o.kt)("inlineCode",{parentName:"p"},"Gas")," and motes."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Please note that Casper will not refund any amount of unused gas."),(0,o.kt)("p",{parentName:"admonition"},"This decision is taken to incentivize the ",(0,o.kt)("a",{parentName:"p",href:"/runtime#runtime-economics"},"Casper Runtime Economics")," by efficiently allocating the computational resources. The ",(0,o.kt)("a",{parentName:"p",href:"/runtime#consensus-before-execution-basics-of-payment"},"consensus-before-execution model")," implements the mechanism to encourage the optimized gas consumption from users and to prevent the overuse of block space by poorly handled deploys.")),(0,o.kt)("h3",{id:"execution-semantics-runtime"},"The Casper Network Runtime"),(0,o.kt)("p",null,"A Wasm module is not natively able to create any effects outside of reading or writing from its own linear memory. Wasm modules must import functions from the host environment they are running in to enable other desired effects, such as reading or writing to global state."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Casper Network Runtime",src:a(7440).Z,width:"1220",height:"604"})),(0,o.kt)("p",null,"All these features are accessible via functions in the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/ext_ffi/index.html"},"Casper External FFI"),"."),(0,o.kt)("h4",{id:"execution-semantics-urefs"},"Generating ",(0,o.kt)("inlineCode",{parentName:"h4"},"URef"),"s"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s are generated using a ",(0,o.kt)("a",{parentName:"p",href:"https://rust-random.github.io/rand/rand_chacha/struct.ChaCha20Rng.html"},"cryptographically secure random number generator")," using the ",(0,o.kt)("a",{parentName:"p",href:"https://cr.yp.to/chacha.html"},"ChaCha algorithm"),". The random number generator is seeded by taking the ",(0,o.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the deploy hash concatenated with an index representing the current phase of execution (to prevent collisions between ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s generated in different phases of the same deploy)."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Generating URefs",src:a(4473).Z,width:"1121",height:"289"})),(0,o.kt)("h2",{id:"accounts-head"},"Accounts"),(0,o.kt)("p",null,"The Casper blockchain uses an on-chain account-based model, uniquely identified by an ",(0,o.kt)("inlineCode",{parentName:"p"},"AccountHash")," derived from a specific ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey"),". The ",(0,o.kt)("a",{parentName:"p",href:"#global-state-trie"},"global state trie store")," requires all keys to be the same length, so the AccountHash is a 32-byte derivative used to abstract any of the supported public key variants."),(0,o.kt)("p",null,"The Casper platform supports two types of keys for creating accounts and signing transactions:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/concepts/accounts-and-keys#eddsa-keys"},"Ed25519")," keys, which use the Edwards-curve Digital Signature Algorithm (EdDSA) and are 66 bytes long"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/concepts/accounts-and-keys#ecdsa-keys"},"Secp256k1")," keys, commonly known as Ethereum keys, which are 68 bytes long")),(0,o.kt)("p",null,'By default, a transactional interaction with the blockchain takes the form of a Deploy cryptographically signed by the key-pair corresponding to the PublicKey used to create the account. All user activity on the Casper blockchain (i.e., "deploys") must originate from an account. Each account has its own context where it can locally store information (e.g., references to useful contracts, metrics, and aggregated data from other parts of the blockchain). Each account also has a "main purse" where it can hold Casper tokens (see ',(0,o.kt)("a",{parentName:"p",href:"#tokens-purses-and-accounts"},"Tokens")," for more information)."),(0,o.kt)("p",null,"This chapter describes the permission model for accounts and their local storage capabilities and briefly mentions some runtime functions for interacting with accounts."),(0,o.kt)("h3",{id:"accounts-creating"},"Creating an account"),(0,o.kt)("p",null,"Account creation automatically happens upon transferring tokens to a yet unused ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey"),". On account creation, the balance of its main purse is equal to the number of tokens transferred during the creation process. Its action thresholds are equal to 1, and there is one associated key. The associated key is the ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey")," used to create the account. In this way, an account is essentially a context object encapsulating the main purse, used to pay for transactions. However, an account may have an additional purse beyond the main purse."),(0,o.kt)("p",{align:"center"},(0,o.kt)("img",{src:"/image/design/account-structure.png",alt:"Image showing the account data structure",width:"200"})),(0,o.kt)("p",null,"An ",(0,o.kt)("inlineCode",{parentName:"p"},"Account")," contains the following data:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A ",(0,o.kt)("inlineCode",{parentName:"li"},"URef"),' representing the account\'s "main purse"'),(0,o.kt)("li",{parentName:"ul"},"A collection of named keys (playing the same role as the named keys in a stored contract)"),(0,o.kt)("li",{parentName:"ul"},'A collection of "associated keys" (see ',(0,o.kt)("a",{parentName:"li",href:"#accounts-associated-keys-weights"},"below for more information"),")"),(0,o.kt)("li",{parentName:"ul"},'"Action thresholds" (see ',(0,o.kt)("a",{parentName:"li",href:"#accounts-actions-thresholds"},"below for more information"),")")),(0,o.kt)("h3",{id:"accounts-permissions"},"Permissions Model"),(0,o.kt)("h4",{id:"accounts-actions-thresholds"},"Actions and Thresholds"),(0,o.kt)("p",null,"An account can perform two types of actions: sending deploys and managing keys. A deploy is simply executing some code on the blockchain, while key management involves changing the associated keys (which will be described in more detail later). Key management cannot be performed independently, as all effects on the blockchain must come via a deploy; therefore, a key management action implies that a deploy action is also taking place."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"ActionThresholds")," contained in the ",(0,o.kt)("inlineCode",{parentName:"p"},"Account")," data structure set a ",(0,o.kt)("inlineCode",{parentName:"p"},"Weight"),", which must be met to perform that action. The next section describes these weight thresholds. Since a key management action requires a deploy action, the key management threshold should always be greater than or equal to the deploy threshold."),(0,o.kt)("h4",{id:"accounts-associated-keys-weights"},"Associated Keys and Weights"),(0,o.kt)("p",null,"Accounts on a Casper network can associate other key pairs through a multiple signature scheme for sending transactions. An account's ",(0,o.kt)("em",{parentName:"p"},"associated keys"),' are the set of public keys allowed to provide signatures on deploys for that account. Each associated key has a weight; these weights combine to meet the action thresholds provided in the previous section. Each deploy must be signed by one or more keys associated with the account that deploy is for, and the sum of the weights of those keys must be greater than or equal to the deployment threshold weight for that account. We call the keys that have signed a deploy the "authorizing keys". Similarly, if a deploy contains key management actions (detailed below), the sum of the weights of the authorizing keys must be greater than or equal to the key management action threshold of the account.'),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},'Any key may help authorize any action; there are no "special keys". All keys contribute their weight in exactly the same way.')),(0,o.kt)("h4",{id:"accounts-key-management"},"Key Management Actions"),(0,o.kt)("p",null,"A ",(0,o.kt)("em",{parentName:"p"},"key management action")," is a change to the account permissions, including:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Adding or removing an associated key"),(0,o.kt)("li",{parentName:"ul"},"Changing the weight of an associated key"),(0,o.kt)("li",{parentName:"ul"},"Changing the threshold of any action")),(0,o.kt)("p",null,"Key management actions have validity rules preventing users from locking themselves out of their accounts. For example, one can set a threshold, at most, the sum of the weights of all associated keys."),(0,o.kt)("h4",{id:"accounts-recovery"},"Account security and recovery using key management"),(0,o.kt)("p",null,"This permissions model's purpose is to keep accounts safe from lost or stolen keys while allowing the usage of modern mobile devices. For example, it may be convenient to sign deploys from a smartphone without worrying about the repercussions of losing the phone. The recommended setup is to have a low-weight key on the phone, enough for the deploy threshold but not enough for key management. If the phone is lost or stolen, a key management action using other associated keys from another device (e.g., a home computer) can be used to remove the lost associated key and add a key that resides on a replacement phone."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},'It is extremely important to ensure there will always be access to a sufficient number of keys to perform the key management action. Otherwise, future recovery will be impossible (Casper currently does not support "inactive recovery").')),(0,o.kt)("h3",{id:"accounts-context"},"The Account Context"),(0,o.kt)("p",null,"A deploy is a user request to perform some execution on the blockchain (see ",(0,o.kt)("a",{parentName:"p",href:"#execution-semantics-head"},"Execution Semantics"),' for more information). It contains "payment code" and "session code", which are references to stored on-chain contracts or Wasm to be executed. For executable Wasm, its execution and the logic therein occur within the context of the account signing the deploy. This means that the executing Wasm has access to the named keys and main purse of the account\'s context.'),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"In the case where there is a reference to stored on-chain Wasm (smart contracts), the execution of the on-chain Wasm will occur in its own separate runtime context. As a result, the stored Wasm will not have access to the named keys or main purse of the calling account.")),(0,o.kt)("h2",{id:"uref-head"},"Unforgeable Reference (URef)"),(0,o.kt)("p",null,"This key type is used for storing any value except ",(0,o.kt)("inlineCode",{parentName:"p"},"Account"),". Additionally, ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s used in Wasm carry permission information to prevent unauthorized usage of the value stored under the key. The runtime tracks this permission information. This means that if malicious Wasm attempts to produce a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),' with permissions that the Wasm does not have, the Wasm has attempted to "forge" the unforgeable reference, and the runtime will raise a forged ',(0,o.kt)("inlineCode",{parentName:"p"},"URef")," error. Permissions for a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," can be given across contract calls, allowing data stored under a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," to be shared in a controlled way. The 32-byte identifier representing the key is generated randomly by the runtime (see ",(0,o.kt)("a",{parentName:"p",href:"#execution-semantics-head"},"Execution Semantics")," for more information). The serialization for ",(0,o.kt)("inlineCode",{parentName:"p"},"Access Rights")," that define the permissions for ",(0,o.kt)("inlineCode",{parentName:"p"},"URefs")," is detailed in the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"CLValues")," section."),(0,o.kt)("h3",{id:"uref-permissions"},"Permissions for ",(0,o.kt)("inlineCode",{parentName:"h3"},"URef"),"s"),(0,o.kt)("p",null,"In the runtime, a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," carries its permissions called ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights"),". Additionally, the runtime tracks what ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights")," would be valid for each ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," in each context. The system assumes that a sent ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," is invalid, regardless of declared ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights"),", and will check it against the executing context to determine validity on each usage. Only the host logic can add a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),", in the following ways:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},'It can exist in a set of "known" ',(0,o.kt)("inlineCode",{parentName:"li"},"URef"),"s"),(0,o.kt)("li",{parentName:"ul"},"It can be freshly created by the runtime via the ",(0,o.kt)("inlineCode",{parentName:"li"},"new_uref")," function"),(0,o.kt)("li",{parentName:"ul"},"For called contracts, the caller can pass it in via the arguments to ",(0,o.kt)("inlineCode",{parentName:"li"},"call_contract")),(0,o.kt)("li",{parentName:"ul"},"It can be returned to the caller from ",(0,o.kt)("inlineCode",{parentName:"li"},"call_contract")," via the ",(0,o.kt)("inlineCode",{parentName:"li"},"ret")," function")),(0,o.kt)("p",null,"Note that only valid ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s may be added to the known ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s or cross-call boundaries; this means the system cannot be tricked into accepting a forged ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," by getting it through a contract or stashing it in the known ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s."),(0,o.kt)("p",null,"The ability to pass ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s between contexts via ",(0,o.kt)("inlineCode",{parentName:"p"},"call_contract")," / ",(0,o.kt)("inlineCode",{parentName:"p"},"ret"),", allows them to share state among a fixed number of parties while keeping it private from all others."),(0,o.kt)("h3",{id:"urefs-and-purses"},(0,o.kt)("inlineCode",{parentName:"h3"},"URef"),"s and Purses"),(0,o.kt)("p",null,"Purses represent a unique type of ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," used for accounting measures within a Casper network. ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s exist as a top-level entity, meaning that individual accounts do not own \u2018URef\u2019s. As described above, accounts and contracts possess certain ",(0,o.kt)("inlineCode",{parentName:"p"},"Access Rights"),", allowing them to interact with the given ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),". While an account will possess an associated ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," representing their main purse, this ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," exists as a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#clvalue-unit"},(0,o.kt)("inlineCode",{parentName:"a"},"Unit"))," and corresponds to a ",(0,o.kt)("em",{parentName:"p"},"balance")," key within the Casper ",(0,o.kt)("em",{parentName:"p"},"mint"),". The individual balance key within the Casper mint is the account's purse, with transfers authorized solely through the associated ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," and the ",(0,o.kt)("inlineCode",{parentName:"p"},"Access Rights")," granted to it."),(0,o.kt)("p",null,"Through this logic, the Casper mint holds all motes on the network and transfers between balance keys at the behest of accounts and contracts as required."),(0,o.kt)("h2",{id:"block-structure-head"},"Block Structure"),(0,o.kt)("p",null,"A ",(0,o.kt)("em",{parentName:"p"},"block")," is the primary data structure by which network nodes communicate information about the state of a Casper network. We briefly describe here the format of this data structure."),(0,o.kt)("h3",{id:"block-structure-data"},"Data Fields"),(0,o.kt)("p",null,"A block consists of the following:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A ",(0,o.kt)("inlineCode",{parentName:"li"},"block_hash")),(0,o.kt)("li",{parentName:"ul"},"A header"),(0,o.kt)("li",{parentName:"ul"},"A body")),(0,o.kt)("p",null,"Each of these fields is detailed in the subsequent sections."),(0,o.kt)("h4",{id:"block_hash"},(0,o.kt)("inlineCode",{parentName:"h4"},"block_hash")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"block_hash")," is the ",(0,o.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the block header."),(0,o.kt)("h4",{id:"header"},"Header"),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#serialization-standard-block"},"block header")," contains the following fields:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"parent_hash")),(0,o.kt)("p",{parentName:"li"},"A list of ",(0,o.kt)("inlineCode",{parentName:"p"},"block_hash"),"es giving the parents of the block.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"state_root_hash")),(0,o.kt)("p",{parentName:"li"},"The global state root hash produced by executing this block's body.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"body_hash")),(0,o.kt)("p",{parentName:"li"},"The hash of the block body.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"random_bit")),(0,o.kt)("p",{parentName:"li"},"A boolean needed for initializing a future era.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"accumulated_seed")),(0,o.kt)("p",{parentName:"li"},"A seed needed for initializing a future era.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"era_end")),(0,o.kt)("p",{parentName:"li"},"Contains equivocation and reward information to be included in the terminal finalized block. It is an optional field.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"timestamp")),(0,o.kt)("p",{parentName:"li"},"The timestamp from when the block was proposed.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"era_id")),(0,o.kt)("p",{parentName:"li"},"Era ID in which this block was created.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"height")),(0,o.kt)("p",{parentName:"li"},"The height of this block, i.e., the number of ancestors.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"protocol_version")),(0,o.kt)("p",{parentName:"li"},"The version of the Casper network when this block was proposed."))),(0,o.kt)("h4",{id:"body"},"Body"),(0,o.kt)("p",null,"The block body contains an ",(0,o.kt)("strong",{parentName:"p"},"ordered")," list of ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployHashes")," which refer to deploys, and an ",(0,o.kt)("strong",{parentName:"p"},"ordered")," list of ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployHashes")," for native transfers (which are specialized deploys that only transfer tokens between accounts). All deploys, including a specialization such as native transfer, can be broadly categorized as some unit of work that, when executed and committed, affect change to ",(0,o.kt)("a",{parentName:"p",href:"#global-state-intro"},"Global State"),". A valid block may contain no deploys and / or native transfers."),(0,o.kt)("p",null,"The block body also contains the public key of the validator that proposed the block."),(0,o.kt)("p",null,"Refer to the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"Serialization Standard")," for additional information on how blocks and deploy are serialized."),(0,o.kt)("h2",{id:"tokens-head"},"Tokens"),(0,o.kt)("p",null,"Casper is a decentralized Proof-of-Stake blockchain platform that uses a consensus algorithm called ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/highway"},"Highway"),". Having a unit of value is required to make this system work because users must pay for computation, and validators must have ",(0,o.kt)("a",{parentName:"p",href:"/staking"},"stake")," to bond. In the blockchain space, this unit of value is a ",(0,o.kt)("em",{parentName:"p"},"token"),"."),(0,o.kt)("p",null,"This chapter describes tokens and how one can use them on the Casper platform."),(0,o.kt)("h3",{id:"token-generation-and-distribution"},"Token Generation and Distribution"),(0,o.kt)("p",null,"A blockchain system generally needs a supply of tokens available to pay for computation and reward validators for processing transactions on the network. The initial supply at the launch of Mainnet was 10 billion CSPR. The current supply is available ",(0,o.kt)("a",{parentName:"p",href:"https://api.cspr.live/supply"},"here"),". In addition to the initial supply, the system will have a low rate of inflation, the results of which will be paid out to validators in the form of seigniorage."),(0,o.kt)("p",null,"The number of tokens used to calculate seigniorage is the initial supply of tokens at genesis."),(0,o.kt)("p",{align:"center"},(0,o.kt)("img",{src:"/image/design/token-lifecycle.png",alt:"Image showing the token lifecycle",width:"700"})),(0,o.kt)("h3",{id:"tokens-divisibility"},"Divisibility of Tokens"),(0,o.kt)("p",null,"Typically, a ",(0,o.kt)("em",{parentName:"p"},"token")," is divisible into some number of parts. We call the indivisible units which make up the CSPR token ",(0,o.kt)("em",{parentName:"p"},"motes"),". Each CSPR is divisible into 10",(0,o.kt)("sup",null,"9")," motes. To avoid rounding errors, it is essential to always represent token balances in motes. In comparison, Ether is divisible into 10",(0,o.kt)("sup",null,"18")," parts called Wei."),(0,o.kt)("p",null,"The concept of ",(0,o.kt)("inlineCode",{parentName:"p"},"CSPR")," is human-readable convenience and does not exist within the actual infrastructure of a Casper network. Instead, all transactions deal solely with ",(0,o.kt)("em",{parentName:"p"},"motes"),"."),(0,o.kt)("h3",{id:"tokens-purses-and-accounts"},"Purses and Accounts"),(0,o.kt)("p",null,"All ",(0,o.kt)("a",{parentName:"p",href:"#accounts-head"},"accounts")," on the Casper system have a purse associated with the Casper system mint, called the ",(0,o.kt)("em",{parentName:"p"},"main purse"),". However, for security reasons, the ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," of the main purse is only available to code running in the context of that account (i.e. only in payment or session code). Therefore, the mint's ",(0,o.kt)("inlineCode",{parentName:"p"},"transfer")," method that accepts ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s is not the most convenient when transferring between account main purses. For this reason, Casper supplies a ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_to_account.html"},"transfer_to_account")," function, which takes the public key used to derive the identity key of the account. This function uses the mint transfer function with the current account's main purse as the ",(0,o.kt)("inlineCode",{parentName:"p"},"source")," and the main purse of the account at the provided key as the ",(0,o.kt)("inlineCode",{parentName:"p"},"target"),"."),(0,o.kt)("h3",{id:"mint-contract"},"The Casper Mint Contract"),(0,o.kt)("p",null,"The Casper ",(0,o.kt)("em",{parentName:"p"},"mint")," is a system contract that manages the balance of ",(0,o.kt)("em",{parentName:"p"},"motes")," within a Casper network. These motes are used to pay for computation and bonding on the network. The mint system contract holds all motes on a Casper network but maintains an internal ledger of the balances for each Account's ",(0,o.kt)("em",{parentName:"p"},"main purse"),". Each balance is associated with a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),", which is a key to instruct the mint to perform actions on that balance (e.g., transfer motes). Informally, these balances are referred to as ",(0,o.kt)("em",{parentName:"p"},"purses")," and conceptually represent a container for motes. The ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," is how a purse is referenced externally, outside the mint."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights")," of the URefs permissions model determines what actions can be performed when using a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," associated with a purse."),(0,o.kt)("p",null,"As all ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s are unforgeable, the only way to interact with a purse is for a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," with appropriate ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights")," to be validly given to the current context."),(0,o.kt)("p",null,"The basic global state options map onto more standard monetary operations according to the table below:"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Global State"),(0,o.kt)("th",{parentName:"tr",align:null},"Action Monetary Action"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Add"),(0,o.kt)("td",{parentName:"tr",align:null},"Deposit (i.e. transfer to)")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Write"),(0,o.kt)("td",{parentName:"tr",align:null},"Withdraw (i.e. transfer from)")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Read"),(0,o.kt)("td",{parentName:"tr",align:null},"Balance check")))),(0,o.kt)("h2",{id:"tokens-mint-interface"},"The mint Contract Interface"),(0,o.kt)("p",null,"The mint system contract exposes the following methods:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer(source: URef, target: URef, amount: Motes) -> TransferResult"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"source")," must have at least ",(0,o.kt)("inlineCode",{parentName:"li"},"Write")," access rights, ",(0,o.kt)("inlineCode",{parentName:"li"},"target")," must have at least ",(0,o.kt)("inlineCode",{parentName:"li"},"Add")," access rights"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"TransferResult")," may be a success acknowledgment or an error in the case of invalid ",(0,o.kt)("inlineCode",{parentName:"li"},"source")," or ",(0,o.kt)("inlineCode",{parentName:"li"},"target")," or insufficient balance in the ",(0,o.kt)("inlineCode",{parentName:"li"},"source")," purse"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"mint(amount: Motes) -> MintResult"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"MintResult")," either gives the created ",(0,o.kt)("inlineCode",{parentName:"li"},"URef")," (with full access rights), which now has a balance equal to the given ",(0,o.kt)("inlineCode",{parentName:"li"},"amount"),"; or an error due to the minting of new motes not being allowed"),(0,o.kt)("li",{parentName:"ul"},"In the Casper mint, only the system account can call ",(0,o.kt)("inlineCode",{parentName:"li"},"mint"),", and it has no private key to produce valid cryptographic signatures, which means only the software itself can execute contracts in the context of the system account"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"create() -> URef"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"a convenience function for ",(0,o.kt)("inlineCode",{parentName:"li"},"mint(0)")," which cannot fail because it is always allowed to create an empty purse"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"balance(purse: URef) -> Option"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"purse")," must have at least ",(0,o.kt)("inlineCode",{parentName:"li"},"Read")," access rights"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"BalanceResult")," either returns the number of motes held by the ",(0,o.kt)("inlineCode",{parentName:"li"},"purse"),", or nothing if the ",(0,o.kt)("inlineCode",{parentName:"li"},"URef")," is not valid")))))}m.isMDXComponent=!0},7440:function(e,t,a){t.Z=a.p+"assets/images/casper-runtime-9bc2eb0948168ce8a2eef7f037af6ba4.png"},4473:function(e,t,a){t.Z=a.p+"assets/images/generating-urefs-af02bd8d865f5da9599a205bb682678e.png"}}]); \ No newline at end of file diff --git a/assets/js/11fbf07d.7996dc0e.js b/assets/js/11fbf07d.7996dc0e.js deleted file mode 100644 index 21f24e777a..0000000000 --- a/assets/js/11fbf07d.7996dc0e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1677],{3905:function(e,t,a){a.d(t,{Zo:function(){return p},kt:function(){return m}});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),h=c(a),u=i,m=h["".concat(l,".").concat(u)]||h[u]||d[u]||o;return a?n.createElement(m,r(r({ref:t},p),{},{components:a})):n.createElement(m,r({ref:t},p))}));function m(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=a.length,r=new Array(o);r[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:i,r[1]=s;for(var c=2;cURefs",id:"execution-semantics-urefs",level:4},{value:"Accounts",id:"accounts-head",level:2},{value:"Creating an account",id:"accounts-creating",level:3},{value:"Permissions Model",id:"accounts-permissions",level:3},{value:"Actions and Thresholds",id:"accounts-actions-thresholds",level:4},{value:"Associated Keys and Weights",id:"accounts-associated-keys-weights",level:4},{value:"Key Management Actions",id:"accounts-key-management",level:4},{value:"Account security and recovery using key management",id:"accounts-recovery",level:4},{value:"The Account Context",id:"accounts-context",level:3},{value:"Unforgeable Reference (URef)",id:"uref-head",level:2},{value:"Permissions for URefs",id:"uref-permissions",level:3},{value:"URefs and Purses",id:"urefs-and-purses",level:3},{value:"Block Structure",id:"block-structure-head",level:2},{value:"Data Fields",id:"block-structure-data",level:3},{value:"block_hash",id:"block_hash",level:4},{value:"Header",id:"header",level:4},{value:"Body",id:"body",level:4},{value:"Tokens",id:"tokens-head",level:2},{value:"Token Generation and Distribution",id:"token-generation-and-distribution",level:3},{value:"Divisibility of Tokens",id:"tokens-divisibility",level:3},{value:"Purses and Accounts",id:"tokens-purses-and-accounts",level:3},{value:"The Casper Mint Contract",id:"mint-contract",level:3},{value:"The mint Contract Interface",id:"tokens-mint-interface",level:2}],d={toc:h},u="wrapper";function m(e){var t=e.components,s=(0,i.Z)(e,r);return(0,o.kt)(u,(0,n.Z)({},d,s,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"casper-network-design"},"Casper Network Design"),(0,o.kt)("h2",{id:"introduction"},"Introduction"),(0,o.kt)("p",null,"Casper is a Proof-of-Stake blockchain platform with an account-based model that performs execution after ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#consensus"},"consensus"),". A Casper network stores data in a structure known as ",(0,o.kt)("a",{parentName:"p",href:"/concepts/global-state"},"Global State"),". Users interact with global state through session code sent in a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/D#deploy"},"Deploy"),". Deploys contain ",(0,o.kt)("a",{parentName:"p",href:"https://webassembly.org/"},"Wasm")," to be executed by the network, thus allowing developers to use their preferred programming language rather than a proprietary language."),(0,o.kt)("p",null,"A deploy executes in the context of the user's ",(0,o.kt)("a",{parentName:"p",href:"#accounts-head"},"Account")," but can call stored Wasm that will execute in its own context. User-related information other than an account is stored in global state as an ",(0,o.kt)("a",{parentName:"p",href:"#uref-head"},"Unforgeable Reference")," or ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),". After a node accepts a deploy as valid, it places the deploy in a proposed ",(0,o.kt)("a",{parentName:"p",href:"#block-structure-head"},"Block")," and gossips it among nodes until the network reaches consensus. At this point, the network executes the Wasm included within the deploy."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#execution-semantics-head"},"Execution Semantics"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#accounts-head"},"Accounts"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#uref-head"},"Unforgeable Reference (URef)"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#block-structure-head"},"Block Structure"))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("a",{parentName:"p",href:"#tokens-head"},"Tokens")))),(0,o.kt)("h2",{id:"execution-semantics-head"},"Execution Semantics"),(0,o.kt)("p",null,"A Casper network is a decentralized computation platform. This section describes aspects of the Casper computational model."),(0,o.kt)("h3",{id:"execution-semantics-gas"},"Measuring Computational Work"),(0,o.kt)("p",null,"Computation is done in a ",(0,o.kt)("a",{parentName:"p",href:"https://webassembly.org/"},"WebAssembly (Wasm)")," interpreter, allowing any programming language which compiles to Wasm to become a smart contract language for the Casper blockchain. Similar to Ethereum, Casper uses ",(0,o.kt)("a",{parentName:"p",href:"/concepts/economics/gas-concepts"},(0,o.kt)("inlineCode",{parentName:"a"},"Gas"))," to measure computational work in a way that is consistent from node to node in a Casper network. Each Wasm opcode is assigned a ",(0,o.kt)("inlineCode",{parentName:"p"},"Gas")," cost, and the amount of gas spent is tracked by the runtime with each opcode executed by the interpreter."),(0,o.kt)("p",null,"Costs for opcode instructions on the Casper Mainnet network can be found ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/resources/production/chainspec.toml#L115"},"here"),"."),(0,o.kt)("p",null,"All executions are finite because each has a finite ",(0,o.kt)("em",{parentName:"p"},"gas limit")," that specifies the maximum amount of gas available to spend before the runtime terminates the computation. The payment executable session determines how to pay for the deploy. The gas limit is set by executing the payment code specified within the deploy."),(0,o.kt)("p",null,"Although the network measures costs in ",(0,o.kt)("inlineCode",{parentName:"p"},"Gas"),", payment for computation occurs in ",(0,o.kt)("a",{parentName:"p",href:"#tokens-divisibility"},"motes"),". Therefore, there is a conversion rate between ",(0,o.kt)("inlineCode",{parentName:"p"},"Gas")," and motes."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Please note that Casper will not refund any amount of unused gas."),(0,o.kt)("p",{parentName:"admonition"},"This decision is taken to incentivize the ",(0,o.kt)("a",{parentName:"p",href:"/runtime#runtime-economics"},"Casper Runtime Economics")," by efficiently allocating the computational resources. The ",(0,o.kt)("a",{parentName:"p",href:"/runtime#consensus-before-execution-basics-of-payment"},"consensus-before-execution model")," implements the mechanism to encourage the optimized gas consumption from users and to prevent the overuse of block space by poorly handled deploys.")),(0,o.kt)("h3",{id:"execution-semantics-runtime"},"The Casper Network Runtime"),(0,o.kt)("p",null,"A Wasm module is not natively able to create any effects outside of reading or writing from its own linear memory. Wasm modules must import functions from the host environment they are running in to enable other desired effects, such as reading or writing to global state."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Casper Network Runtime",src:a(7440).Z,width:"1220",height:"604"})),(0,o.kt)("p",null,"All these features are accessible via functions in the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/ext_ffi/index.html"},"Casper External FFI"),"."),(0,o.kt)("h4",{id:"execution-semantics-urefs"},"Generating ",(0,o.kt)("inlineCode",{parentName:"h4"},"URef"),"s"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s are generated using a ",(0,o.kt)("a",{parentName:"p",href:"https://rust-random.github.io/rand/rand_chacha/struct.ChaCha20Rng.html"},"cryptographically secure random number generator")," using the ",(0,o.kt)("a",{parentName:"p",href:"https://cr.yp.to/chacha.html"},"ChaCha algorithm"),". The random number generator is seeded by taking the ",(0,o.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the deploy hash concatenated with an index representing the current phase of execution (to prevent collisions between ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s generated in different phases of the same deploy)."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"Generating URefs",src:a(4473).Z,width:"1121",height:"289"})),(0,o.kt)("h2",{id:"accounts-head"},"Accounts"),(0,o.kt)("p",null,"The Casper blockchain uses an on-chain account-based model, uniquely identified by an ",(0,o.kt)("inlineCode",{parentName:"p"},"AccountHash")," derived from a specific ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey"),". The ",(0,o.kt)("a",{parentName:"p",href:"#global-state-trie"},"global state trie store")," requires all keys to be the same length, so the AccountHash is a 32-byte derivative used to abstract any of the supported public key variants."),(0,o.kt)("p",null,"The Casper platform supports two types of keys for creating accounts and signing transactions:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/concepts/accounts-and-keys#eddsa-keys"},"Ed25519")," keys, which use the Edwards-curve Digital Signature Algorithm (EdDSA) and are 66 bytes long"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/concepts/accounts-and-keys#ecdsa-keys"},"Secp256k1")," keys, commonly known as Ethereum keys, which are 68 bytes long")),(0,o.kt)("p",null,'By default, a transactional interaction with the blockchain takes the form of a Deploy cryptographically signed by the key-pair corresponding to the PublicKey used to create the account. All user activity on the Casper blockchain (i.e., "deploys") must originate from an account. Each account has its own context where it can locally store information (e.g., references to useful contracts, metrics, and aggregated data from other parts of the blockchain). Each account also has a "main purse" where it can hold Casper tokens (see ',(0,o.kt)("a",{parentName:"p",href:"#tokens-purses-and-accounts"},"Tokens")," for more information)."),(0,o.kt)("p",null,"This chapter describes the permission model for accounts and their local storage capabilities and briefly mentions some runtime functions for interacting with accounts."),(0,o.kt)("h3",{id:"accounts-creating"},"Creating an account"),(0,o.kt)("p",null,"Account creation automatically happens upon transferring tokens to a yet unused ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey"),". On account creation, the balance of its main purse is equal to the number of tokens transferred during the creation process. Its action thresholds are equal to 1, and there is one associated key. The associated key is the ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey")," used to create the account. In this way, an account is essentially a context object encapsulating the main purse, used to pay for transactions. However, an account may have an additional purse beyond the main purse."),(0,o.kt)("p",{align:"center"},(0,o.kt)("img",{src:"/image/design/account-structure.png",alt:"Image showing the account data structure",width:"200"})),(0,o.kt)("p",null,"An ",(0,o.kt)("inlineCode",{parentName:"p"},"Account")," contains the following data:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A ",(0,o.kt)("inlineCode",{parentName:"li"},"URef"),' representing the account\'s "main purse"'),(0,o.kt)("li",{parentName:"ul"},"A collection of named keys (playing the same role as the named keys in a stored contract)"),(0,o.kt)("li",{parentName:"ul"},'A collection of "associated keys" (see ',(0,o.kt)("a",{parentName:"li",href:"#accounts-associated-keys-weights"},"below for more information"),")"),(0,o.kt)("li",{parentName:"ul"},'"Action thresholds" (see ',(0,o.kt)("a",{parentName:"li",href:"#accounts-actions-thresholds"},"below for more information"),")")),(0,o.kt)("h3",{id:"accounts-permissions"},"Permissions Model"),(0,o.kt)("h4",{id:"accounts-actions-thresholds"},"Actions and Thresholds"),(0,o.kt)("p",null,"An account can perform two types of actions: sending deploys and managing keys. A deploy is simply executing some code on the blockchain, while key management involves changing the associated keys (which will be described in more detail later). Key management cannot be performed independently, as all effects on the blockchain must come via a deploy; therefore, a key management action implies that a deploy action is also taking place."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"ActionThresholds")," contained in the ",(0,o.kt)("inlineCode",{parentName:"p"},"Account")," data structure set a ",(0,o.kt)("inlineCode",{parentName:"p"},"Weight"),", which must be met to perform that action. The next section describes these weight thresholds. Since a key management action requires a deploy action, the key management threshold should always be greater than or equal to the deploy threshold."),(0,o.kt)("h4",{id:"accounts-associated-keys-weights"},"Associated Keys and Weights"),(0,o.kt)("p",null,"Accounts on a Casper network can associate other key pairs through a multiple signature scheme for sending transactions. An account's ",(0,o.kt)("em",{parentName:"p"},"associated keys"),' are the set of public keys allowed to provide signatures on deploys for that account. Each associated key has a weight; these weights combine to meet the action thresholds provided in the previous section. Each deploy must be signed by one or more keys associated with the account that deploy is for, and the sum of the weights of those keys must be greater than or equal to the deployment threshold weight for that account. We call the keys that have signed a deploy the "authorizing keys". Similarly, if a deploy contains key management actions (detailed below), the sum of the weights of the authorizing keys must be greater than or equal to the key management action threshold of the account.'),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},'Any key may help authorize any action; there are no "special keys". All keys contribute their weight in exactly the same way.')),(0,o.kt)("h4",{id:"accounts-key-management"},"Key Management Actions"),(0,o.kt)("p",null,"A ",(0,o.kt)("em",{parentName:"p"},"key management action")," is a change to the account permissions, including:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Adding or removing an associated key"),(0,o.kt)("li",{parentName:"ul"},"Changing the weight of an associated key"),(0,o.kt)("li",{parentName:"ul"},"Changing the threshold of any action")),(0,o.kt)("p",null,"Key management actions have validity rules preventing users from locking themselves out of their accounts. For example, one can set a threshold, at most, the sum of the weights of all associated keys."),(0,o.kt)("h4",{id:"accounts-recovery"},"Account security and recovery using key management"),(0,o.kt)("p",null,"This permissions model's purpose is to keep accounts safe from lost or stolen keys while allowing the usage of modern mobile devices. For example, it may be convenient to sign deploys from a smartphone without worrying about the repercussions of losing the phone. The recommended setup is to have a low-weight key on the phone, enough for the deploy threshold but not enough for key management. If the phone is lost or stolen, a key management action using other associated keys from another device (e.g., a home computer) can be used to remove the lost associated key and add a key that resides on a replacement phone."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},'It is extremely important to ensure there will always be access to a sufficient number of keys to perform the key management action. Otherwise, future recovery will be impossible (Casper currently does not support "inactive recovery").')),(0,o.kt)("h3",{id:"accounts-context"},"The Account Context"),(0,o.kt)("p",null,"A deploy is a user request to perform some execution on the blockchain (see ",(0,o.kt)("a",{parentName:"p",href:"#execution-semantics-head"},"Execution Semantics"),' for more information). It contains "payment code" and "session code", which are references to stored on-chain contracts or Wasm to be executed. For executable Wasm, its execution and the logic therein occur within the context of the account signing the deploy. This means that the executing Wasm has access to the named keys and main purse of the account\'s context.'),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"In the case where there is a reference to stored on-chain Wasm (smart contracts), the execution of the on-chain Wasm will occur in its own separate runtime context. As a result, the stored Wasm will not have access to the named keys or main purse of the calling account.")),(0,o.kt)("h2",{id:"uref-head"},"Unforgeable Reference (URef)"),(0,o.kt)("p",null,"This key type is used for storing any value except ",(0,o.kt)("inlineCode",{parentName:"p"},"Account"),". Additionally, ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s used in Wasm carry permission information to prevent unauthorized usage of the value stored under the key. The runtime tracks this permission information. This means that if malicious Wasm attempts to produce a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),' with permissions that the Wasm does not have, the Wasm has attempted to "forge" the unforgeable reference, and the runtime will raise a forged ',(0,o.kt)("inlineCode",{parentName:"p"},"URef")," error. Permissions for a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," can be given across contract calls, allowing data stored under a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," to be shared in a controlled way. The 32-byte identifier representing the key is generated randomly by the runtime (see ",(0,o.kt)("a",{parentName:"p",href:"#execution-semantics-head"},"Execution Semantics")," for more information). The serialization for ",(0,o.kt)("inlineCode",{parentName:"p"},"Access Rights")," that define the permissions for ",(0,o.kt)("inlineCode",{parentName:"p"},"URefs")," is detailed in the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"CLValues")," section."),(0,o.kt)("h3",{id:"uref-permissions"},"Permissions for ",(0,o.kt)("inlineCode",{parentName:"h3"},"URef"),"s"),(0,o.kt)("p",null,"In the runtime, a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," carries its permissions called ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights"),". Additionally, the runtime tracks what ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights")," would be valid for each ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," in each context. The system assumes that a sent ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," is invalid, regardless of declared ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights"),", and will check it against the executing context to determine validity on each usage. Only the host logic can add a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),", in the following ways:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},'It can exist in a set of "known" ',(0,o.kt)("inlineCode",{parentName:"li"},"URef"),"s"),(0,o.kt)("li",{parentName:"ul"},"It can be freshly created by the runtime via the ",(0,o.kt)("inlineCode",{parentName:"li"},"new_uref")," function"),(0,o.kt)("li",{parentName:"ul"},"For called contracts, the caller can pass it in via the arguments to ",(0,o.kt)("inlineCode",{parentName:"li"},"call_contract")),(0,o.kt)("li",{parentName:"ul"},"It can be returned to the caller from ",(0,o.kt)("inlineCode",{parentName:"li"},"call_contract")," via the ",(0,o.kt)("inlineCode",{parentName:"li"},"ret")," function")),(0,o.kt)("p",null,"Note that only valid ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s may be added to the known ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s or cross-call boundaries; this means the system cannot be tricked into accepting a forged ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," by getting it through a contract or stashing it in the known ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s."),(0,o.kt)("p",null,"The ability to pass ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s between contexts via ",(0,o.kt)("inlineCode",{parentName:"p"},"call_contract")," / ",(0,o.kt)("inlineCode",{parentName:"p"},"ret"),", allows them to share state among a fixed number of parties while keeping it private from all others."),(0,o.kt)("h3",{id:"urefs-and-purses"},(0,o.kt)("inlineCode",{parentName:"h3"},"URef"),"s and Purses"),(0,o.kt)("p",null,"Purses represent a unique type of ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," used for accounting measures within a Casper network. ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s exist as a top-level entity, meaning that individual accounts do not own \u2018URef\u2019s. As described above, accounts and contracts possess certain ",(0,o.kt)("inlineCode",{parentName:"p"},"Access Rights"),", allowing them to interact with the given ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),". While an account will possess an associated ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," representing their main purse, this ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," exists as a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#clvalue-unit"},(0,o.kt)("inlineCode",{parentName:"a"},"Unit"))," and corresponds to a ",(0,o.kt)("em",{parentName:"p"},"balance")," key within the Casper ",(0,o.kt)("em",{parentName:"p"},"mint"),". The individual balance key within the Casper mint is the account's purse, with transfers authorized solely through the associated ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," and the ",(0,o.kt)("inlineCode",{parentName:"p"},"Access Rights")," granted to it."),(0,o.kt)("p",null,"Through this logic, the Casper mint holds all motes on the network and transfers between balance keys at the behest of accounts and contracts as required."),(0,o.kt)("h2",{id:"block-structure-head"},"Block Structure"),(0,o.kt)("p",null,"A ",(0,o.kt)("em",{parentName:"p"},"block")," is the primary data structure by which network nodes communicate information about the state of a Casper network. We briefly describe here the format of this data structure."),(0,o.kt)("h3",{id:"block-structure-data"},"Data Fields"),(0,o.kt)("p",null,"A block consists of the following:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"A ",(0,o.kt)("inlineCode",{parentName:"li"},"block_hash")),(0,o.kt)("li",{parentName:"ul"},"A header"),(0,o.kt)("li",{parentName:"ul"},"A body")),(0,o.kt)("p",null,"Each of these fields is detailed in the subsequent sections."),(0,o.kt)("h4",{id:"block_hash"},(0,o.kt)("inlineCode",{parentName:"h4"},"block_hash")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"block_hash")," is the ",(0,o.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the block header."),(0,o.kt)("h4",{id:"header"},"Header"),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#serialization-standard-block"},"block header")," contains the following fields:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"parent_hash")),(0,o.kt)("p",{parentName:"li"},"A list of ",(0,o.kt)("inlineCode",{parentName:"p"},"block_hash"),"es giving the parents of the block.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"state_root_hash")),(0,o.kt)("p",{parentName:"li"},"The global state root hash produced by executing this block's body.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"body_hash")),(0,o.kt)("p",{parentName:"li"},"The hash of the block body.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"random_bit")),(0,o.kt)("p",{parentName:"li"},"A boolean needed for initializing a future era.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"accumulated_seed")),(0,o.kt)("p",{parentName:"li"},"A seed needed for initializing a future era.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"era_end")),(0,o.kt)("p",{parentName:"li"},"Contains equivocation and reward information to be included in the terminal finalized block. It is an optional field.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"timestamp")),(0,o.kt)("p",{parentName:"li"},"The timestamp from when the block was proposed.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"era_id")),(0,o.kt)("p",{parentName:"li"},"Era ID in which this block was created.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"height")),(0,o.kt)("p",{parentName:"li"},"The height of this block, i.e., the number of ancestors.")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"protocol_version")),(0,o.kt)("p",{parentName:"li"},"The version of the Casper network when this block was proposed."))),(0,o.kt)("h4",{id:"body"},"Body"),(0,o.kt)("p",null,"The block body contains an ",(0,o.kt)("strong",{parentName:"p"},"ordered")," list of ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployHashes")," which refer to deploys, and an ",(0,o.kt)("strong",{parentName:"p"},"ordered")," list of ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployHashes")," for native transfers (which are specialized deploys that only transfer tokens between accounts). All deploys, including a specialization such as native transfer, can be broadly categorized as some unit of work that, when executed and committed, affect change to ",(0,o.kt)("a",{parentName:"p",href:"#global-state-intro"},"Global State"),". A valid block may contain no deploys and / or native transfers."),(0,o.kt)("p",null,"The block body also contains the public key of the validator that proposed the block."),(0,o.kt)("p",null,"Refer to the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"Serialization Standard")," for additional information on how blocks and deploy are serialized."),(0,o.kt)("h2",{id:"tokens-head"},"Tokens"),(0,o.kt)("p",null,"Casper is a decentralized Proof-of-Stake blockchain platform that uses a consensus algorithm called ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/highway"},"Highway"),". Having a unit of value is required to make this system work because users must pay for computation, and validators must have ",(0,o.kt)("a",{parentName:"p",href:"/staking"},"stake")," to bond. In the blockchain space, this unit of value is a ",(0,o.kt)("em",{parentName:"p"},"token"),"."),(0,o.kt)("p",null,"This chapter describes tokens and how one can use them on the Casper platform."),(0,o.kt)("h3",{id:"token-generation-and-distribution"},"Token Generation and Distribution"),(0,o.kt)("p",null,"A blockchain system generally needs a supply of tokens available to pay for computation and reward validators for processing transactions on the network. The initial supply at the launch of Mainnet was 10 billion CSPR. The current supply is available ",(0,o.kt)("a",{parentName:"p",href:"https://api.cspr.live/supply"},"here"),". In addition to the initial supply, the system will have a low rate of inflation, the results of which will be paid out to validators in the form of seigniorage."),(0,o.kt)("p",null,"The number of tokens used to calculate seigniorage is the initial supply of tokens at genesis."),(0,o.kt)("p",{align:"center"},(0,o.kt)("img",{src:"/image/design/token-lifecycle.png",alt:"Image showing the token lifecycle",width:"700"})),(0,o.kt)("h3",{id:"tokens-divisibility"},"Divisibility of Tokens"),(0,o.kt)("p",null,"Typically, a ",(0,o.kt)("em",{parentName:"p"},"token")," is divisible into some number of parts. We call the indivisible units which make up the CSPR token ",(0,o.kt)("em",{parentName:"p"},"motes"),". Each CSPR is divisible into 10",(0,o.kt)("sup",null,"9")," motes. To avoid rounding errors, it is essential to always represent token balances in motes. In comparison, Ether is divisible into 10",(0,o.kt)("sup",null,"18")," parts called Wei."),(0,o.kt)("p",null,"The concept of ",(0,o.kt)("inlineCode",{parentName:"p"},"CSPR")," is human-readable convenience and does not exist within the actual infrastructure of a Casper network. Instead, all transactions deal solely with ",(0,o.kt)("em",{parentName:"p"},"motes"),"."),(0,o.kt)("h3",{id:"tokens-purses-and-accounts"},"Purses and Accounts"),(0,o.kt)("p",null,"All ",(0,o.kt)("a",{parentName:"p",href:"#accounts-head"},"accounts")," on the Casper system have a purse associated with the Casper system mint, called the ",(0,o.kt)("em",{parentName:"p"},"main purse"),". However, for security reasons, the ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," of the main purse is only available to code running in the context of that account (i.e. only in payment or session code). Therefore, the mint's ",(0,o.kt)("inlineCode",{parentName:"p"},"transfer")," method that accepts ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s is not the most convenient when transferring between account main purses. For this reason, Casper supplies a ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_to_account.html"},"transfer_to_account")," function, which takes the public key used to derive the identity key of the account. This function uses the mint transfer function with the current account's main purse as the ",(0,o.kt)("inlineCode",{parentName:"p"},"source")," and the main purse of the account at the provided key as the ",(0,o.kt)("inlineCode",{parentName:"p"},"target"),"."),(0,o.kt)("h3",{id:"mint-contract"},"The Casper Mint Contract"),(0,o.kt)("p",null,"The Casper ",(0,o.kt)("em",{parentName:"p"},"mint")," is a system contract that manages the balance of ",(0,o.kt)("em",{parentName:"p"},"motes")," within a Casper network. These motes are used to pay for computation and bonding on the network. The mint system contract holds all motes on a Casper network but maintains an internal ledger of the balances for each Account's ",(0,o.kt)("em",{parentName:"p"},"main purse"),". Each balance is associated with a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),", which is a key to instruct the mint to perform actions on that balance (e.g., transfer motes). Informally, these balances are referred to as ",(0,o.kt)("em",{parentName:"p"},"purses")," and conceptually represent a container for motes. The ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," is how a purse is referenced externally, outside the mint."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights")," of the URefs permissions model determines what actions can be performed when using a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," associated with a purse."),(0,o.kt)("p",null,"As all ",(0,o.kt)("inlineCode",{parentName:"p"},"URef"),"s are unforgeable, the only way to interact with a purse is for a ",(0,o.kt)("inlineCode",{parentName:"p"},"URef")," with appropriate ",(0,o.kt)("inlineCode",{parentName:"p"},"AccessRights")," to be validly given to the current context."),(0,o.kt)("p",null,"The basic global state options map onto more standard monetary operations according to the table below:"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Global State"),(0,o.kt)("th",{parentName:"tr",align:null},"Action Monetary Action"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Add"),(0,o.kt)("td",{parentName:"tr",align:null},"Deposit (i.e. transfer to)")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Write"),(0,o.kt)("td",{parentName:"tr",align:null},"Withdraw (i.e. transfer from)")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Read"),(0,o.kt)("td",{parentName:"tr",align:null},"Balance check")))),(0,o.kt)("h2",{id:"tokens-mint-interface"},"The mint Contract Interface"),(0,o.kt)("p",null,"The mint system contract exposes the following methods:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer(source: URef, target: URef, amount: Motes) -> TransferResult"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"source")," must have at least ",(0,o.kt)("inlineCode",{parentName:"li"},"Write")," access rights, ",(0,o.kt)("inlineCode",{parentName:"li"},"target")," must have at least ",(0,o.kt)("inlineCode",{parentName:"li"},"Add")," access rights"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"TransferResult")," may be a success acknowledgment or an error in the case of invalid ",(0,o.kt)("inlineCode",{parentName:"li"},"source")," or ",(0,o.kt)("inlineCode",{parentName:"li"},"target")," or insufficient balance in the ",(0,o.kt)("inlineCode",{parentName:"li"},"source")," purse"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"mint(amount: Motes) -> MintResult"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"MintResult")," either gives the created ",(0,o.kt)("inlineCode",{parentName:"li"},"URef")," (with full access rights), which now has a balance equal to the given ",(0,o.kt)("inlineCode",{parentName:"li"},"amount"),"; or an error due to the minting of new motes not being allowed"),(0,o.kt)("li",{parentName:"ul"},"In the Casper mint, only the system account can call ",(0,o.kt)("inlineCode",{parentName:"li"},"mint"),", and it has no private key to produce valid cryptographic signatures, which means only the software itself can execute contracts in the context of the system account"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"create() -> URef"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"a convenience function for ",(0,o.kt)("inlineCode",{parentName:"li"},"mint(0)")," which cannot fail because it is always allowed to create an empty purse"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"balance(purse: URef) -> Option"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"purse")," must have at least ",(0,o.kt)("inlineCode",{parentName:"li"},"Read")," access rights"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"BalanceResult")," either returns the number of motes held by the ",(0,o.kt)("inlineCode",{parentName:"li"},"purse"),", or nothing if the ",(0,o.kt)("inlineCode",{parentName:"li"},"URef")," is not valid")))))}m.isMDXComponent=!0},7440:function(e,t,a){t.Z=a.p+"assets/images/casper-runtime-9bc2eb0948168ce8a2eef7f037af6ba4.png"},4473:function(e,t,a){t.Z=a.p+"assets/images/generating-urefs-af02bd8d865f5da9599a205bb682678e.png"}}]); \ No newline at end of file diff --git a/assets/js/14c517c6.1da3d9fd.js b/assets/js/14c517c6.1da3d9fd.js deleted file mode 100644 index f9d6321309..0000000000 --- a/assets/js/14c517c6.1da3d9fd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7378],{3905:function(e,t,r){r.d(t,{Zo:function(){return u},kt:function(){return m}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(r),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return r?n.createElement(h,s(s({ref:t},c),{},{components:r})):n.createElement(h,s({ref:t},c))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:a,s[1]=i;for(var p=2;p=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(r),m=a,h=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return r?n.createElement(h,s(s({ref:t},c),{},{components:r})):n.createElement(h,s({ref:t},c))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:a,s[1]=i;for(var p=2;p=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=c(n),m=o,h=p["".concat(l,".").concat(m)]||p[m]||u[m]||r;return n?a.createElement(h,i(i({ref:t},d),{},{components:n})):a.createElement(h,i({ref:t},d))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var c=2;c \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point withdraw_bid \\\n--session-arg=\"public_key:public_key=''\" \\\n--session-arg=\"amount:u512=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entrypoint that will be used when calling the contract")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid")," entry point expects two arguments, while the third one is optional:"),(0,r.kt)("ol",{start:7},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"public key"),": The hexadecimal public key of the account's purse to withdraw. This key must match the secret key that signs the deploy and has to match the public key of a bid in the auction contract"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The amount being withdrawn")),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid")," entry point on the auction contract has a fixed cost of 2.5 CSPR.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example command uses the Casper Testnet to withdraw 5 CSPR from the bid:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point withdraw_bid \\\n--session-arg \"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg \"amount:U512='$[5 * 1000000000]'\"\n")),(0,r.kt)("p",null,"Below is the same command with the optional purse set to a different purse where the amount will be returned. ",(0,r.kt)("strong",{parentName:"p"},"Adjust all the values to your use case.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point withdraw_bid \\\n--session-arg \"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg \"amount:U512='$[5 * 1000000000]'\"\n")),(0,r.kt)("h2",{id:"withdraw-compiled-wasm"},"Method 2: Unbonding with Compiled Wasm"),(0,r.kt)("p",null,"There is a second way to withdraw a bid, using the compiled Wasm ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid.wasm"),". The process is the same as bonding but uses a different contract."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path /casper-node/target/wasm32-unknown-unknown/release/withdraw_bid.wasm \\\n--session-arg=\"public_key:public_key=''\" \\\n--session-arg=\"amount:u512=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes estimated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the compiled Wasm on your computer")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid.wasm")," expects two arguments, while the third one is optional:"),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"public key"),": The hexadecimal public key of the account's purse to withdraw. This key must match the secret key that signs the deploy and has to match the public key of a bid in the auction contract"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The amount being withdrawn")),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"This method is more expensive than calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid")," entrypoint in the system auction contract, which has a fixed cost of 2.5 CSPR.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"Here is an example request to unbond stake using the ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid.wasm"),". The payment amount specified is 4 CSPR. You must modify the payment and other values in the deploy based on the network's ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--session-path $HOME/casper-node/target/wasm32-unknown-unknown/release/withdraw_bid.wasm \\\n--payment-amount 4000000000 \\\n--session-arg=\"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg=\"amount:u512='1000000000000'\"\n")),(0,r.kt)("h2",{id:"check-the-auction-contract"},"Check the Auction Contract"),(0,r.kt)("p",null,"Check the auction contract for updates to the bid amounts."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info --node-address http://\n")),(0,r.kt)("h2",{id:"unbonding-wait-period"},"Unbonding Wait Period"),(0,r.kt)("p",null,"To prevent long-range attacks, requests to unbond must go through a mandatory wait period, currently set to 7 eras lasting approximately 14-16 hours."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/19dcc625.ad773672.js b/assets/js/19dcc625.ad773672.js new file mode 100644 index 0000000000..38166cba4f --- /dev/null +++ b/assets/js/19dcc625.ad773672.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7925],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return h}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=c(n),m=o,h=p["".concat(l,".").concat(m)]||p[m]||u[m]||r;return n?a.createElement(h,i(i({ref:t},d),{},{components:n})):a.createElement(h,i({ref:t},d))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var c=2;c \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point withdraw_bid \\\n--session-arg=\"public_key:public_key=''\" \\\n--session-arg=\"amount:u512=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entrypoint that will be used when calling the contract")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid")," entry point expects two arguments, while the third one is optional:"),(0,r.kt)("ol",{start:7},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"public key"),": The hexadecimal public key of the account's purse to withdraw. This key must match the secret key that signs the deploy and has to match the public key of a bid in the auction contract"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The amount being withdrawn")),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid")," entry point on the auction contract has a fixed cost of 2.5 CSPR.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example command uses the Casper Testnet to withdraw 5 CSPR from the bid:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point withdraw_bid \\\n--session-arg \"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg \"amount:U512='$[5 * 1000000000]'\"\n")),(0,r.kt)("p",null,"Below is the same command with the optional purse set to a different purse where the amount will be returned. ",(0,r.kt)("strong",{parentName:"p"},"Adjust all the values to your use case.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point withdraw_bid \\\n--session-arg \"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg \"amount:U512='$[5 * 1000000000]'\"\n")),(0,r.kt)("h2",{id:"withdraw-compiled-wasm"},"Method 2: Unbonding with Compiled Wasm"),(0,r.kt)("p",null,"There is a second way to withdraw a bid, using the compiled Wasm ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid.wasm"),". The process is the same as bonding but uses a different contract."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path /casper-node/target/wasm32-unknown-unknown/release/withdraw_bid.wasm \\\n--session-arg=\"public_key:public_key=''\" \\\n--session-arg=\"amount:u512=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes estimated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the compiled Wasm on your computer")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid.wasm")," expects two arguments, while the third one is optional:"),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"public key"),": The hexadecimal public key of the account's purse to withdraw. This key must match the secret key that signs the deploy and has to match the public key of a bid in the auction contract"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The amount being withdrawn")),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"This method is more expensive than calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid")," entrypoint in the system auction contract, which has a fixed cost of 2.5 CSPR.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"Here is an example request to unbond stake using the ",(0,r.kt)("inlineCode",{parentName:"p"},"withdraw_bid.wasm"),". The payment amount specified is 4 CSPR. You must modify the payment and other values in the deploy based on the network's ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--session-path $HOME/casper-node/target/wasm32-unknown-unknown/release/withdraw_bid.wasm \\\n--payment-amount 4000000000 \\\n--session-arg=\"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg=\"amount:u512='1000000000000'\"\n")),(0,r.kt)("h2",{id:"check-the-auction-contract"},"Check the Auction Contract"),(0,r.kt)("p",null,"Check the auction contract for updates to the bid amounts."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info --node-address http://\n")),(0,r.kt)("h2",{id:"unbonding-wait-period"},"Unbonding Wait Period"),(0,r.kt)("p",null,"To prevent long-range attacks, requests to unbond must go through a mandatory wait period, currently set to 7 eras lasting approximately 14-16 hours."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1afb40fe.b74d0572.js b/assets/js/1afb40fe.b74d0572.js new file mode 100644 index 0000000000..bad23caac7 --- /dev/null +++ b/assets/js/1afb40fe.b74d0572.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[870],{3905:function(e,t,a){a.d(t,{Zo:function(){return s},kt:function(){return u}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function d(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var i=n.createContext({}),o=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):d(d({},t),e)),a},s=function(e){var t=o(e.components);return n.createElement(i.Provider,{value:t},e.children)},p="mdxType",b={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=o(a),f=r,u=p["".concat(i,".").concat(f)]||p[f]||b[f]||l;return a?n.createElement(u,d(d({ref:t},s),{},{components:a})):n.createElement(u,d({ref:t},s))}));function u(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,d=new Array(l);d[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[p]="string"==typeof e?e:r,d[1]=c;for(var o=2;ochain_get_block_result",id:"chain_get_block_result",level:3},{value:"chain_get_block_transfers",id:"chain-get-block-transfers",level:2},{value:"chain_get_block_transfers_result",id:"chain_get_block_transfers_result",level:3},{value:"chain_get_era_summary",id:"chain-get-era-summary",level:2},{value:"chain_get_era_summary_result",id:"chain_get_era_summary_result",level:3},{value:"chain_get_state_root_hash",id:"chain-get-state-root-hash",level:2},{value:"chain_get_state_root_hash_result",id:"chain_get_state_root_hash_result",level:3},{value:"info_get_chainspec",id:"info-get-chainspec",level:2},{value:"info_get_chainspec_result",id:"info_get_chainspec_result",level:3},{value:"info_get_deploy",id:"info-get-deploy",level:2},{value:"info_get_deploy_result",id:"info_get_deploy_result",level:3},{value:"query_balance",id:"query-balance",level:2},{value:"query_balance_result",id:"query_balance_result",level:3},{value:"query_global_state",id:"query-global-state",level:2},{value:"query_global_state_result",id:"query_global_state_result",level:3},{value:"state_get_account_info",id:"state-get-account-info",level:2},{value:"state_get_account_info_result",id:"state_get_account_info_result",level:3},{value:"state_get_dictionary_item",id:"state-get-dictionary-item",level:2},{value:"info_get_peers",id:"info-get-peers",level:2},{value:"info_get_peers_result",id:"info_get_peers_result",level:3},{value:"info_get_status",id:"info-get-status",level:2},{value:"info_get_status_result",id:"info_get_status_result",level:3}],b={toc:p},f="wrapper";function u(e){var t=e.components,a=(0,r.Z)(e,d);return(0,l.kt)(f,(0,n.Z)({},b,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"informational"},"Informational JSON-RPC Methods"),(0,l.kt)("p",null,"The following methods return information from a node on a Casper network. The response should be identical, regardless of the node queried, as the information in question is objective and common to all nodes within a network."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"chain-get-block"},"chain_get_block"),(0,l.kt)("p",null,"This method returns the JSON representation of a ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"Block")," from the network."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash or the Block height.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_block request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "chain_get_block",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_block_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_block_result")),(0,l.kt)("p",null,"The result from ",(0,l.kt)("inlineCode",{parentName:"p"},"chain_get_block")," depends on block availability from a given node. If ",(0,l.kt)("inlineCode",{parentName:"p"},"chain_get_block")," returns an error message that the node does not have information on the given block, you may attempt to get the information from a different node."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#jsonblock"},"block")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block, if found. (Not required)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_block result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block": {\n "body": {\n "deploy_hashes": [],\n "proposer": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "transfer_hashes": [\n "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa"\n ]\n },\n "hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "header": {\n "accumulated_seed": "ac979f51525cfd979b14aa7dc0737c5154eabe0db9280eceaa8dc8d2905b20d5",\n "body_hash": "cd502c5393a3c8b66d6979ad7857507c9baf5a8ba16ba99c28378d3a970fff42",\n "era_end": {\n "era_report": {\n "equivocators": [\n "013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"\n ],\n "inactive_validators": [\n "018139770ea87d175f56a35466c34c7ecccb8d8a91b4ee37a25df60f5b8fc9b394"\n ],\n "rewards": [\n {\n "amount": 1000,\n "validator": "018a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c"\n }\n ]\n },\n "next_era_validator_weights": [\n {\n "validator": "016e7a1cdd29b0b78fd13af4c5598feff4ef2a97166e3ca6f2e4fbfccd80505bf1",\n "weight": "456"\n },\n {\n "validator": "018a875fff1eb38451577acd5afee405456568dd7c89e090863a0557bc7af49f17",\n "weight": "789"\n },\n {\n "validator": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "weight": "123"\n }\n ]\n },\n "era_id": 1,\n "height": 10,\n "parent_hash": "0707070707070707070707070707070707070707070707070707070707070707",\n "protocol_version": "1.0.0",\n "random_bit": true,\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",\n "timestamp": "2020-11-17T00:39:24.072Z"\n },\n "proofs": [\n {\n "public_key": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "signature": "016291a7b2689e2edcc6e79030be50edd02f9bd7d809921ae2654012f808c7b9a0f125bc32d6aa610cbd012395a9832ccfaa9262023339f1db71ca073a13bb9707"\n }\n ]\n }\n }\n}\n\n'))),(0,l.kt)("h2",{id:"chain-get-block-transfers"},"chain_get_block_transfers"),(0,l.kt)("p",null,"This method returns all ",(0,l.kt)("strong",{parentName:"p"},"successful")," native transfers within a given ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"Block")," from a network."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_block_transfers request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "chain_get_block_transfers",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_block_transfers_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_block_transfers_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockhash"},"block_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash, if found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#transfer"},"transfers")),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block's successful transfers, if found.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_block_transfers result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "transfers": [\n {\n "amount": "0",\n "deploy_hash": "0000000000000000000000000000000000000000000000000000000000000000",\n "from": "account-hash-0000000000000000000000000000000000000000000000000000000000000000",\n "gas": "0",\n "id": null,\n "source": "uref-0000000000000000000000000000000000000000000000000000000000000000-000",\n "target": "uref-0000000000000000000000000000000000000000000000000000000000000000-000",\n "to": null\n }\n ]\n }\n}\n\n'))),(0,l.kt)("h2",{id:"chain-get-era-summary"},"chain_get_era_summary"),(0,l.kt)("p",null,"This method returns the era summary at a given ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"Block"),". If you do not specify a ",(0,l.kt)("inlineCode",{parentName:"p"},"block_identifier"),", you will receive the era summary at the highest state root hash."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash. (Optional)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_era_summary request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc":"2.0",\n "method":"chain_get_era_summary",\n "params": [\n {\n "Hash":"9bfa58709058935882a095ca6adf844b72a2ddf0f49b8575ef1ceda987452fb8"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_era_summary_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_era_summary_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#erasummary"},"era_summary")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The era summary (if found).")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_era_summary result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "id": 1,\n "result": {\n "api_version": "1.0.0",\n "era_summary": {\n "block_hash": "9bfa58709058935882a095ca6adf844b72a2ddf0f49b8575ef1ceda987452fb8",\n "era_id": 1,\n "stored_value": {\n "EraInfo": {\n "seigniorage_allocations": [\n {\n "Delegator": {\n "delegator_public_key": "01c08939bf1ecd1139448d435989a761c975466d30b96c2dd74e9d23c7b12bc9ff",\n "validator_public_key": "01039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b",\n "amount": "53472520551166781393617756"\n }\n },\n {\n "Validator": {\n "validator_public_key": "01039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b",\n "amount": "54552773491594393138943367"\n }\n },\n {\n "Delegator": {\n "delegator_public_key": "01264689a5b4c57dac1088cd0aae8074de105f2269f6041e2c120e80df7a95e6b5",\n "validator_public_key": "013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c18726",\n "amount": "51312014670568117976319374"\n }\n },\n {\n "Validator": {\n "validator_public_key": "013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c18726",\n "amount": "56713279372733183026458256"\n }\n },\n {\n "Delegator": {\n "delegator_public_key": "016f571eaf1d3a442e684ecdb31d00a51448dcbaa06d00b340983311f0ba3e76db",\n "validator_public_key": "0186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f12",\n "amount": "51852141140784624481333262"\n }\n },\n {\n "Validator": {\n "validator_public_key": "0186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f12",\n "amount": "56173152902516676521444368"\n }\n },\n {\n "Delegator": {\n "delegator_public_key": "0161e7ed5c592f16b507b9dd196662b530f9bde6c5b2cfd957fe8d0700ecfbe20b",\n "validator_public_key": "01d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b",\n "amount": "52392267611001130986347150"\n }\n },\n {\n "Validator": {\n "validator_public_key": "01d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b",\n "amount": "55633026432300170016430480"\n }\n },\n {\n "Delegator": {\n "delegator_public_key": "01b1339a1d114036d84d7b65c804669166d38456114657abbb0e53e67bf1667c60",\n "validator_public_key": "01dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f",\n "amount": "52932394080952975520954950"\n }\n },\n {\n "Validator": {\n "validator_public_key": "01dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f",\n "amount": "55092899961808199011606173"\n }\n }\n ]\n }\n },\n "state_root_hash": "918abd1973171867e03c1e6e56fd7dd9da35c92461784f9a15c0df23e437d850",\n "merkle_proof": "010000000e0000000000000000000000000000000000000000000000000000000000000000070a0000000101c08939bf1ecd1139448d435989a761c975466d30b96c2dd74e9d23c7b12bc9ff01039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b0b5c4316483512c2253f3b2c0001039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b0b87d59268bf17d8c6ff1f2d0101264689a5b4c57dac1088cd0aae8074de105f2269f6041e2c120e80df7a95e6b5013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c187260b8e45261378f096e3bd712a00013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c187260b90eee69bba24050981e92e01016f571eaf1d3a442e684ecdb31d00a51448dcbaa06d00b340983311f0ba3e76db0186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f120b0ef09fedb1f521341ee42a000186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f120b10446dc1801f7ab820772e010161e7ed5c592f16b507b9dd196662b530f9bde6c5b2cfd957fe8d0700ecfbe20b01d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b0b8e9a19c8ebfaac847e562b0001d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b0b9099f3e6461aef67c0042e0101b1339a1d114036d84d7b65c804669166d38456114657abbb0e53e67bf1667c6001dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f0b46fad737700f37d5dec82b0001dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f0b9d1ed178841a631760922d01000000000e060000000001fb7043fe388fef916937aa899a0dda9b042168149e600fb068ecb16839d545d60101a0676758b903440b28c8f4a1d46404e9879fcfc0b90dad20962536de493aecc302013584bc9d5c00ac639fe14410b4cfa480b12eddd8f3dce08d7b76ae47977c1c680601664224aca1272e2a5632da4a56399dee6c585318ebbb7bb4040039792d3ad33c07013b48237cd26eb35ec3c864e1ae250ca656d00893de1dfc4c951e0d779adeda1d0a002c722cac61792676eb19d773fd3c41e37a63f54f78bdf7712ca96a5c5e5c4986"\n }\n }\n}\n\n'))),(0,l.kt)("h2",{id:"chain-get-state-root-hash"},"chain_get_state_root_hash"),(0,l.kt)("p",null,"This method returns a state root hash at a given ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"Block"),". If you do not specify a ",(0,l.kt)("inlineCode",{parentName:"p"},"block_identifier"),", you will receive the highest state root hash."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash. (Optional)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_state_root_hash request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "chain_get_state_root_hash",\n "params": [\n {\n "Height": 10\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_state_root_hash_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_state_root_hash_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#digest"},"state_root_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"Hex-encoded hash of the state root.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_state_root_hash result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808"\n }\n}\n\n'))),(0,l.kt)("h2",{id:"info-get-chainspec"},"info_get_chainspec"),(0,l.kt)("p",null,"This method returns raw bytes for chainspec files."),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_chainspec request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "method": "info_get_chainspec",\n "id": 5510244237763930243\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_chainspec_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_chainspec_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#ChainspecRawBytes"},"chainspec_bytes")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The raw bytes of the chainspec.toml, genesis accounts.toml, and global_state.toml files.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_chainspec result"),(0,l.kt)("p",null,"Please note that adding a ",(0,l.kt)("inlineCode",{parentName:"p"},"--vv")," flag will return the full chainspec bytes."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.5.0",\n "chainspec_bytes": {\n "chainspec_bytes": "[22040 hex chars]",\n "maybe_genesis_accounts_bytes": null,\n "maybe_global_state_bytes": null\n }\n },\n "id": 5510244237763930243\n}\n\n'))),(0,l.kt)("h2",{id:"info-get-deploy"},"info_get_deploy"),(0,l.kt)("p",null,"This method retrieves a ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#execution-semantics-deploys"},"Deploy")," from a network. It requires a ",(0,l.kt)("inlineCode",{parentName:"p"},"deploy_hash")," to query the Deploy."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deployhash"},"deploy_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The Deploy hash.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#finalizedapprovals"},"finalized_approvals")),(0,l.kt)("td",{parentName:"tr",align:null},"Boolean"),(0,l.kt)("td",{parentName:"tr",align:null},"Determines whether to return the Deploy with the finalized approvals substituted. (Optional)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_deploy request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "info_get_deploy",\n "params": [\n "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa",\n true\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_deploy_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_deploy_result")),(0,l.kt)("p",null,"The response contains the Deploy and the results of executing the Deploy."),(0,l.kt)("p",null,"If the ",(0,l.kt)("inlineCode",{parentName:"p"},"execution_results")," field is empty, it means that the network processed the ",(0,l.kt)("inlineCode",{parentName:"p"},"Deploy"),", but has yet to execute it. If the network executed the ",(0,l.kt)("inlineCode",{parentName:"p"},"Deploy"),", it will return the results of the execution. The execution results contain the Block hash which contains the Deploy."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deploy"},"deploy")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Deploy.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#jsonexecutionresult"},"execution_results")),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"An array of execution results with Block hashes.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_deploy result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy": {\n "approvals": [\n {\n "signature": "014c1a89f92e29dd74fc648f741137d9caf4edba97c5f9799ce0c9aa6b0c9b58db368c64098603dbecef645774c05dff057cb1f91f2cf390bbacce78aa6f084007",\n "signer": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c"\n }\n ],\n "hash": "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa",\n "header": {\n "account": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "body_hash": "d53cf72d17278fd47d399013ca389c50d589352f1a12593c0b8e01872a641b50",\n "chain_name": "casper-example",\n "dependencies": [\n "0101010101010101010101010101010101010101010101010101010101010101"\n ],\n "gas_price": 1,\n "timestamp": "2020-11-17T00:39:24.072Z",\n "ttl": "1h"\n },\n "payment": {\n "StoredContractByName": {\n "args": [\n [\n "amount",\n {\n "bytes": "e8030000",\n "cl_type": "I32",\n "parsed": 1000\n }\n ]\n ],\n "entry_point": "example-entry-point",\n "name": "casper-example"\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "bytes": "e8030000",\n "cl_type": "I32",\n "parsed": 1000\n }\n ]\n ]\n }\n }\n },\n "execution_results": [\n {\n "block_hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "result": {\n "Success": {\n "cost": "123456",\n "effect": {\n "operations": [\n {\n "key": "account-hash-2c4a11c062a8a337bfc97e27fd66291caeb2c65865dcb5d3ef3759c4c97efecb",\n "kind": "Write"\n },\n {\n "key": "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1",\n "kind": "Read"\n }\n ],\n "transforms": [\n {\n "key": "uref-2c4a11c062a8a337bfc97e27fd66291caeb2c65865dcb5d3ef3759c4c97efecb-007",\n "transform": {\n "AddUInt64": 8\n }\n },\n {\n "key": "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1",\n "transform": "Identity"\n }\n ]\n },\n "transfers": [\n "transfer-5959595959595959595959595959595959595959595959595959595959595959",\n "transfer-8282828282828282828282828282828282828282828282828282828282828282"\n ]\n }\n }\n }\n ]\n }\n}\n\n'))),(0,l.kt)("h2",{id:"query-balance"},"query_balance"),(0,l.kt)("p",null,"This method allows you to query for the balance of a purse using a ",(0,l.kt)("inlineCode",{parentName:"p"},"PurseIdentifier")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"StateIdentifier"),"."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#purseidentifier"},"purse_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The identifier to obtain the purse corresponding to the balance query.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#globalstateidentifier"},"state_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The state identifier used for the query; if none is passed the tip of the chain will be used.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example query_balance request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "query_balance",\n "params": [\n {\n "name": "state_identifier",\n "value": {\n "BlockHash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n },\n {\n "name": "purse_identifier",\n "value": {\n "main_purse_under_account_hash": "account-hash-0909090909090909090909090909090909090909090909090909090909090909"\n }\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"query_balance_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"query_balance_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#u512"},"balance")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The balance represented in motes.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example query_balance result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "id": -6143675785141640608,\n "result": {\n "api_version": "1.0.0",\n "balance": "1000000000000000000000000000000000"\n }\n}\n\n'))),(0,l.kt)("h2",{id:"query-global-state"},"query_global_state"),(0,l.kt)("p",null,"This method allows for you to query for a value stored under certain keys in global state. You may query using either a ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block_hash"},"Block hash")," or state root hash."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Note: Querying a purse's balance requires the use of ",(0,l.kt)("inlineCode",{parentName:"li"},"query_balance"),", rather than any iteration of ",(0,l.kt)("inlineCode",{parentName:"li"},"query_global_state"),".")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#globalstateidentifier"},"state_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The identifier used for the query.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"key"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"casper_types::Key")," as a formatted string.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"path"),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"The path components starting from the key as base.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example query_global_state request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "query_global_state",\n "params": [\n "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1",\n [],\n {\n "BlockHash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"query_global_state_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"query_global_state_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#jsonblockheader"},"block_header")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block header if a Block hash was provided. (Not required)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#storedvalue"},"stored_value")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The stored value.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#merkle-proof"},"merkle_proof")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The merkle proof.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example query_global_state result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": {\n "accumulated_seed": "ac979f51525cfd979b14aa7dc0737c5154eabe0db9280eceaa8dc8d2905b20d5",\n "body_hash": "cd502c5393a3c8b66d6979ad7857507c9baf5a8ba16ba99c28378d3a970fff42",\n "era_end": {\n "era_report": {\n "equivocators": [\n "013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"\n ],\n "inactive_validators": [\n "018139770ea87d175f56a35466c34c7ecccb8d8a91b4ee37a25df60f5b8fc9b394"\n ],\n "rewards": [\n {\n "amount": 1000,\n "validator": "018a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c"\n }\n ]\n },\n "next_era_validator_weights": [\n {\n "validator": "016e7a1cdd29b0b78fd13af4c5598feff4ef2a97166e3ca6f2e4fbfccd80505bf1",\n "weight": "456"\n },\n {\n "validator": "018a875fff1eb38451577acd5afee405456568dd7c89e090863a0557bc7af49f17",\n "weight": "789"\n },\n {\n "validator": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "weight": "123"\n }\n ]\n },\n "era_id": 1,\n "height": 10,\n "parent_hash": "0707070707070707070707070707070707070707070707070707070707070707",\n "protocol_version": "1.0.0",\n "random_bit": true,\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",\n "timestamp": "2020-11-17T00:39:24.072Z"\n },\n "merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3",\n "stored_value": {\n "Account": {\n "account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",\n "weight": 1\n }\n ],\n "main_purse": "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007",\n "named_keys": []\n }\n }\n }\n}\n\n'))),(0,l.kt)("h2",{id:"state-get-account-info"},"state_get_account_info"),(0,l.kt)("p",null,"This method returns a JSON representation of an ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Account")," from the network. The ",(0,l.kt)("inlineCode",{parentName:"p"},"block_identifier")," must refer to a Block after the Account's creation, or the method will return an empty response."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#publickey"},"public_key")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The public key of the Account.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block identifier.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_account_info request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "state_get_account_info",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n },\n "013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"state_get_account_info_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"state_get_account_info_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#account"},"account")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"A JSON representation of the Account structure.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#merkleproof"},"merkle_proof")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The merkle proof.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_account_info result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "account": {\n "account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",\n "weight": 1\n }\n ],\n "main_purse": "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007",\n "named_keys": []\n },\n "api_version": "1.4.13",\n "merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3"\n }\n}\n\n'))),(0,l.kt)("h2",{id:"state-get-dictionary-item"},"state_get_dictionary_item"),(0,l.kt)("p",null,"This method returns an item from a Dictionary. Every dictionary has a seed URef, findable by using a ",(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_identifier"),". The address of a stored value is the blake2b hash of the seed URef and the byte representation of the dictionary key."),(0,l.kt)("p",null,"You may query a stored value directly using the dictionary address."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#digest"},"state_root_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"Hash of the state root.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#dictionaryidentifier"},"dictionary_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Dictionary query identifier.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_dictionary_item request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "state_get_dictionary_item",\n "params": [\n {\n "URef": {\n "dictionary_item_key": "a_unique_entry_identifier",\n "seed_uref": "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007"\n }\n },\n "0808080808080808080808080808080808080808080808080808080808080808"\n ]\n}\n\n'))),"### `state_get_dictionary_item_result`",(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"dictionary_key"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The key under which the value is stored.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#storedvalue"},"stored_value")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The stored value.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#merkle-proof"},"merkle_proof")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The merkle proof.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_dictionary_item result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "dictionary_key": "dictionary-67518854aa916c97d4e53df8570c8217ccc259da2721b692102d76acd0ee8d1f",\n "merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3",\n "stored_value": {\n "CLValue": {\n "bytes": "0100000000000000",\n "cl_type": "U64",\n "parsed": 1\n }\n }\n }\n}\n\n'))),(0,l.kt)("hr",null),(0,l.kt)("h1",{id:"node-informational"},"Node Informational JSON-RPC Methods"),(0,l.kt)("p",null,"The following methods return information from a node on a Casper network. The responses return information specific to the queried node, and as such, will vary."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"info-get-peers"},"info_get_peers"),(0,l.kt)("p",null,"This method returns a list of peers connected to the node."),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_peers request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "info_get_peers",\n "params": []\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_peers_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_peers_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#peersmap"},"peers")),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"The node ID and network address of each connected peer.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_peers result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "peers": [\n {\n "address": "127.0.0.1:54321",\n "node_id": "tls:0101..0101"\n }\n ]\n }\n}\n\n'))),(0,l.kt)("h2",{id:"info-get-status"},"info_get_status"),(0,l.kt)("p",null,"This method returns the current status of a node."),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_status request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "info_get_status",\n "params": []\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_status_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_status_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#AvailableBlockRange"},"available_block_range")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The available block range in storage.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#BlockSynchronizerStatus"},"block_sync")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The status of the block synchronizer builders.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"build_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The compiled node version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"chainspec_name"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The chainspec name, used to identify the currently connected network.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#minimalblockinfo"},"last_added_block_info")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The minimal info of the last Block from the linear chain.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#timestamp"},"last_progress")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"Timestamp of the last recorded progress in the reactor.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#nextupgrade"},"next_upgrade")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"Information about the next scheduled upgrade.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#publickey"},"our_public_signing_key")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"Our public signing key.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#peersmap"},"peers")),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"The node ID and network address of each connected peer.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#reactorstate"},"reactor_state")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The current state of the node reactor.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#timediff"},"round_length")),(0,l.kt)("td",{parentName:"tr",align:null},"Integer"),(0,l.kt)("td",{parentName:"tr",align:null},"The next round length if this node is a validator. A round length is the amount of time it takes to reach consensus on proposing a Block.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#digest"},"starting_state_root_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The state root hash used at the start of the current session.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#timediff"},"uptime")),(0,l.kt)("td",{parentName:"tr",align:null},"Integer"),(0,l.kt)("td",{parentName:"tr",align:null},"Time that passed since the node has started.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_status result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "name": "info_get_status_result",\n "value": {\n "peers": [\n {\n "node_id": "tls:0101..0101",\n "address": "127.0.0.1:54321"\n }\n ],\n "api_version": "1.4.8",\n "build_version": "1.0.0-xxxxxxxxx@DEBUG",\n "chainspec_name": "casper-example",\n "starting_state_root_hash": null,\n "last_added_block_info": {\n "hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "timestamp": "2020-11-17T00:39:24.072Z",\n "era_id": 1,\n "height": 10,\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",\n "creator": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c"\n },\n "our_public_signing_key": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "round_length": "1m 5s 536ms",\n "next_upgrade": {\n "activation_point": 42,\n "protocol_version": "2.0.1"\n },\n "uptime": "13s",\n "reactor_state": "Initialize",\n "last_progress": "1970-01-01T00:00:00.000Z",\n "available_block_range": {\n "low": 0,\n "high": 0\n },\n "block_sync": {\n "historical": {\n "block_hash": "16ddf28e2b3d2e17f4cef36f8b58827eca917af225d139b0c77df3b4a67dc55e",\n "block_height": 40,\n "acquisition_state": "have strict finality(40) for: block hash 16dd..c55e"\n },\n "forward": {\n "block_hash": "59907b1e32a9158169c4d89d9ce5ac9164fc31240bfcfb0969227ece06d74983",\n "block_height": 6701,\n "acquisition_state": "have block body(6701) for: block hash 5990..4983"\n }\n }\n }\n}\n\n'))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1afb40fe.fa9ecae2.js b/assets/js/1afb40fe.fa9ecae2.js deleted file mode 100644 index e56841526a..0000000000 --- a/assets/js/1afb40fe.fa9ecae2.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[870],{3905:function(e,t,a){a.d(t,{Zo:function(){return s},kt:function(){return u}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function d(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var i=n.createContext({}),o=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):d(d({},t),e)),a},s=function(e){var t=o(e.components);return n.createElement(i.Provider,{value:t},e.children)},p="mdxType",b={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=o(a),f=r,u=p["".concat(i,".").concat(f)]||p[f]||b[f]||l;return a?n.createElement(u,d(d({ref:t},s),{},{components:a})):n.createElement(u,d({ref:t},s))}));function u(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,d=new Array(l);d[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[p]="string"==typeof e?e:r,d[1]=c;for(var o=2;ochain_get_block_result",id:"chain_get_block_result",level:3},{value:"chain_get_block_transfers",id:"chain-get-block-transfers",level:2},{value:"chain_get_block_transfers_result",id:"chain_get_block_transfers_result",level:3},{value:"chain_get_era_summary",id:"chain-get-era-summary",level:2},{value:"chain_get_era_summary_result",id:"chain_get_era_summary_result",level:3},{value:"chain_get_state_root_hash",id:"chain-get-state-root-hash",level:2},{value:"chain_get_state_root_hash_result",id:"chain_get_state_root_hash_result",level:3},{value:"info_get_chainspec",id:"info-get-chainspec",level:2},{value:"info_get_chainspec_result",id:"info_get_chainspec_result",level:3},{value:"info_get_deploy",id:"info-get-deploy",level:2},{value:"info_get_deploy_result",id:"info_get_deploy_result",level:3},{value:"query_balance",id:"query-balance",level:2},{value:"query_balance_result",id:"query_balance_result",level:3},{value:"query_global_state",id:"query-global-state",level:2},{value:"query_global_state_result",id:"query_global_state_result",level:3},{value:"state_get_account_info",id:"state-get-account-info",level:2},{value:"state_get_account_info_result",id:"state_get_account_info_result",level:3},{value:"state_get_dictionary_item",id:"state-get-dictionary-item",level:2},{value:"info_get_peers",id:"info-get-peers",level:2},{value:"info_get_peers_result",id:"info_get_peers_result",level:3},{value:"info_get_status",id:"info-get-status",level:2},{value:"info_get_status_result",id:"info_get_status_result",level:3}],b={toc:p},f="wrapper";function u(e){var t=e.components,a=(0,r.Z)(e,d);return(0,l.kt)(f,(0,n.Z)({},b,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"informational"},"Informational JSON-RPC Methods"),(0,l.kt)("p",null,"The following methods return information from a node on a Casper network. The response should be identical, regardless of the node queried, as the information in question is objective and common to all nodes within a network."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"chain-get-block"},"chain_get_block"),(0,l.kt)("p",null,"This method returns the JSON representation of a ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"Block")," from the network."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash or the Block height.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_block request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "chain_get_block",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_block_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_block_result")),(0,l.kt)("p",null,"The result from ",(0,l.kt)("inlineCode",{parentName:"p"},"chain_get_block")," depends on block availability from a given node. If ",(0,l.kt)("inlineCode",{parentName:"p"},"chain_get_block")," returns an error message that the node does not have information on the given block, you may attempt to get the information from a different node."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#jsonblock"},"block")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block, if found. (Not required)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_block result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block": {\n "body": {\n "deploy_hashes": [],\n "proposer": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "transfer_hashes": [\n "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa"\n ]\n },\n "hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "header": {\n "accumulated_seed": "ac979f51525cfd979b14aa7dc0737c5154eabe0db9280eceaa8dc8d2905b20d5",\n "body_hash": "cd502c5393a3c8b66d6979ad7857507c9baf5a8ba16ba99c28378d3a970fff42",\n "era_end": {\n "era_report": {\n "equivocators": [\n "013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"\n ],\n "inactive_validators": [\n "018139770ea87d175f56a35466c34c7ecccb8d8a91b4ee37a25df60f5b8fc9b394"\n ],\n "rewards": [\n {\n "amount": 1000,\n "validator": "018a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c"\n }\n ]\n },\n "next_era_validator_weights": [\n {\n "validator": "016e7a1cdd29b0b78fd13af4c5598feff4ef2a97166e3ca6f2e4fbfccd80505bf1",\n "weight": "456"\n },\n {\n "validator": "018a875fff1eb38451577acd5afee405456568dd7c89e090863a0557bc7af49f17",\n "weight": "789"\n },\n {\n "validator": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "weight": "123"\n }\n ]\n },\n "era_id": 1,\n "height": 10,\n "parent_hash": "0707070707070707070707070707070707070707070707070707070707070707",\n "protocol_version": "1.0.0",\n "random_bit": true,\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",\n "timestamp": "2020-11-17T00:39:24.072Z"\n },\n "proofs": [\n {\n "public_key": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "signature": "016291a7b2689e2edcc6e79030be50edd02f9bd7d809921ae2654012f808c7b9a0f125bc32d6aa610cbd012395a9832ccfaa9262023339f1db71ca073a13bb9707"\n }\n ]\n }\n }\n}\n\n'))),(0,l.kt)("h2",{id:"chain-get-block-transfers"},"chain_get_block_transfers"),(0,l.kt)("p",null,"This method returns all ",(0,l.kt)("strong",{parentName:"p"},"successful")," native transfers within a given ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"Block")," from a network."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_block_transfers request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "chain_get_block_transfers",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_block_transfers_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_block_transfers_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockhash"},"block_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash, if found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#transfer"},"transfers")),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block's successful transfers, if found.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_block_transfers result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "transfers": [\n {\n "amount": "0",\n "deploy_hash": "0000000000000000000000000000000000000000000000000000000000000000",\n "from": "account-hash-0000000000000000000000000000000000000000000000000000000000000000",\n "gas": "0",\n "id": null,\n "source": "uref-0000000000000000000000000000000000000000000000000000000000000000-000",\n "target": "uref-0000000000000000000000000000000000000000000000000000000000000000-000",\n "to": null\n }\n ]\n }\n}\n\n'))),(0,l.kt)("h2",{id:"chain-get-era-summary"},"chain_get_era_summary"),(0,l.kt)("p",null,"This method returns the era summary at a given ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"Block"),". If you do not specify a ",(0,l.kt)("inlineCode",{parentName:"p"},"block_identifier"),", you will receive the era summary at the highest state root hash."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash. (Optional)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_era_summary request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc":"2.0",\n "method":"chain_get_era_summary",\n "params": [\n {\n "Hash":"9bfa58709058935882a095ca6adf844b72a2ddf0f49b8575ef1ceda987452fb8"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_era_summary_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_era_summary_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#erasummary"},"era_summary")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The era summary (if found).")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_era_summary result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "id": 1,\n "result": {\n "api_version": "1.0.0",\n "era_summary": {\n "block_hash": "9bfa58709058935882a095ca6adf844b72a2ddf0f49b8575ef1ceda987452fb8",\n "era_id": 1,\n "stored_value": {\n "EraInfo": {\n "seigniorage_allocations": [\n {\n "Delegator": {\n "delegator_public_key": "01c08939bf1ecd1139448d435989a761c975466d30b96c2dd74e9d23c7b12bc9ff",\n "validator_public_key": "01039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b",\n "amount": "53472520551166781393617756"\n }\n },\n {\n "Validator": {\n "validator_public_key": "01039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b",\n "amount": "54552773491594393138943367"\n }\n },\n {\n "Delegator": {\n "delegator_public_key": "01264689a5b4c57dac1088cd0aae8074de105f2269f6041e2c120e80df7a95e6b5",\n "validator_public_key": "013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c18726",\n "amount": "51312014670568117976319374"\n }\n },\n {\n "Validator": {\n "validator_public_key": "013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c18726",\n "amount": "56713279372733183026458256"\n }\n },\n {\n "Delegator": {\n "delegator_public_key": "016f571eaf1d3a442e684ecdb31d00a51448dcbaa06d00b340983311f0ba3e76db",\n "validator_public_key": "0186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f12",\n "amount": "51852141140784624481333262"\n }\n },\n {\n "Validator": {\n "validator_public_key": "0186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f12",\n "amount": "56173152902516676521444368"\n }\n },\n {\n "Delegator": {\n "delegator_public_key": "0161e7ed5c592f16b507b9dd196662b530f9bde6c5b2cfd957fe8d0700ecfbe20b",\n "validator_public_key": "01d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b",\n "amount": "52392267611001130986347150"\n }\n },\n {\n "Validator": {\n "validator_public_key": "01d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b",\n "amount": "55633026432300170016430480"\n }\n },\n {\n "Delegator": {\n "delegator_public_key": "01b1339a1d114036d84d7b65c804669166d38456114657abbb0e53e67bf1667c60",\n "validator_public_key": "01dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f",\n "amount": "52932394080952975520954950"\n }\n },\n {\n "Validator": {\n "validator_public_key": "01dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f",\n "amount": "55092899961808199011606173"\n }\n }\n ]\n }\n },\n "state_root_hash": "918abd1973171867e03c1e6e56fd7dd9da35c92461784f9a15c0df23e437d850",\n "merkle_proof": "010000000e0000000000000000000000000000000000000000000000000000000000000000070a0000000101c08939bf1ecd1139448d435989a761c975466d30b96c2dd74e9d23c7b12bc9ff01039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b0b5c4316483512c2253f3b2c0001039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b0b87d59268bf17d8c6ff1f2d0101264689a5b4c57dac1088cd0aae8074de105f2269f6041e2c120e80df7a95e6b5013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c187260b8e45261378f096e3bd712a00013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c187260b90eee69bba24050981e92e01016f571eaf1d3a442e684ecdb31d00a51448dcbaa06d00b340983311f0ba3e76db0186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f120b0ef09fedb1f521341ee42a000186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f120b10446dc1801f7ab820772e010161e7ed5c592f16b507b9dd196662b530f9bde6c5b2cfd957fe8d0700ecfbe20b01d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b0b8e9a19c8ebfaac847e562b0001d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b0b9099f3e6461aef67c0042e0101b1339a1d114036d84d7b65c804669166d38456114657abbb0e53e67bf1667c6001dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f0b46fad737700f37d5dec82b0001dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f0b9d1ed178841a631760922d01000000000e060000000001fb7043fe388fef916937aa899a0dda9b042168149e600fb068ecb16839d545d60101a0676758b903440b28c8f4a1d46404e9879fcfc0b90dad20962536de493aecc302013584bc9d5c00ac639fe14410b4cfa480b12eddd8f3dce08d7b76ae47977c1c680601664224aca1272e2a5632da4a56399dee6c585318ebbb7bb4040039792d3ad33c07013b48237cd26eb35ec3c864e1ae250ca656d00893de1dfc4c951e0d779adeda1d0a002c722cac61792676eb19d773fd3c41e37a63f54f78bdf7712ca96a5c5e5c4986"\n }\n }\n}\n\n'))),(0,l.kt)("h2",{id:"chain-get-state-root-hash"},"chain_get_state_root_hash"),(0,l.kt)("p",null,"This method returns a state root hash at a given ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"Block"),". If you do not specify a ",(0,l.kt)("inlineCode",{parentName:"p"},"block_identifier"),", you will receive the highest state root hash."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block hash. (Optional)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_state_root_hash request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "chain_get_state_root_hash",\n "params": [\n {\n "Height": 10\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_state_root_hash_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_state_root_hash_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#digest"},"state_root_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"Hex-encoded hash of the state root.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_state_root_hash result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808"\n }\n}\n\n'))),(0,l.kt)("h2",{id:"info-get-chainspec"},"info_get_chainspec"),(0,l.kt)("p",null,"This method returns raw bytes for chainspec files."),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_chainspec request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "method": "info_get_chainspec",\n "id": 5510244237763930243\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_chainspec_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_chainspec_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#ChainspecRawBytes"},"chainspec_bytes")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The raw bytes of the chainspec.toml, genesis accounts.toml, and global_state.toml files.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_chainspec result"),(0,l.kt)("p",null,"Please note that adding a ",(0,l.kt)("inlineCode",{parentName:"p"},"--vv")," flag will return the full chainspec bytes."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.5.0",\n "chainspec_bytes": {\n "chainspec_bytes": "[22040 hex chars]",\n "maybe_genesis_accounts_bytes": null,\n "maybe_global_state_bytes": null\n }\n },\n "id": 5510244237763930243\n}\n\n'))),(0,l.kt)("h2",{id:"info-get-deploy"},"info_get_deploy"),(0,l.kt)("p",null,"This method retrieves a ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#execution-semantics-deploys"},"Deploy")," from a network. It requires a ",(0,l.kt)("inlineCode",{parentName:"p"},"deploy_hash")," to query the Deploy."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deployhash"},"deploy_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The Deploy hash.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#finalizedapprovals"},"finalized_approvals")),(0,l.kt)("td",{parentName:"tr",align:null},"Boolean"),(0,l.kt)("td",{parentName:"tr",align:null},"Determines whether to return the Deploy with the finalized approvals substituted. (Optional)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_deploy request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "info_get_deploy",\n "params": [\n "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa",\n true\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_deploy_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_deploy_result")),(0,l.kt)("p",null,"The response contains the Deploy and the results of executing the Deploy."),(0,l.kt)("p",null,"If the ",(0,l.kt)("inlineCode",{parentName:"p"},"execution_results")," field is empty, it means that the network processed the ",(0,l.kt)("inlineCode",{parentName:"p"},"Deploy"),", but has yet to execute it. If the network executed the ",(0,l.kt)("inlineCode",{parentName:"p"},"Deploy"),", it will return the results of the execution. The execution results contain the Block hash which contains the Deploy."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deploy"},"deploy")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Deploy.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#jsonexecutionresult"},"execution_results")),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"An array of execution results with Block hashes.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_deploy result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy": {\n "approvals": [\n {\n "signature": "014c1a89f92e29dd74fc648f741137d9caf4edba97c5f9799ce0c9aa6b0c9b58db368c64098603dbecef645774c05dff057cb1f91f2cf390bbacce78aa6f084007",\n "signer": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c"\n }\n ],\n "hash": "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa",\n "header": {\n "account": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "body_hash": "d53cf72d17278fd47d399013ca389c50d589352f1a12593c0b8e01872a641b50",\n "chain_name": "casper-example",\n "dependencies": [\n "0101010101010101010101010101010101010101010101010101010101010101"\n ],\n "gas_price": 1,\n "timestamp": "2020-11-17T00:39:24.072Z",\n "ttl": "1h"\n },\n "payment": {\n "StoredContractByName": {\n "args": [\n [\n "amount",\n {\n "bytes": "e8030000",\n "cl_type": "I32",\n "parsed": 1000\n }\n ]\n ],\n "entry_point": "example-entry-point",\n "name": "casper-example"\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "bytes": "e8030000",\n "cl_type": "I32",\n "parsed": 1000\n }\n ]\n ]\n }\n }\n },\n "execution_results": [\n {\n "block_hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "result": {\n "Success": {\n "cost": "123456",\n "effect": {\n "operations": [\n {\n "key": "account-hash-2c4a11c062a8a337bfc97e27fd66291caeb2c65865dcb5d3ef3759c4c97efecb",\n "kind": "Write"\n },\n {\n "key": "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1",\n "kind": "Read"\n }\n ],\n "transforms": [\n {\n "key": "uref-2c4a11c062a8a337bfc97e27fd66291caeb2c65865dcb5d3ef3759c4c97efecb-007",\n "transform": {\n "AddUInt64": 8\n }\n },\n {\n "key": "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1",\n "transform": "Identity"\n }\n ]\n },\n "transfers": [\n "transfer-5959595959595959595959595959595959595959595959595959595959595959",\n "transfer-8282828282828282828282828282828282828282828282828282828282828282"\n ]\n }\n }\n }\n ]\n }\n}\n\n'))),(0,l.kt)("h2",{id:"query-balance"},"query_balance"),(0,l.kt)("p",null,"This method allows you to query for the balance of a purse using a ",(0,l.kt)("inlineCode",{parentName:"p"},"PurseIdentifier")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"StateIdentifier"),"."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#purseidentifier"},"purse_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The identifier to obtain the purse corresponding to the balance query.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#globalstateidentifier"},"state_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The state identifier used for the query; if none is passed the tip of the chain will be used.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example query_balance request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "query_balance",\n "params": [\n {\n "name": "state_identifier",\n "value": {\n "BlockHash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n },\n {\n "name": "purse_identifier",\n "value": {\n "main_purse_under_account_hash": "account-hash-0909090909090909090909090909090909090909090909090909090909090909"\n }\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"query_balance_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"query_balance_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#u512"},"balance")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The balance represented in motes.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example query_balance result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "id": -6143675785141640608,\n "result": {\n "api_version": "1.0.0",\n "balance": "1000000000000000000000000000000000"\n }\n}\n\n'))),(0,l.kt)("h2",{id:"query-global-state"},"query_global_state"),(0,l.kt)("p",null,"This method allows for you to query for a value stored under certain keys in global state. You may query using either a ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block_hash"},"Block hash")," or state root hash."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Note: Querying a purse's balance requires the use of ",(0,l.kt)("inlineCode",{parentName:"li"},"query_balance"),", rather than any iteration of ",(0,l.kt)("inlineCode",{parentName:"li"},"query_global_state"),".")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#globalstateidentifier"},"state_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The identifier used for the query.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"key"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"casper_types::Key")," as a formatted string.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"path"),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"The path components starting from the key as base.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example query_global_state request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "query_global_state",\n "params": [\n "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1",\n [],\n {\n "BlockHash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"query_global_state_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"query_global_state_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#jsonblockheader"},"block_header")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block header if a Block hash was provided. (Not required)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#storedvalue"},"stored_value")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The stored value.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#merkle-proof"},"merkle_proof")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The merkle proof.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example query_global_state result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": {\n "accumulated_seed": "ac979f51525cfd979b14aa7dc0737c5154eabe0db9280eceaa8dc8d2905b20d5",\n "body_hash": "cd502c5393a3c8b66d6979ad7857507c9baf5a8ba16ba99c28378d3a970fff42",\n "era_end": {\n "era_report": {\n "equivocators": [\n "013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"\n ],\n "inactive_validators": [\n "018139770ea87d175f56a35466c34c7ecccb8d8a91b4ee37a25df60f5b8fc9b394"\n ],\n "rewards": [\n {\n "amount": 1000,\n "validator": "018a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c"\n }\n ]\n },\n "next_era_validator_weights": [\n {\n "validator": "016e7a1cdd29b0b78fd13af4c5598feff4ef2a97166e3ca6f2e4fbfccd80505bf1",\n "weight": "456"\n },\n {\n "validator": "018a875fff1eb38451577acd5afee405456568dd7c89e090863a0557bc7af49f17",\n "weight": "789"\n },\n {\n "validator": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "weight": "123"\n }\n ]\n },\n "era_id": 1,\n "height": 10,\n "parent_hash": "0707070707070707070707070707070707070707070707070707070707070707",\n "protocol_version": "1.0.0",\n "random_bit": true,\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",\n "timestamp": "2020-11-17T00:39:24.072Z"\n },\n "merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3",\n "stored_value": {\n "Account": {\n "account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",\n "weight": 1\n }\n ],\n "main_purse": "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007",\n "named_keys": []\n }\n }\n }\n}\n\n'))),(0,l.kt)("h2",{id:"state-get-account-info"},"state_get_account_info"),(0,l.kt)("p",null,"This method returns a JSON representation of an ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Account")," from the network. The ",(0,l.kt)("inlineCode",{parentName:"p"},"block_identifier")," must refer to a Block after the Account's creation, or the method will return an empty response."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#publickey"},"public_key")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The public key of the Account.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block identifier.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_account_info request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "state_get_account_info",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n },\n "013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"state_get_account_info_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"state_get_account_info_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#account"},"account")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"A JSON representation of the Account structure.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#merkleproof"},"merkle_proof")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The merkle proof.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_account_info result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "account": {\n "account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",\n "weight": 1\n }\n ],\n "main_purse": "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007",\n "named_keys": []\n },\n "api_version": "1.4.13",\n "merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3"\n }\n}\n\n'))),(0,l.kt)("h2",{id:"state-get-dictionary-item"},"state_get_dictionary_item"),(0,l.kt)("p",null,"This method returns an item from a Dictionary. Every dictionary has a seed URef, findable by using a ",(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_identifier"),". The address of a stored value is the blake2b hash of the seed URef and the byte representation of the dictionary key."),(0,l.kt)("p",null,"You may query a stored value directly using the dictionary address."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#digest"},"state_root_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"Hash of the state root.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#dictionaryidentifier"},"dictionary_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Dictionary query identifier.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_dictionary_item request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "state_get_dictionary_item",\n "params": [\n {\n "URef": {\n "dictionary_item_key": "a_unique_entry_identifier",\n "seed_uref": "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007"\n }\n },\n "0808080808080808080808080808080808080808080808080808080808080808"\n ]\n}\n\n'))),"### `state_get_dictionary_item_result`",(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"dictionary_key"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The key under which the value is stored.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#storedvalue"},"stored_value")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The stored value.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#merkle-proof"},"merkle_proof")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The merkle proof.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_dictionary_item result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "dictionary_key": "dictionary-67518854aa916c97d4e53df8570c8217ccc259da2721b692102d76acd0ee8d1f",\n "merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3",\n "stored_value": {\n "CLValue": {\n "bytes": "0100000000000000",\n "cl_type": "U64",\n "parsed": 1\n }\n }\n }\n}\n\n'))),(0,l.kt)("hr",null),(0,l.kt)("h1",{id:"node-informational"},"Node Informational JSON-RPC Methods"),(0,l.kt)("p",null,"The following methods return information from a node on a Casper network. The responses return information specific to the queried node, and as such, will vary."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"info-get-peers"},"info_get_peers"),(0,l.kt)("p",null,"This method returns a list of peers connected to the node."),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_peers request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "info_get_peers",\n "params": []\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_peers_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_peers_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#peersmap"},"peers")),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"The node ID and network address of each connected peer.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_peers result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "peers": [\n {\n "address": "127.0.0.1:54321",\n "node_id": "tls:0101..0101"\n }\n ]\n }\n}\n\n'))),(0,l.kt)("h2",{id:"info-get-status"},"info_get_status"),(0,l.kt)("p",null,"This method returns the current status of a node."),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_status request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "info_get_status",\n "params": []\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_status_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_status_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#AvailableBlockRange"},"available_block_range")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The available block range in storage.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#BlockSynchronizerStatus"},"block_sync")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The status of the block synchronizer builders.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"build_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The compiled node version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"chainspec_name"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The chainspec name, used to identify the currently connected network.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#minimalblockinfo"},"last_added_block_info")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The minimal info of the last Block from the linear chain.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#timestamp"},"last_progress")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"Timestamp of the last recorded progress in the reactor.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#nextupgrade"},"next_upgrade")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"Information about the next scheduled upgrade.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#publickey"},"our_public_signing_key")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"Our public signing key.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#peersmap"},"peers")),(0,l.kt)("td",{parentName:"tr",align:null},"Array"),(0,l.kt)("td",{parentName:"tr",align:null},"The node ID and network address of each connected peer.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#reactorstate"},"reactor_state")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The current state of the node reactor.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#timediff"},"round_length")),(0,l.kt)("td",{parentName:"tr",align:null},"Integer"),(0,l.kt)("td",{parentName:"tr",align:null},"The next round length if this node is a validator. A round length is the amount of time it takes to reach consensus on proposing a Block.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#digest"},"starting_state_root_hash")),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The state root hash used at the start of the current session.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#timediff"},"uptime")),(0,l.kt)("td",{parentName:"tr",align:null},"Integer"),(0,l.kt)("td",{parentName:"tr",align:null},"Time that passed since the node has started.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_status result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "name": "info_get_status_result",\n "value": {\n "peers": [\n {\n "node_id": "tls:0101..0101",\n "address": "127.0.0.1:54321"\n }\n ],\n "api_version": "1.4.8",\n "build_version": "1.0.0-xxxxxxxxx@DEBUG",\n "chainspec_name": "casper-example",\n "starting_state_root_hash": null,\n "last_added_block_info": {\n "hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "timestamp": "2020-11-17T00:39:24.072Z",\n "era_id": 1,\n "height": 10,\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",\n "creator": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c"\n },\n "our_public_signing_key": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "round_length": "1m 5s 536ms",\n "next_upgrade": {\n "activation_point": 42,\n "protocol_version": "2.0.1"\n },\n "uptime": "13s",\n "reactor_state": "Initialize",\n "last_progress": "1970-01-01T00:00:00.000Z",\n "available_block_range": {\n "low": 0,\n "high": 0\n },\n "block_sync": {\n "historical": {\n "block_hash": "16ddf28e2b3d2e17f4cef36f8b58827eca917af225d139b0c77df3b4a67dc55e",\n "block_height": 40,\n "acquisition_state": "have strict finality(40) for: block hash 16dd..c55e"\n },\n "forward": {\n "block_hash": "59907b1e32a9158169c4d89d9ce5ac9164fc31240bfcfb0969227ece06d74983",\n "block_height": 6701,\n "acquisition_state": "have block body(6701) for: block hash 5990..4983"\n }\n }\n }\n}\n\n'))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1b581919.189083f6.js b/assets/js/1b581919.189083f6.js new file mode 100644 index 0000000000..74c006ab33 --- /dev/null +++ b/assets/js/1b581919.189083f6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7832],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),h=i,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||o;return n?a.createElement(m,r(r({ref:t},p),{},{components:n})):a.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var c=2;c with your public key manually and run this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info | jq '.result.auction_state.bids[] | select( .public_key == \"\")'\n")),(0,o.kt)("p",null,"Or, if you set up the node as described in this documentation, you can run another command that will automatically put in your public key:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info | jq --arg pk \"$(cat /etc/casper/validator_keys/public_key_hex)\" '.result.auction_state.bids[] | select( (.public_key | ascii_downcase) == ($pk | ascii_downcase) )'\n")),(0,o.kt)("p",null,"You know you were evicted if the ",(0,o.kt)("inlineCode",{parentName:"p"},"get-auction-info")," command returned your bid showing an ",(0,o.kt)("strong",{parentName:"p"},"inactive")," field. See the ",(0,o.kt)("a",{parentName:"p",href:"/operators/becoming-a-validator/inactive-vs-faulty"},"Inactive vs. Faulty Validator Nodes")," page for more information."),(0,o.kt)("p",null,"If you receive a ",(0,o.kt)("inlineCode",{parentName:"p"},"parse error: Invalid numeric literal at"),", this usually means that your RPC port is not up yet. Get your node in sync, and the RPC will come up. This should be working before you try to recover. Try running the following command to check the status of your RPC port:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info\n")),(0,o.kt)("h2",{id:"correcting-any-underlying-node-issues"},"Correcting any Underlying Node Issues"),(0,o.kt)("p",null,"Before fixing the eviction, you need to correct the problem that caused your node to be evicted. Stage missed upgrades, correct any node issues, and get your node in sync."),(0,o.kt)("p",null,"To check if your node is in sync, compare the current block height at ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"https://cspr.live/")," with the height from your node with:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s localhost:8888/status | jq .last_added_block_info\n")),(0,o.kt)("p",null,"If you cannot figure out the issue, ask for help in the ",(0,o.kt)("em",{parentName:"p"},"node-tech-support")," channel on ",(0,o.kt)("a",{parentName:"p",href:"https://discord.com/invite/casperblockchain"},"Discord"),"."),(0,o.kt)("h2",{id:"activating-the-bid"},"Activating the Bid"),(0,o.kt)("p",null,"Once your node is in sync and ready to validate again, you must activate your invalid bid. There are two ways to reactivate your bid. The recommended and cheaper method is to call the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point from the system auction contract. The second method involves building the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm")," contract as explained in ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup/joining#step-3-build-contracts"},"Building the Required Contracts"),"."),(0,o.kt)("p",null,"We recommend testing the following steps on the official Testnet before performing them in a live environment like the Casper Mainnet."),(0,o.kt)("h3",{id:"activating-system-auction"},"Method 1: Activating the Bid with the System Auction Contract"),(0,o.kt)("p",null,"This method calls the existing ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point from the system auction contract. Using this method, you do not need to build any contracts, reducing costs and complexity."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point activate_bid \\\n--session-arg \"validator_public_key:public_key='$(cat /etc/casper/validator_keys/public_key_hex)'\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. You must check the network's chainspec. For example, this entry point call needs 10,000 motes for node version ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entry point that will be used when calling the system auction contract. In this case, it is ",(0,o.kt)("inlineCode",{parentName:"li"},"activate_bid"))),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point expects one argument:"),(0,o.kt)("ol",{start:7},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"validator_public_key"),": The hexadecimal public key of the validator reactivating its bid. ",(0,o.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the bid activation request"))),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,o.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point on the auction contract has a fixed cost of 10,000 motes.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"This example uses the Casper Testnet to reactivate a bid:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 10000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point activate_bid \\\n--session-arg \"validator_public_key:public_key='$(cat /etc/casper/validator_keys/public_key_hex)'\"\n")),(0,o.kt)("p",null,"Next, ",(0,o.kt)("a",{parentName:"p",href:"#checking-the-bid-activation"},"check the bid activation")," status."),(0,o.kt)("h3",{id:"activating-compiled-wasm"},"Method 2: Activating the Bid with Compiled Wasm"),(0,o.kt)("p",null,"The second method to rejoin the network is to reactivate your bid using the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'sudo -u casper casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path "$HOME/casper-node/target/wasm32-unknown-unknown/release/activate_bid.wasm" \\\n--session-arg "validator_public_key:public_key=\'$(cat /etc/casper/validator_keys/public_key_hex)\'"\n')),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the compiled Wasm on your computer")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm")," expects one argument:"),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"validator_public_key"),": The hexadecimal public key of the validator reactivating its bid. ",(0,o.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the bid activation request"))),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"As described above, this method is much more expensive than calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"Here is an example that reactivates a bid using the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm"),". You must modify the payment and other values in the deploy based on your environment and the network's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),". For example, if you use the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm")," on a network with node version ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.4.9/resources/production/chainspec.toml"},"1.4.9"),", you will require a balance of at least 5 CSPR for this contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 5000000000 \\\n--session-path "$HOME/casper-node/target/wasm32-unknown-unknown/release/activate_bid.wasm" \\\n--session-arg "validator_public_key:public_key=\'$(cat /etc/casper/validator_keys/public_key_hex)\'"\n')),(0,o.kt)("p",null,"Check that the deploy was successful with the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client get-deploy ")," or by searching for the deploy hash on ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"https://cspr.live/"),". Also, check the bid activation status as shown below."),(0,o.kt)("h2",{id:"checking-the-bid-activation"},"Checking the Bid Activation"),(0,o.kt)("p",null,"Once your deploy processes, you can ",(0,o.kt)("a",{parentName:"p",href:"/operators/becoming-a-validator/recovering#detecting-the-eviction-using-the-casper-client"},"check your bid")," again. You should now see ",(0,o.kt)("inlineCode",{parentName:"p"},'"inactive": false')," in the output."),(0,o.kt)("p",null,"If you wait until the next Era starts, you should also see your public key as a future validator on the ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/validators"},"Validators")," tab."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1b581919.482f87ce.js b/assets/js/1b581919.482f87ce.js deleted file mode 100644 index 11bf838249..0000000000 --- a/assets/js/1b581919.482f87ce.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7832],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=c(n),h=i,m=d["".concat(l,".").concat(h)]||d[h]||u[h]||o;return n?a.createElement(m,r(r({ref:t},p),{},{components:n})):a.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:i,r[1]=s;for(var c=2;c with your public key manually and run this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info | jq '.result.auction_state.bids[] | select( .public_key == \"\")'\n")),(0,o.kt)("p",null,"Or, if you set up the node as described in this documentation, you can run another command that will automatically put in your public key:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info | jq --arg pk \"$(cat /etc/casper/validator_keys/public_key_hex)\" '.result.auction_state.bids[] | select( (.public_key | ascii_downcase) == ($pk | ascii_downcase) )'\n")),(0,o.kt)("p",null,"You know you were evicted if the ",(0,o.kt)("inlineCode",{parentName:"p"},"get-auction-info")," command returned your bid showing an ",(0,o.kt)("strong",{parentName:"p"},"inactive")," field. See the ",(0,o.kt)("a",{parentName:"p",href:"/operators/becoming-a-validator/inactive-vs-faulty"},"Inactive vs. Faulty Validator Nodes")," page for more information."),(0,o.kt)("p",null,"If you receive a ",(0,o.kt)("inlineCode",{parentName:"p"},"parse error: Invalid numeric literal at"),", this usually means that your RPC port is not up yet. Get your node in sync, and the RPC will come up. This should be working before you try to recover. Try running the following command to check the status of your RPC port:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info\n")),(0,o.kt)("h2",{id:"correcting-any-underlying-node-issues"},"Correcting any Underlying Node Issues"),(0,o.kt)("p",null,"Before fixing the eviction, you need to correct the problem that caused your node to be evicted. Stage missed upgrades, correct any node issues, and get your node in sync."),(0,o.kt)("p",null,"To check if your node is in sync, compare the current block height at ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"https://cspr.live/")," with the height from your node with:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s localhost:8888/status | jq .last_added_block_info\n")),(0,o.kt)("p",null,"If you cannot figure out the issue, ask for help in the ",(0,o.kt)("em",{parentName:"p"},"node-tech-support")," channel on ",(0,o.kt)("a",{parentName:"p",href:"https://discord.com/invite/casperblockchain"},"Discord"),"."),(0,o.kt)("h2",{id:"activating-the-bid"},"Activating the Bid"),(0,o.kt)("p",null,"Once your node is in sync and ready to validate again, you must activate your invalid bid. There are two ways to reactivate your bid. The recommended and cheaper method is to call the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point from the system auction contract. The second method involves building the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm")," contract as explained in ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup/joining#step-3-build-contracts"},"Building the Required Contracts"),"."),(0,o.kt)("p",null,"We recommend testing the following steps on the official Testnet before performing them in a live environment like the Casper Mainnet."),(0,o.kt)("h3",{id:"activating-system-auction"},"Method 1: Activating the Bid with the System Auction Contract"),(0,o.kt)("p",null,"This method calls the existing ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point from the system auction contract. Using this method, you do not need to build any contracts, reducing costs and complexity."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point activate_bid \\\n--session-arg \"validator_public_key:public_key='$(cat /etc/casper/validator_keys/public_key_hex)'\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. You must check the network's chainspec. For example, this entry point call needs 10,000 motes for node version ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entry point that will be used when calling the system auction contract. In this case, it is ",(0,o.kt)("inlineCode",{parentName:"li"},"activate_bid"))),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point expects one argument:"),(0,o.kt)("ol",{start:7},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"validator_public_key"),": The hexadecimal public key of the validator reactivating its bid. ",(0,o.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the bid activation request"))),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,o.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"Calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point on the auction contract has a fixed cost of 10,000 motes.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"This example uses the Casper Testnet to reactivate a bid:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 10000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point activate_bid \\\n--session-arg \"validator_public_key:public_key='$(cat /etc/casper/validator_keys/public_key_hex)'\"\n")),(0,o.kt)("p",null,"Next, ",(0,o.kt)("a",{parentName:"p",href:"#checking-the-bid-activation"},"check the bid activation")," status."),(0,o.kt)("h3",{id:"activating-compiled-wasm"},"Method 2: Activating the Bid with Compiled Wasm"),(0,o.kt)("p",null,"The second method to rejoin the network is to reactivate your bid using the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'sudo -u casper casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path "$HOME/casper-node/target/wasm32-unknown-unknown/release/activate_bid.wasm" \\\n--session-arg "validator_public_key:public_key=\'$(cat /etc/casper/validator_keys/public_key_hex)\'"\n')),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the compiled Wasm on your computer")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm")," expects one argument:"),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"validator_public_key"),": The hexadecimal public key of the validator reactivating its bid. ",(0,o.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the bid activation request"))),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"As described above, this method is much more expensive than calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid")," entry point.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"Here is an example that reactivates a bid using the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm"),". You must modify the payment and other values in the deploy based on your environment and the network's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),". For example, if you use the ",(0,o.kt)("inlineCode",{parentName:"p"},"activate_bid.wasm")," on a network with node version ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.4.9/resources/production/chainspec.toml"},"1.4.9"),", you will require a balance of at least 5 CSPR for this contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 5000000000 \\\n--session-path "$HOME/casper-node/target/wasm32-unknown-unknown/release/activate_bid.wasm" \\\n--session-arg "validator_public_key:public_key=\'$(cat /etc/casper/validator_keys/public_key_hex)\'"\n')),(0,o.kt)("p",null,"Check that the deploy was successful with the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client get-deploy ")," or by searching for the deploy hash on ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"https://cspr.live/"),". Also, check the bid activation status as shown below."),(0,o.kt)("h2",{id:"checking-the-bid-activation"},"Checking the Bid Activation"),(0,o.kt)("p",null,"Once your deploy processes, you can ",(0,o.kt)("a",{parentName:"p",href:"/operators/becoming-a-validator/recovering#detecting-the-eviction-using-the-casper-client"},"check your bid")," again. You should now see ",(0,o.kt)("inlineCode",{parentName:"p"},'"inactive": false')," in the output."),(0,o.kt)("p",null,"If you wait until the next Era starts, you should also see your public key as a future validator on the ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/validators"},"Validators")," tab."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1c22d3ad.8cf6a072.js b/assets/js/1c22d3ad.8cf6a072.js deleted file mode 100644 index 44f4b841c5..0000000000 --- a/assets/js/1c22d3ad.8cf6a072.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5870],{3905:function(e,n,t){t.d(n,{Zo:function(){return p},kt:function(){return m}});var a=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function r(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var l=a.createContext({}),d=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},p=function(e){var n=d(e.components);return a.createElement(l.Provider,{value:n},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(t),h=i,m=c["".concat(l,".").concat(h)]||c[h]||u[h]||o;return t?a.createElement(m,r(r({ref:n},p),{},{components:t})):a.createElement(m,r({ref:n},p))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var o=t.length,r=new Array(o);r[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[c]="string"==typeof e?e:i,r[1]=s;for(var d=2;dMessage Type",id:"the-message-type",level:2},{value:"Handshake Behavior",id:"handshake-behavior",level:2},{value:"Blocking Nodes",id:"blocking-nodes",level:2},{value:"The Payload Type",id:"the-payload-type",level:2},{value:"Consensus",id:"consensus",level:3},{value:"Gossiping",id:"gossiping",level:3},{value:"Unsafe-for-syncing",id:"unsafe-for-syncing",level:3},{value:"Gossiping",id:"gossiping-1",level:2},{value:"GetRequests",id:"getrequests",level:2},{value:"Finality Signatures",id:"finality-signatures",level:2},{value:"Trie Chunking",id:"trie-chunking",level:2}],u={toc:c},h="wrapper";function m(e){var n=e.components,t=(0,i.Z)(e,r);return(0,o.kt)(h,(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"casper-node-networking-protocol"},"Casper Node Networking Protocol"),(0,o.kt)("h2",{id:"casper-node-networking-protocol-mainnet-protocol-version-150"},"Casper Node Networking Protocol (Mainnet Protocol Version 1.5.0)"),(0,o.kt)("p",null,"This is a description of the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node"),"'s networking protocol. This document follows the conventions laid out in ",(0,o.kt)("a",{parentName:"p",href:"https://datatracker.ietf.org/doc/html/rfc2119"},"RFC2119"),"."),(0,o.kt)("h2",{id:"connection-level"},"Connection Level"),(0,o.kt)("p",null,"Any ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," taking part in the Casper network SHOULD open connections to every other casper-node it is aware of and has not blocked. These connections are established using TLS, presenting a client certificate."),(0,o.kt)("h3",{id:"reciprocity-retries-and-data-direction"},"Reciprocity, retries and data direction"),(0,o.kt)("p",null,"A connection that was initiated by a node is considered an ",(0,o.kt)("em",{parentName:"p"},"outgoing")," connection by the node itself, but an ",(0,o.kt)("em",{parentName:"p"},"incoming")," connection by all other peers."),(0,o.kt)("p",null,"A node that created an outgoing connection SHOULD terminate the connection if it does not detect an incoming connection from the connected-to node within a short amount of time."),(0,o.kt)("p",null,"A node that receives an incoming connection MUST eventually establish an outgoing connection to the node."),(0,o.kt)("p",null,"A node SHOULD retry any failed outgoing connection periodically with exponential backoff. A node MUST NOT attempt to reconnect more than once per second."),(0,o.kt)("p",null,"Nodes MUST NOT send data through incoming connections, other than handshakes. Nodes MUST NOT accept any data coming through outgoing connections, other than handshakes."),(0,o.kt)("h3",{id:"tls-parameters"},"TLS parameters"),(0,o.kt)("p",null,"Any node creating a connection to a node MUST present a client certificate with the following properties:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Signature algorithm: ",(0,o.kt)("inlineCode",{parentName:"li"},"ECDSA_WITH_SHA512")),(0,o.kt)("li",{parentName:"ul"},"Subject name: Same as issuer name (self-signed certificate!)"),(0,o.kt)("li",{parentName:"ul"},"Serial number: 1"),(0,o.kt)("li",{parentName:"ul"},'Expiration ("not before"): Must be earlier than current time.'),(0,o.kt)("li",{parentName:"ul"},'Expiration ("not after"): Must be later than current time.'),(0,o.kt)("li",{parentName:"ul"},"Signature: Must be using ",(0,o.kt)("inlineCode",{parentName:"li"},"SECP521R1")," with ",(0,o.kt)("inlineCode",{parentName:"li"},"SHA512")," and valid.")),(0,o.kt)("p",null,"The SHA512 fingerprint of the ",(0,o.kt)("em",{parentName:"p"},"public key")," is considered the ",(0,o.kt)("strong",{parentName:"p"},"NodeID")," of the node."),(0,o.kt)("p",null,"Any node MUST immediately terminate a connection if it does not match the given parameters. The same certificate MUST be used as a server certificate for other clients connecting to this node."),(0,o.kt)("p",null,"An incoming connection with a valid TLS certificate SHOULD be accepted. As all certificates are self-signed, no further checking is done."),(0,o.kt)("h3",{id:"discovery"},"Discovery"),(0,o.kt)("p",null,"A node address is defined as an IPv4 address and a port. A node's address is the publicly reachable IP address and port that it is listening on for node-to-node-communication."),(0,o.kt)("p",null,"Every node SHOULD have one or more so-called ",(0,o.kt)("em",{parentName:"p"},"known node addresses")," of other nodes configured."),(0,o.kt)("p",null,"On start-up, a node SHOULD attempt to connect to all known nodes. A node SHOULD never forget a known node address."),(0,o.kt)("p",null,"Every node MUST periodically gossip its own node address to the network (see gossiping below)."),(0,o.kt)("p",null,"A node ",(0,o.kt)("em",{parentName:"p"},"learns")," new node addresses through receiving a gossiped node address, or being told of an address through the handshake."),(0,o.kt)("p",null,"Upon learning of a previously unknown node address, a node SHOULD attempt to connect to it."),(0,o.kt)("p",null,"After failing to connect to a node address, a node MAY forget it after a certain amount of retries, this process is called ",(0,o.kt)("em",{parentName:"p"},"forgetting")," a node. An address that has been forgotten will be considered new the next time it is learned."),(0,o.kt)("p",null,"A node MUST NOT forget the known addresses it was configured with initially."),(0,o.kt)("h2",{id:"framing"},"Framing"),(0,o.kt)("p",null,"To send a message to a peer across an established TLS connection, a node MUST send a message length header consisting of a 32 byte big endian integer with the message length first."),(0,o.kt)("p",null,"A node receiving a message length header that exceeds the maximum message size specified in the chainspec MUST immediately terminate the connection."),(0,o.kt)("h2",{id:"encoding"},"Encoding"),(0,o.kt)("p",null,"The node uses three encoding schemes: Handshakes (see below) are encoded using ",(0,o.kt)("a",{parentName:"p",href:"https://msgpack.org"},"MessagePack"),", while regular messages are encoded using ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/bincode"},"bincode"),". Many (but not all) data objects use ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/bytesrepr/index.html"},(0,o.kt)("inlineCode",{parentName:"a"},"bytesrepr"))," for serialization."),(0,o.kt)("p",null,"The node uses the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/rmp-serde/0.14.4/rmp_serde/index.html"},(0,o.kt)("inlineCode",{parentName:"a"},"rmp-serde"))," crate, version ",(0,o.kt)("inlineCode",{parentName:"p"},"0.14.4"),", which is kept fixed to ensure handshake compatibility with protocol version 1.0 of the node."),(0,o.kt)("p",null,"All nodes MUST use the following settings for ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode")," encoding of network messages:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Byte limit: Unlimited"),(0,o.kt)("li",{parentName:"ul"},"Endianness: Little Endian"),(0,o.kt)("li",{parentName:"ul"},"Integer Encoding: Varint"),(0,o.kt)("li",{parentName:"ul"},"Trailing Bytes: Not allowed")),(0,o.kt)("p",null,"Any other use of ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode")," encoding (e.g. for GetRequest payloads, see below) MUST use the following ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode")," encoding settings:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Byte limit: Unlimited"),(0,o.kt)("li",{parentName:"ul"},"Endianness: Little Endian"),(0,o.kt)("li",{parentName:"ul"},"Integer Encoding: Fixint"),(0,o.kt)("li",{parentName:"ul"},"Trailing Bytes: Allowed")),(0,o.kt)("p",null,"Unless noted otherwise, any structure encoded as MessagePack or bincode is serialized using the standard ",(0,o.kt)("a",{parentName:"p",href:"https://serde.rs"},(0,o.kt)("inlineCode",{parentName:"a"},"serde")),"-derived encoding. For ",(0,o.kt)("inlineCode",{parentName:"p"},"bytesrepr")," serialization refer to the specific implementations in the ",(0,o.kt)("inlineCode",{parentName:"p"},"bytesrepr")," crate."),(0,o.kt)("p",null,"Any data types given from here on out are described using simplified ",(0,o.kt)("a",{parentName:"p",href:"https://www.rust-lang.org/"},"Rust")," structure definitions."),(0,o.kt)("h2",{id:"the-message-type"},"The ",(0,o.kt)("inlineCode",{parentName:"h2"},"Message")," Type"),(0,o.kt)("p",null,"The following data types make up the networking protocol:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"enum Message {\n Handshake {\n network_name: String,\n public_addr: SocketAddr,\n // default: 1.0\n protocol_version: ProtocolVersion,\n // default: `None`\n consensus_certificate: Option,\n // default: false\n is_syncing: bool,\n // default: `None`\n chainspec_hash: Option,\n },\n Payload(Payload),\n}\n\nstruct ConsensusCertificate {\n public_key: PublicKey,\n signature: Signature,\n}\n\nstruct Digest([u8; 32]);\n")),(0,o.kt)("p",null,"For ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/string/struct.String.html"},(0,o.kt)("inlineCode",{parentName:"a"},"String")),", ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/net/enum.SocketAddr.html"},(0,o.kt)("inlineCode",{parentName:"a"},"SocketAddr")),", ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/struct.ProtocolVersion.html"},(0,o.kt)("inlineCode",{parentName:"a"},"ProtocolVersion")),", ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/option/enum.Option.html"},(0,o.kt)("inlineCode",{parentName:"a"},"Option")),", ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/crypto/enum.PublicKey.html"},(0,o.kt)("inlineCode",{parentName:"a"},"PublicKey")),", ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/crypto/enum.Signature.html"},(0,o.kt)("inlineCode",{parentName:"a"},"Signature"))," see the respective docs and details below."),(0,o.kt)("h2",{id:"handshake-behavior"},"Handshake Behavior"),(0,o.kt)("p",null,"A node establishing a new connection MUST immediately send a handshake through said connection to the peer, regardless of whether an incoming or outgoing connection was established (this is an exception to the restriction of only sending data through outgoing connections)."),(0,o.kt)("p",null,"A handshake MUST be encoded using the ",(0,o.kt)("inlineCode",{parentName:"p"},"Message::Handshake")," structure. A node running version 1.5 SHOULD NOT omit any of the fields for which default values are available (",(0,o.kt)("inlineCode",{parentName:"p"},"protocol_version"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"consensus_certificate"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"is_syncing"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"chainspec_hash"),"). A node MUST accept any handshake that omits one or more of these fields and fill them with defaults."),(0,o.kt)("p",null,"After receiving a handshake, a node MUST compare the ",(0,o.kt)("inlineCode",{parentName:"p"},"network_name"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"protocol_version")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"chainspec_hash")," fields against its own configuration: If any of these do not match, it MUST disconnect from the node and SHOULD block it."),(0,o.kt)("p",null,"A node MUST mark any peer that connects to it (thus is an incoming connection from the perspective of the node) with a value of ",(0,o.kt)("inlineCode",{parentName:"p"},"is_syncing")," set to ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),' as "syncing" and MUST NOT allow any of its own messages that are marked unsafe-for-syncing to be sent to that node, by silently dropping them instead.'),(0,o.kt)("p",null,"A node MAY compare peers that provide a ",(0,o.kt)("inlineCode",{parentName:"p"},"consensus_certificate")," to the currently active set of validators and mark it as an active validator to give it preferential treatment when outgoing bandwidth is limited."),(0,o.kt)("p",null,"Upon handshake completion, the node SHOULD learn the provided ",(0,o.kt)("inlineCode",{parentName:"p"},"public_addr"),"."),(0,o.kt)("h2",{id:"blocking-nodes"},"Blocking Nodes"),(0,o.kt)("p",null,"If a node blocks a peer, it MUST sever all incoming and outgoing connections to said node. It MUST take note of the NodeId of the node, marking it as blocked and MUST not allow any new connection to proceed past the handshake."),(0,o.kt)("p",null,"A node MUST NOT block peers based on IP address or port. Nodes MUST NOT block peers for more than an hour."),(0,o.kt)("p",null,"After a block on a node is expired, the node SHOULD ",(0,o.kt)("em",{parentName:"p"},"forget")," the nodes IP address, allowing a later ",(0,o.kt)("em",{parentName:"p"},"learning")," of said address again."),(0,o.kt)("h2",{id:"the-payload-type"},"The ",(0,o.kt)("inlineCode",{parentName:"h2"},"Payload")," Type"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"Payload")," (found in the node sources as ",(0,o.kt)("inlineCode",{parentName:"p"},"Message")," in ",(0,o.kt)("inlineCode",{parentName:"p"},"payload.rs"),") contains variants for all node-to-node communicating subsystems of a running node, which are described below. Note that some of the variants have been renamed for clarity in this specification. Since field names are not used in ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode")," encoding, this should have no effect on implementations."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"enum Payload {\n Consensus(ConsensusMessage),\n DeployGossiper(DeployGossiperMessage),\n AddressGossiper(AddressGossiperMessage),\n GetRequest {\n tag: Tag,\n serialized_id: Vec,\n },\n GetResponse {\n tag: Tag,\n serialized_item: Vec<[u8]>,\n },\n FinalitySignature(FinalitySignature),\n}\n\nenum DeployGossiperMessage {\n Gossip(DeployHash),\n GossipResponse {\n item_id: DeployHash,\n is_already_held: bool,\n },\n}\n\nenum AddressGossiperMessage {\n Gossip(GossippedAddress),\n GossipResponse {\n item_id: GossippedAddress,\n is_already_held: bool,\n },\n}\n\nstruct DeployHash(Digest);\nstruct GossipedAddress(SocketAddr);\n")),(0,o.kt)("h3",{id:"consensus"},"Consensus"),(0,o.kt)("p",null,"A consensus message is sent exclusively between instances of the consensus component, from one peer to another. A precise description of the Highway consensus protocol is out of scope of this document, see the ",(0,o.kt)("inlineCode",{parentName:"p"},"consensus::Message")," type or an appropriate description of the underlying protocol for details."),(0,o.kt)("h3",{id:"gossiping"},"Gossiping"),(0,o.kt)("p",null,"Gossiping messages are sent by a node to a subset of its peers to announce the availability of new data items. Peers MUST be distinguished by NodeID, not by listening address."),(0,o.kt)("p",null,"A node must support a gossiper for deploys and one for ",(0,o.kt)("inlineCode",{parentName:"p"},"GossippedAddress"),", which is an alias for the regular Rust standard library's ",(0,o.kt)("inlineCode",{parentName:"p"},"SocketAddr"),"."),(0,o.kt)("p",null,"A node SHOULD begin a gossiping process for all deploys previously unknown to it. A node MUST periodically send an ",(0,o.kt)("inlineCode",{parentName:"p"},"AddressGossiperMessage::Gossip")," message to a random subset selected in a similar manner as the one for deploy gossip to make its own address known, see the gossiping process section below for details."),(0,o.kt)("h3",{id:"unsafe-for-syncing"},"Unsafe-for-syncing"),(0,o.kt)("p",null,"A node that is syncing MUST indicate this by setting ",(0,o.kt)("inlineCode",{parentName:"p"},"is_syncing")," to ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),"."),(0,o.kt)("p",null,"A node MAY implement a scheme for request throttling/backpressure for GetRequests (see below) of ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieNode"),"s that can cause issues with peers that are also sending GetRequests."),(0,o.kt)("p",null,"A node that succeeds in a handshake with a peer that has set ",(0,o.kt)("inlineCode",{parentName:"p"},"is_syncing")," MUST make note of this flag. If the node itself is implementing the feature described above, it MUST NOT make any GetRequests directed at this peer for ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieNode"),"s."),(0,o.kt)("h2",{id:"gossiping-1"},"Gossiping"),(0,o.kt)("p",null,"Gossiping is distributing items across the network by sending it to a subset of known peers that do not have the item already, and having them repeat this process until a certain degree of saturation is observed."),(0,o.kt)("p",null,"Any item has an associated ID type which denotes what is used to uniquely identify it when gossiping. If an item is small enough, the ID may just be the item itself."),(0,o.kt)("p",null,"Gossiper messages have the following structure:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"enum GossiperMessage {\n Gossip(Id),\n GossipResponse {\n item_id: Id,\n is_already_held: bool,\n },\n}\n")),(0,o.kt)("p",null,"To gossip, a node MAY send a ",(0,o.kt)("inlineCode",{parentName:"p"},"GossiperMessage::Gossip")," message to a random subset of configurable size of peers to announce that it has received and validated a new item. Any peer receiving such a message SHOULD answer with a ",(0,o.kt)("inlineCode",{parentName:"p"},"GossiperMessage:GossipResponse"),", citing the given id and using ",(0,o.kt)("inlineCode",{parentName:"p"},"is_already_held")," to indicate whether it already possessed the given item."),(0,o.kt)("p",null,"The node SHOULD attempt to continue to find peers with a negative response, up to a configurable limit of attempts and/or success rate, or until running out of valid peers."),(0,o.kt)("p",null,"The node that initiated the gossip MUST keep track of which peer replied with a positive (",(0,o.kt)("inlineCode",{parentName:"p"},"is_already_held")," being ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),") response and MUST NOT send another ",(0,o.kt)("inlineCode",{parentName:"p"},"Gossip")," message for same ID to any of these peers during this gossip process. However, it MAY restart gossiping the same item at a later time, considering these peers again."),(0,o.kt)("p",null,"If a node receives a negative ",(0,o.kt)("inlineCode",{parentName:"p"},"GossiperMessage::GossipResponse")," (i.e. ",(0,o.kt)("inlineCode",{parentName:"p"},"is_already_held")," being ",(0,o.kt)("inlineCode",{parentName:"p"},"false"),"), and the item's ID is not the item itself, it MUST handle that repsponse as if the peer had sent a ",(0,o.kt)("inlineCode",{parentName:"p"},"GetRequest")," for the item (see GetRequests section below)."),(0,o.kt)("h2",{id:"getrequests"},"GetRequests"),(0,o.kt)("p",null,'The "GetRequests" mechanism allows retrieving various items through primary or derived keys from peers.'),(0,o.kt)("p",null,"A peer MAY send a ",(0,o.kt)("inlineCode",{parentName:"p"},"GetRequest")," (see ",(0,o.kt)("inlineCode",{parentName:"p"},"Payload::GetRequest"),") with a ",(0,o.kt)("inlineCode",{parentName:"p"},"Tag")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_id")," payload. Both ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_id")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_item")," MUST be encoded using ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode"),' (see "Encoding" section for details).'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub enum Tag {\n Deploy,\n FinalizedApprovals,\n Block,\n GossipedAddress,\n BlockAndMetadataByHeight,\n BlockHeaderByHash,\n BlockHeaderAndFinalitySignaturesByHeight,\n TrieOrChunk,\n BlockAndDeploysByHash,\n BlockHeaderBatch,\n FinalitySignaturesByHash,\n}\n")),(0,o.kt)("p",null,"The tag dictates which item is being retrieved, and which key (ID type) is being used."),(0,o.kt)("p",null,"A node that receives a ",(0,o.kt)("inlineCode",{parentName:"p"},"GetRequest")," from a peer SHOULD return a ",(0,o.kt)("inlineCode",{parentName:"p"},"GetResponse")," (see ",(0,o.kt)("inlineCode",{parentName:"p"},"Payload::GetResponse"),"). The ",(0,o.kt)("inlineCode",{parentName:"p"},"GetResponse")," MUST use the same ",(0,o.kt)("inlineCode",{parentName:"p"},"Tag"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub enum FetchedOrNotFound {\n Fetched(T),\n NotFound(Id),\n}\n")),(0,o.kt)("p",null,"If the item was found, ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_item")," MUST contain a serialized ",(0,o.kt)("inlineCode",{parentName:"p"},"FetchedOrNotFound::Fetched")," instance, with the inner value ",(0,o.kt)("inlineCode",{parentName:"p"},"T")," being the item."),(0,o.kt)("p",null,"If the item was not found, ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_item")," MUST contain a ",(0,o.kt)("inlineCode",{parentName:"p"},"FetchedOrNotFound::NotFound")," instance, with the inner value ",(0,o.kt)("inlineCode",{parentName:"p"},"Id")," being the ID found in the originating ",(0,o.kt)("inlineCode",{parentName:"p"},"GetRequest"),"."),(0,o.kt)("p",null,"A node MUST not send any items to a peer that it itself has not verified."),(0,o.kt)("p",null,"The following table shows which tag corresponds to which ID and item type. Type definitions for ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployHash")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"GossippedAddress")," can be found earlier in this document, other types are described following this section. Further details of many of these types can be found in the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"Serialization Standard"),", but be aware that those docs describe serializing using bytesrepr rather than bincode."),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Tag"),(0,o.kt)("th",{parentName:"tr",align:null},"ID type"),(0,o.kt)("th",{parentName:"tr",align:null},"Payload (item) type"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Deploy"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"DeployHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"Deploy"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"FinalizedApprovals"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"DeployHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"FinalizedApprovalsWithId"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Block"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"Block"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"GossipedAddress"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"GossipedAddress")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"GossipedAddress"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockAndMetadataByHeight"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"u64")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockWithMetadata"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockHeaderByHash"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHeader"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockHeaderAndFinalitySignaturesByHeight"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"u64")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHeaderWithMetadata"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"TrieOrChunk"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"TrieOrChunkId")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"TrieOrChunk"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockAndDeploysByHash"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockAndDeploys"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockHeaderBatch"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHeadersBatchId")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHeadersBatch"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"FinalitySignaturesByHash"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockSignatures"))))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub struct Deploy {\n hash: DeployHash,\n header: DeployHeader,\n payment: ExecutableDeployItem,\n session: ExecutableDeployItem,\n approvals: BTreeSet,\n}\n\nstruct DeployHeader {\n account: PublicKey,\n timestamp: u64,\n ttl: u64,\n gas_price: u64,\n body_hash: Digest,\n dependencies: Vec,\n chain_name: String,\n}\n\nenum PublicKey {\n System,\n Ed25519(Vec),\n Secp256k1(Vec),\n}\n\nenum ExecutableDeployItem {\n ModuleBytes {\n module_bytes: Vec,\n args: RuntimeArgs,\n },\n StoredContractByHash {\n hash: [u8; 32],\n entry_point: String,\n args: RuntimeArgs,\n },\n StoredContractByName {\n name: String,\n entry_point: String,\n args: RuntimeArgs,\n },\n StoredVersionedContractByHash {\n hash: [u8; 32],\n version: Option,\n entry_point: String,\n args: RuntimeArgs,\n },\n StoredVersionedContractByName {\n name: String,\n version: Option,\n entry_point: String,\n args: RuntimeArgs,\n },\n Transfer { args: RuntimeArgs },\n}\n\nstruct RuntimeArgs(Vec);\n\nstruct NamedArg(String, CLValue);\n\nstruct CLValue(CLType, Vec);\n\nenum CLType {\n Bool,\n I32,\n I64,\n U8,\n U32,\n U64,\n U128,\n U256,\n U512,\n Unit,\n String,\n Key,\n URef,\n PublicKey,\n Option(Box),\n List(Box),\n ByteArray(u32),\n Result { ok: Box, err: Box },\n Map { key: Box, value: Box },\n Tuple1([Box; 1]),\n Tuple2([Box; 2]),\n Tuple3([Box; 3]),\n Any,\n}\n\nstruct Approval {\n signer: PublicKey,\n signature: Signature,\n}\n\nenum Signature {\n System,\n Ed25519(Vec),\n Secp256k1(Vec),\n}\n\nstruct FinalizedApprovalsWithId {\n id: DeployHash,\n approvals: FinalizedApprovals,\n}\n\nstruct FinalizedApprovals(BTreeSet);\n\nstruct Block {\n hash: BlockHash,\n header: BlockHeader,\n body: BlockBody,\n}\n\nstruct BlockHash(Digest);\n\nstruct BlockHeader {\n parent_hash: BlockHash,\n state_root_hash: Digest,\n body_hash: Digest,\n random_bit: bool,\n accumulated_seed: Digest,\n era_end: Option,\n timestamp: u64,\n era_id: u64,\n height: u64,\n protocol_version: ProtocolVersion,\n}\n\nstruct EraEnd {\n era_report: EraReport,\n next_era_validator_weights: BTreeMap,\n}\n\nstruct EraReport {\n equivocators: Vec,\n rewards: BTreeMap,\n inactive_validators: Vec,\n}\n\nstruct ProtocolVersion {\n major: u32,\n minor: u32,\n patch: u32,\n}\n\nstruct BlockBody {\n proposer: PublicKey,\n deploy_hashes: Vec,\n transfer_hashes: Vec,\n}\n")),(0,o.kt)("p",null,"Custom variable length encoding is used when serializing ",(0,o.kt)("inlineCode",{parentName:"p"},"U512"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"U256")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"U128")," types. They are encoded in a way equivalent to encoding the following pseudo struct:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"struct Bigint {\n serialized_length: u8,\n little_endian_unpadded_bytes: [u8, serialized_length - 1],\n}\n")),(0,o.kt)("p",null,"In other words, the following steps are taken:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"convert the bigint to an array of bytes in little-endian form"),(0,o.kt)("li",{parentName:"ul"},"strip the contiguous range of irrelevant padding ",(0,o.kt)("inlineCode",{parentName:"li"},"0")," bytes from the right hand end, if any"),(0,o.kt)("li",{parentName:"ul"},"prefix this remaining array with a byte holding the number of remaining bytes + 1, to indicate the length of the final byte array including the length byte itself")),(0,o.kt)("p",null,"For a description explaining the use of ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieOrChunk"),' and related types, see the "Trie chunking" section. The relevant types are:'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"struct TrieOrChunkId(u64, Digest);\n\nenum TrieOrChunk {\n Trie(Bytes),\n ChunkWithProof(ChunkWithProof),\n}\n\nstruct ChunkWithProof {\n proof: IndexedMerkleProof,\n chunk: Bytes,\n}\n\nstruct IndexedMerkleProof {\n index: u64,\n count: u64,\n merkle_proof: Vec,\n}\n")),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"BlockHeadersBatchId")," is used to request multiple ",(0,o.kt)("inlineCode",{parentName:"p"},"BlockHeader"),"s with a single request."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"struct BlockHeadersBatchId {\n highest: u64,\n lowest: u64,\n}\n\nstruct BlockWithMetadata {\n block: Block,\n finality_signatures: BlockSignatures,\n}\n\nstruct BlockHeaderWithMetadata {\n block_header: BlockHeader,\n block_signatures: BlockSignatures,\n}\n\nstruct BlockSignatures {\n block_hash: BlockHash,\n era_id: u64,\n proofs: BTreeMap,\n}\n\nstruct BlockAndDeploys {\n block: Block,\n deploys: Vec,\n}\n\nstruct BlockHeadersBatch(Vec);\n")),(0,o.kt)("h2",{id:"finality-signatures"},"Finality Signatures"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"Payload::FinalitySignature")," variant is used when broadcasting finality signatures."),(0,o.kt)("p",null,"A node that is an active validator MUST create and broadcast, i.e. send to all connected peers, a finality signature for every valid block it receives or creates."),(0,o.kt)("h2",{id:"trie-chunking"},"Trie Chunking"),(0,o.kt)("p",null,"Large trie nodes are split when transferred across the network, according to ",(0,o.kt)("inlineCode",{parentName:"p"},"CHUNK_SIZE_BYTES"),", which is set to 8388608 bytes (8 megabytes). Any trie node that is less than 8388608 in size will be represented by a ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieOrChunk::Trie")," instance."),(0,o.kt)("p",null,"Should a trie node be larger than this, a Merkle tree is constructed with ",(0,o.kt)("inlineCode",{parentName:"p"},"CHUNK_SIZE_BYTES")," sized chunks and is identified by the root hash of the resulting tree instead."),(0,o.kt)("p",null,"Peers MUST only request chunks. The ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieOrChunkId")," type allows for requesting the n-th chunk of a given trie node. See the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-hashing"},"casper-hashing")," crate for details."),(0,o.kt)("p",null,"A node receiving a ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieOrChunk")," item from a peer MUST validate it by checking the given Merkle proof against the item hash (which is the tree's root hash), before accepting it."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1c22d3ad.a70828b6.js b/assets/js/1c22d3ad.a70828b6.js new file mode 100644 index 0000000000..69b0e96ee8 --- /dev/null +++ b/assets/js/1c22d3ad.a70828b6.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5870],{3905:function(e,n,t){t.d(n,{Zo:function(){return p},kt:function(){return m}});var a=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function r(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var l=a.createContext({}),d=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},p=function(e){var n=d(e.components);return a.createElement(l.Provider,{value:n},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=d(t),h=i,m=c["".concat(l,".").concat(h)]||c[h]||u[h]||o;return t?a.createElement(m,r(r({ref:n},p),{},{components:t})):a.createElement(m,r({ref:n},p))}));function m(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var o=t.length,r=new Array(o);r[0]=h;var s={};for(var l in n)hasOwnProperty.call(n,l)&&(s[l]=n[l]);s.originalType=e,s[c]="string"==typeof e?e:i,r[1]=s;for(var d=2;dMessage Type",id:"the-message-type",level:2},{value:"Handshake Behavior",id:"handshake-behavior",level:2},{value:"Blocking Nodes",id:"blocking-nodes",level:2},{value:"The Payload Type",id:"the-payload-type",level:2},{value:"Consensus",id:"consensus",level:3},{value:"Gossiping",id:"gossiping",level:3},{value:"Unsafe-for-syncing",id:"unsafe-for-syncing",level:3},{value:"Gossiping",id:"gossiping-1",level:2},{value:"GetRequests",id:"getrequests",level:2},{value:"Finality Signatures",id:"finality-signatures",level:2},{value:"Trie Chunking",id:"trie-chunking",level:2}],u={toc:c},h="wrapper";function m(e){var n=e.components,t=(0,i.Z)(e,r);return(0,o.kt)(h,(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"casper-node-networking-protocol"},"Casper Node Networking Protocol"),(0,o.kt)("h2",{id:"casper-node-networking-protocol-mainnet-protocol-version-150"},"Casper Node Networking Protocol (Mainnet Protocol Version 1.5.0)"),(0,o.kt)("p",null,"This is a description of the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node"),"'s networking protocol. This document follows the conventions laid out in ",(0,o.kt)("a",{parentName:"p",href:"https://datatracker.ietf.org/doc/html/rfc2119"},"RFC2119"),"."),(0,o.kt)("h2",{id:"connection-level"},"Connection Level"),(0,o.kt)("p",null,"Any ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," taking part in the Casper network SHOULD open connections to every other casper-node it is aware of and has not blocked. These connections are established using TLS, presenting a client certificate."),(0,o.kt)("h3",{id:"reciprocity-retries-and-data-direction"},"Reciprocity, retries and data direction"),(0,o.kt)("p",null,"A connection that was initiated by a node is considered an ",(0,o.kt)("em",{parentName:"p"},"outgoing")," connection by the node itself, but an ",(0,o.kt)("em",{parentName:"p"},"incoming")," connection by all other peers."),(0,o.kt)("p",null,"A node that created an outgoing connection SHOULD terminate the connection if it does not detect an incoming connection from the connected-to node within a short amount of time."),(0,o.kt)("p",null,"A node that receives an incoming connection MUST eventually establish an outgoing connection to the node."),(0,o.kt)("p",null,"A node SHOULD retry any failed outgoing connection periodically with exponential backoff. A node MUST NOT attempt to reconnect more than once per second."),(0,o.kt)("p",null,"Nodes MUST NOT send data through incoming connections, other than handshakes. Nodes MUST NOT accept any data coming through outgoing connections, other than handshakes."),(0,o.kt)("h3",{id:"tls-parameters"},"TLS parameters"),(0,o.kt)("p",null,"Any node creating a connection to a node MUST present a client certificate with the following properties:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Signature algorithm: ",(0,o.kt)("inlineCode",{parentName:"li"},"ECDSA_WITH_SHA512")),(0,o.kt)("li",{parentName:"ul"},"Subject name: Same as issuer name (self-signed certificate!)"),(0,o.kt)("li",{parentName:"ul"},"Serial number: 1"),(0,o.kt)("li",{parentName:"ul"},'Expiration ("not before"): Must be earlier than current time.'),(0,o.kt)("li",{parentName:"ul"},'Expiration ("not after"): Must be later than current time.'),(0,o.kt)("li",{parentName:"ul"},"Signature: Must be using ",(0,o.kt)("inlineCode",{parentName:"li"},"SECP521R1")," with ",(0,o.kt)("inlineCode",{parentName:"li"},"SHA512")," and valid.")),(0,o.kt)("p",null,"The SHA512 fingerprint of the ",(0,o.kt)("em",{parentName:"p"},"public key")," is considered the ",(0,o.kt)("strong",{parentName:"p"},"NodeID")," of the node."),(0,o.kt)("p",null,"Any node MUST immediately terminate a connection if it does not match the given parameters. The same certificate MUST be used as a server certificate for other clients connecting to this node."),(0,o.kt)("p",null,"An incoming connection with a valid TLS certificate SHOULD be accepted. As all certificates are self-signed, no further checking is done."),(0,o.kt)("h3",{id:"discovery"},"Discovery"),(0,o.kt)("p",null,"A node address is defined as an IPv4 address and a port. A node's address is the publicly reachable IP address and port that it is listening on for node-to-node-communication."),(0,o.kt)("p",null,"Every node SHOULD have one or more so-called ",(0,o.kt)("em",{parentName:"p"},"known node addresses")," of other nodes configured."),(0,o.kt)("p",null,"On start-up, a node SHOULD attempt to connect to all known nodes. A node SHOULD never forget a known node address."),(0,o.kt)("p",null,"Every node MUST periodically gossip its own node address to the network (see gossiping below)."),(0,o.kt)("p",null,"A node ",(0,o.kt)("em",{parentName:"p"},"learns")," new node addresses through receiving a gossiped node address, or being told of an address through the handshake."),(0,o.kt)("p",null,"Upon learning of a previously unknown node address, a node SHOULD attempt to connect to it."),(0,o.kt)("p",null,"After failing to connect to a node address, a node MAY forget it after a certain amount of retries, this process is called ",(0,o.kt)("em",{parentName:"p"},"forgetting")," a node. An address that has been forgotten will be considered new the next time it is learned."),(0,o.kt)("p",null,"A node MUST NOT forget the known addresses it was configured with initially."),(0,o.kt)("h2",{id:"framing"},"Framing"),(0,o.kt)("p",null,"To send a message to a peer across an established TLS connection, a node MUST send a message length header consisting of a 32 byte big endian integer with the message length first."),(0,o.kt)("p",null,"A node receiving a message length header that exceeds the maximum message size specified in the chainspec MUST immediately terminate the connection."),(0,o.kt)("h2",{id:"encoding"},"Encoding"),(0,o.kt)("p",null,"The node uses three encoding schemes: Handshakes (see below) are encoded using ",(0,o.kt)("a",{parentName:"p",href:"https://msgpack.org"},"MessagePack"),", while regular messages are encoded using ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/bincode"},"bincode"),". Many (but not all) data objects use ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/bytesrepr/index.html"},(0,o.kt)("inlineCode",{parentName:"a"},"bytesrepr"))," for serialization."),(0,o.kt)("p",null,"The node uses the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/rmp-serde/0.14.4/rmp_serde/index.html"},(0,o.kt)("inlineCode",{parentName:"a"},"rmp-serde"))," crate, version ",(0,o.kt)("inlineCode",{parentName:"p"},"0.14.4"),", which is kept fixed to ensure handshake compatibility with protocol version 1.0 of the node."),(0,o.kt)("p",null,"All nodes MUST use the following settings for ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode")," encoding of network messages:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Byte limit: Unlimited"),(0,o.kt)("li",{parentName:"ul"},"Endianness: Little Endian"),(0,o.kt)("li",{parentName:"ul"},"Integer Encoding: Varint"),(0,o.kt)("li",{parentName:"ul"},"Trailing Bytes: Not allowed")),(0,o.kt)("p",null,"Any other use of ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode")," encoding (e.g. for GetRequest payloads, see below) MUST use the following ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode")," encoding settings:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Byte limit: Unlimited"),(0,o.kt)("li",{parentName:"ul"},"Endianness: Little Endian"),(0,o.kt)("li",{parentName:"ul"},"Integer Encoding: Fixint"),(0,o.kt)("li",{parentName:"ul"},"Trailing Bytes: Allowed")),(0,o.kt)("p",null,"Unless noted otherwise, any structure encoded as MessagePack or bincode is serialized using the standard ",(0,o.kt)("a",{parentName:"p",href:"https://serde.rs"},(0,o.kt)("inlineCode",{parentName:"a"},"serde")),"-derived encoding. For ",(0,o.kt)("inlineCode",{parentName:"p"},"bytesrepr")," serialization refer to the specific implementations in the ",(0,o.kt)("inlineCode",{parentName:"p"},"bytesrepr")," crate."),(0,o.kt)("p",null,"Any data types given from here on out are described using simplified ",(0,o.kt)("a",{parentName:"p",href:"https://www.rust-lang.org/"},"Rust")," structure definitions."),(0,o.kt)("h2",{id:"the-message-type"},"The ",(0,o.kt)("inlineCode",{parentName:"h2"},"Message")," Type"),(0,o.kt)("p",null,"The following data types make up the networking protocol:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"enum Message {\n Handshake {\n network_name: String,\n public_addr: SocketAddr,\n // default: 1.0\n protocol_version: ProtocolVersion,\n // default: `None`\n consensus_certificate: Option,\n // default: false\n is_syncing: bool,\n // default: `None`\n chainspec_hash: Option,\n },\n Payload(Payload),\n}\n\nstruct ConsensusCertificate {\n public_key: PublicKey,\n signature: Signature,\n}\n\nstruct Digest([u8; 32]);\n")),(0,o.kt)("p",null,"For ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/string/struct.String.html"},(0,o.kt)("inlineCode",{parentName:"a"},"String")),", ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/net/enum.SocketAddr.html"},(0,o.kt)("inlineCode",{parentName:"a"},"SocketAddr")),", ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/struct.ProtocolVersion.html"},(0,o.kt)("inlineCode",{parentName:"a"},"ProtocolVersion")),", ",(0,o.kt)("a",{parentName:"p",href:"https://doc.rust-lang.org/std/option/enum.Option.html"},(0,o.kt)("inlineCode",{parentName:"a"},"Option")),", ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/crypto/enum.PublicKey.html"},(0,o.kt)("inlineCode",{parentName:"a"},"PublicKey")),", ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/crypto/enum.Signature.html"},(0,o.kt)("inlineCode",{parentName:"a"},"Signature"))," see the respective docs and details below."),(0,o.kt)("h2",{id:"handshake-behavior"},"Handshake Behavior"),(0,o.kt)("p",null,"A node establishing a new connection MUST immediately send a handshake through said connection to the peer, regardless of whether an incoming or outgoing connection was established (this is an exception to the restriction of only sending data through outgoing connections)."),(0,o.kt)("p",null,"A handshake MUST be encoded using the ",(0,o.kt)("inlineCode",{parentName:"p"},"Message::Handshake")," structure. A node running version 1.5 SHOULD NOT omit any of the fields for which default values are available (",(0,o.kt)("inlineCode",{parentName:"p"},"protocol_version"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"consensus_certificate"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"is_syncing"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"chainspec_hash"),"). A node MUST accept any handshake that omits one or more of these fields and fill them with defaults."),(0,o.kt)("p",null,"After receiving a handshake, a node MUST compare the ",(0,o.kt)("inlineCode",{parentName:"p"},"network_name"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"protocol_version")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"chainspec_hash")," fields against its own configuration: If any of these do not match, it MUST disconnect from the node and SHOULD block it."),(0,o.kt)("p",null,"A node MUST mark any peer that connects to it (thus is an incoming connection from the perspective of the node) with a value of ",(0,o.kt)("inlineCode",{parentName:"p"},"is_syncing")," set to ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),' as "syncing" and MUST NOT allow any of its own messages that are marked unsafe-for-syncing to be sent to that node, by silently dropping them instead.'),(0,o.kt)("p",null,"A node MAY compare peers that provide a ",(0,o.kt)("inlineCode",{parentName:"p"},"consensus_certificate")," to the currently active set of validators and mark it as an active validator to give it preferential treatment when outgoing bandwidth is limited."),(0,o.kt)("p",null,"Upon handshake completion, the node SHOULD learn the provided ",(0,o.kt)("inlineCode",{parentName:"p"},"public_addr"),"."),(0,o.kt)("h2",{id:"blocking-nodes"},"Blocking Nodes"),(0,o.kt)("p",null,"If a node blocks a peer, it MUST sever all incoming and outgoing connections to said node. It MUST take note of the NodeId of the node, marking it as blocked and MUST not allow any new connection to proceed past the handshake."),(0,o.kt)("p",null,"A node MUST NOT block peers based on IP address or port. Nodes MUST NOT block peers for more than an hour."),(0,o.kt)("p",null,"After a block on a node is expired, the node SHOULD ",(0,o.kt)("em",{parentName:"p"},"forget")," the nodes IP address, allowing a later ",(0,o.kt)("em",{parentName:"p"},"learning")," of said address again."),(0,o.kt)("h2",{id:"the-payload-type"},"The ",(0,o.kt)("inlineCode",{parentName:"h2"},"Payload")," Type"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"Payload")," (found in the node sources as ",(0,o.kt)("inlineCode",{parentName:"p"},"Message")," in ",(0,o.kt)("inlineCode",{parentName:"p"},"payload.rs"),") contains variants for all node-to-node communicating subsystems of a running node, which are described below. Note that some of the variants have been renamed for clarity in this specification. Since field names are not used in ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode")," encoding, this should have no effect on implementations."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"enum Payload {\n Consensus(ConsensusMessage),\n DeployGossiper(DeployGossiperMessage),\n AddressGossiper(AddressGossiperMessage),\n GetRequest {\n tag: Tag,\n serialized_id: Vec,\n },\n GetResponse {\n tag: Tag,\n serialized_item: Vec<[u8]>,\n },\n FinalitySignature(FinalitySignature),\n}\n\nenum DeployGossiperMessage {\n Gossip(DeployHash),\n GossipResponse {\n item_id: DeployHash,\n is_already_held: bool,\n },\n}\n\nenum AddressGossiperMessage {\n Gossip(GossippedAddress),\n GossipResponse {\n item_id: GossippedAddress,\n is_already_held: bool,\n },\n}\n\nstruct DeployHash(Digest);\nstruct GossipedAddress(SocketAddr);\n")),(0,o.kt)("h3",{id:"consensus"},"Consensus"),(0,o.kt)("p",null,"A consensus message is sent exclusively between instances of the consensus component, from one peer to another. A precise description of the Highway consensus protocol is out of scope of this document, see the ",(0,o.kt)("inlineCode",{parentName:"p"},"consensus::Message")," type or an appropriate description of the underlying protocol for details."),(0,o.kt)("h3",{id:"gossiping"},"Gossiping"),(0,o.kt)("p",null,"Gossiping messages are sent by a node to a subset of its peers to announce the availability of new data items. Peers MUST be distinguished by NodeID, not by listening address."),(0,o.kt)("p",null,"A node must support a gossiper for deploys and one for ",(0,o.kt)("inlineCode",{parentName:"p"},"GossippedAddress"),", which is an alias for the regular Rust standard library's ",(0,o.kt)("inlineCode",{parentName:"p"},"SocketAddr"),"."),(0,o.kt)("p",null,"A node SHOULD begin a gossiping process for all deploys previously unknown to it. A node MUST periodically send an ",(0,o.kt)("inlineCode",{parentName:"p"},"AddressGossiperMessage::Gossip")," message to a random subset selected in a similar manner as the one for deploy gossip to make its own address known, see the gossiping process section below for details."),(0,o.kt)("h3",{id:"unsafe-for-syncing"},"Unsafe-for-syncing"),(0,o.kt)("p",null,"A node that is syncing MUST indicate this by setting ",(0,o.kt)("inlineCode",{parentName:"p"},"is_syncing")," to ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),"."),(0,o.kt)("p",null,"A node MAY implement a scheme for request throttling/backpressure for GetRequests (see below) of ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieNode"),"s that can cause issues with peers that are also sending GetRequests."),(0,o.kt)("p",null,"A node that succeeds in a handshake with a peer that has set ",(0,o.kt)("inlineCode",{parentName:"p"},"is_syncing")," MUST make note of this flag. If the node itself is implementing the feature described above, it MUST NOT make any GetRequests directed at this peer for ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieNode"),"s."),(0,o.kt)("h2",{id:"gossiping-1"},"Gossiping"),(0,o.kt)("p",null,"Gossiping is distributing items across the network by sending it to a subset of known peers that do not have the item already, and having them repeat this process until a certain degree of saturation is observed."),(0,o.kt)("p",null,"Any item has an associated ID type which denotes what is used to uniquely identify it when gossiping. If an item is small enough, the ID may just be the item itself."),(0,o.kt)("p",null,"Gossiper messages have the following structure:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"enum GossiperMessage {\n Gossip(Id),\n GossipResponse {\n item_id: Id,\n is_already_held: bool,\n },\n}\n")),(0,o.kt)("p",null,"To gossip, a node MAY send a ",(0,o.kt)("inlineCode",{parentName:"p"},"GossiperMessage::Gossip")," message to a random subset of configurable size of peers to announce that it has received and validated a new item. Any peer receiving such a message SHOULD answer with a ",(0,o.kt)("inlineCode",{parentName:"p"},"GossiperMessage:GossipResponse"),", citing the given id and using ",(0,o.kt)("inlineCode",{parentName:"p"},"is_already_held")," to indicate whether it already possessed the given item."),(0,o.kt)("p",null,"The node SHOULD attempt to continue to find peers with a negative response, up to a configurable limit of attempts and/or success rate, or until running out of valid peers."),(0,o.kt)("p",null,"The node that initiated the gossip MUST keep track of which peer replied with a positive (",(0,o.kt)("inlineCode",{parentName:"p"},"is_already_held")," being ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),") response and MUST NOT send another ",(0,o.kt)("inlineCode",{parentName:"p"},"Gossip")," message for same ID to any of these peers during this gossip process. However, it MAY restart gossiping the same item at a later time, considering these peers again."),(0,o.kt)("p",null,"If a node receives a negative ",(0,o.kt)("inlineCode",{parentName:"p"},"GossiperMessage::GossipResponse")," (i.e. ",(0,o.kt)("inlineCode",{parentName:"p"},"is_already_held")," being ",(0,o.kt)("inlineCode",{parentName:"p"},"false"),"), and the item's ID is not the item itself, it MUST handle that repsponse as if the peer had sent a ",(0,o.kt)("inlineCode",{parentName:"p"},"GetRequest")," for the item (see GetRequests section below)."),(0,o.kt)("h2",{id:"getrequests"},"GetRequests"),(0,o.kt)("p",null,'The "GetRequests" mechanism allows retrieving various items through primary or derived keys from peers.'),(0,o.kt)("p",null,"A peer MAY send a ",(0,o.kt)("inlineCode",{parentName:"p"},"GetRequest")," (see ",(0,o.kt)("inlineCode",{parentName:"p"},"Payload::GetRequest"),") with a ",(0,o.kt)("inlineCode",{parentName:"p"},"Tag")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_id")," payload. Both ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_id")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_item")," MUST be encoded using ",(0,o.kt)("inlineCode",{parentName:"p"},"bincode"),' (see "Encoding" section for details).'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub enum Tag {\n Deploy,\n FinalizedApprovals,\n Block,\n GossipedAddress,\n BlockAndMetadataByHeight,\n BlockHeaderByHash,\n BlockHeaderAndFinalitySignaturesByHeight,\n TrieOrChunk,\n BlockAndDeploysByHash,\n BlockHeaderBatch,\n FinalitySignaturesByHash,\n}\n")),(0,o.kt)("p",null,"The tag dictates which item is being retrieved, and which key (ID type) is being used."),(0,o.kt)("p",null,"A node that receives a ",(0,o.kt)("inlineCode",{parentName:"p"},"GetRequest")," from a peer SHOULD return a ",(0,o.kt)("inlineCode",{parentName:"p"},"GetResponse")," (see ",(0,o.kt)("inlineCode",{parentName:"p"},"Payload::GetResponse"),"). The ",(0,o.kt)("inlineCode",{parentName:"p"},"GetResponse")," MUST use the same ",(0,o.kt)("inlineCode",{parentName:"p"},"Tag"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub enum FetchedOrNotFound {\n Fetched(T),\n NotFound(Id),\n}\n")),(0,o.kt)("p",null,"If the item was found, ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_item")," MUST contain a serialized ",(0,o.kt)("inlineCode",{parentName:"p"},"FetchedOrNotFound::Fetched")," instance, with the inner value ",(0,o.kt)("inlineCode",{parentName:"p"},"T")," being the item."),(0,o.kt)("p",null,"If the item was not found, ",(0,o.kt)("inlineCode",{parentName:"p"},"serialized_item")," MUST contain a ",(0,o.kt)("inlineCode",{parentName:"p"},"FetchedOrNotFound::NotFound")," instance, with the inner value ",(0,o.kt)("inlineCode",{parentName:"p"},"Id")," being the ID found in the originating ",(0,o.kt)("inlineCode",{parentName:"p"},"GetRequest"),"."),(0,o.kt)("p",null,"A node MUST not send any items to a peer that it itself has not verified."),(0,o.kt)("p",null,"The following table shows which tag corresponds to which ID and item type. Type definitions for ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployHash")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"GossippedAddress")," can be found earlier in this document, other types are described following this section. Further details of many of these types can be found in the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"Serialization Standard"),", but be aware that those docs describe serializing using bytesrepr rather than bincode."),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Tag"),(0,o.kt)("th",{parentName:"tr",align:null},"ID type"),(0,o.kt)("th",{parentName:"tr",align:null},"Payload (item) type"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Deploy"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"DeployHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"Deploy"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"FinalizedApprovals"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"DeployHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"FinalizedApprovalsWithId"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"Block"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"Block"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"GossipedAddress"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"GossipedAddress")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"GossipedAddress"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockAndMetadataByHeight"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"u64")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockWithMetadata"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockHeaderByHash"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHeader"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockHeaderAndFinalitySignaturesByHeight"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"u64")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHeaderWithMetadata"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"TrieOrChunk"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"TrieOrChunkId")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"TrieOrChunk"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockAndDeploysByHash"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockAndDeploys"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"BlockHeaderBatch"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHeadersBatchId")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHeadersBatch"))),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"FinalitySignaturesByHash"),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockHash")),(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("inlineCode",{parentName:"td"},"BlockSignatures"))))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub struct Deploy {\n hash: DeployHash,\n header: DeployHeader,\n payment: ExecutableDeployItem,\n session: ExecutableDeployItem,\n approvals: BTreeSet,\n}\n\nstruct DeployHeader {\n account: PublicKey,\n timestamp: u64,\n ttl: u64,\n gas_price: u64,\n body_hash: Digest,\n dependencies: Vec,\n chain_name: String,\n}\n\nenum PublicKey {\n System,\n Ed25519(Vec),\n Secp256k1(Vec),\n}\n\nenum ExecutableDeployItem {\n ModuleBytes {\n module_bytes: Vec,\n args: RuntimeArgs,\n },\n StoredContractByHash {\n hash: [u8; 32],\n entry_point: String,\n args: RuntimeArgs,\n },\n StoredContractByName {\n name: String,\n entry_point: String,\n args: RuntimeArgs,\n },\n StoredVersionedContractByHash {\n hash: [u8; 32],\n version: Option,\n entry_point: String,\n args: RuntimeArgs,\n },\n StoredVersionedContractByName {\n name: String,\n version: Option,\n entry_point: String,\n args: RuntimeArgs,\n },\n Transfer { args: RuntimeArgs },\n}\n\nstruct RuntimeArgs(Vec);\n\nstruct NamedArg(String, CLValue);\n\nstruct CLValue(CLType, Vec);\n\nenum CLType {\n Bool,\n I32,\n I64,\n U8,\n U32,\n U64,\n U128,\n U256,\n U512,\n Unit,\n String,\n Key,\n URef,\n PublicKey,\n Option(Box),\n List(Box),\n ByteArray(u32),\n Result { ok: Box, err: Box },\n Map { key: Box, value: Box },\n Tuple1([Box; 1]),\n Tuple2([Box; 2]),\n Tuple3([Box; 3]),\n Any,\n}\n\nstruct Approval {\n signer: PublicKey,\n signature: Signature,\n}\n\nenum Signature {\n System,\n Ed25519(Vec),\n Secp256k1(Vec),\n}\n\nstruct FinalizedApprovalsWithId {\n id: DeployHash,\n approvals: FinalizedApprovals,\n}\n\nstruct FinalizedApprovals(BTreeSet);\n\nstruct Block {\n hash: BlockHash,\n header: BlockHeader,\n body: BlockBody,\n}\n\nstruct BlockHash(Digest);\n\nstruct BlockHeader {\n parent_hash: BlockHash,\n state_root_hash: Digest,\n body_hash: Digest,\n random_bit: bool,\n accumulated_seed: Digest,\n era_end: Option,\n timestamp: u64,\n era_id: u64,\n height: u64,\n protocol_version: ProtocolVersion,\n}\n\nstruct EraEnd {\n era_report: EraReport,\n next_era_validator_weights: BTreeMap,\n}\n\nstruct EraReport {\n equivocators: Vec,\n rewards: BTreeMap,\n inactive_validators: Vec,\n}\n\nstruct ProtocolVersion {\n major: u32,\n minor: u32,\n patch: u32,\n}\n\nstruct BlockBody {\n proposer: PublicKey,\n deploy_hashes: Vec,\n transfer_hashes: Vec,\n}\n")),(0,o.kt)("p",null,"Custom variable length encoding is used when serializing ",(0,o.kt)("inlineCode",{parentName:"p"},"U512"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"U256")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"U128")," types. They are encoded in a way equivalent to encoding the following pseudo struct:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"struct Bigint {\n serialized_length: u8,\n little_endian_unpadded_bytes: [u8, serialized_length - 1],\n}\n")),(0,o.kt)("p",null,"In other words, the following steps are taken:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"convert the bigint to an array of bytes in little-endian form"),(0,o.kt)("li",{parentName:"ul"},"strip the contiguous range of irrelevant padding ",(0,o.kt)("inlineCode",{parentName:"li"},"0")," bytes from the right hand end, if any"),(0,o.kt)("li",{parentName:"ul"},"prefix this remaining array with a byte holding the number of remaining bytes + 1, to indicate the length of the final byte array including the length byte itself")),(0,o.kt)("p",null,"For a description explaining the use of ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieOrChunk"),' and related types, see the "Trie chunking" section. The relevant types are:'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"struct TrieOrChunkId(u64, Digest);\n\nenum TrieOrChunk {\n Trie(Bytes),\n ChunkWithProof(ChunkWithProof),\n}\n\nstruct ChunkWithProof {\n proof: IndexedMerkleProof,\n chunk: Bytes,\n}\n\nstruct IndexedMerkleProof {\n index: u64,\n count: u64,\n merkle_proof: Vec,\n}\n")),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"BlockHeadersBatchId")," is used to request multiple ",(0,o.kt)("inlineCode",{parentName:"p"},"BlockHeader"),"s with a single request."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"struct BlockHeadersBatchId {\n highest: u64,\n lowest: u64,\n}\n\nstruct BlockWithMetadata {\n block: Block,\n finality_signatures: BlockSignatures,\n}\n\nstruct BlockHeaderWithMetadata {\n block_header: BlockHeader,\n block_signatures: BlockSignatures,\n}\n\nstruct BlockSignatures {\n block_hash: BlockHash,\n era_id: u64,\n proofs: BTreeMap,\n}\n\nstruct BlockAndDeploys {\n block: Block,\n deploys: Vec,\n}\n\nstruct BlockHeadersBatch(Vec);\n")),(0,o.kt)("h2",{id:"finality-signatures"},"Finality Signatures"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"Payload::FinalitySignature")," variant is used when broadcasting finality signatures."),(0,o.kt)("p",null,"A node that is an active validator MUST create and broadcast, i.e. send to all connected peers, a finality signature for every valid block it receives or creates."),(0,o.kt)("h2",{id:"trie-chunking"},"Trie Chunking"),(0,o.kt)("p",null,"Large trie nodes are split when transferred across the network, according to ",(0,o.kt)("inlineCode",{parentName:"p"},"CHUNK_SIZE_BYTES"),", which is set to 8388608 bytes (8 megabytes). Any trie node that is less than 8388608 in size will be represented by a ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieOrChunk::Trie")," instance."),(0,o.kt)("p",null,"Should a trie node be larger than this, a Merkle tree is constructed with ",(0,o.kt)("inlineCode",{parentName:"p"},"CHUNK_SIZE_BYTES")," sized chunks and is identified by the root hash of the resulting tree instead."),(0,o.kt)("p",null,"Peers MUST only request chunks. The ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieOrChunkId")," type allows for requesting the n-th chunk of a given trie node. See the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-hashing"},"casper-hashing")," crate for details."),(0,o.kt)("p",null,"A node receiving a ",(0,o.kt)("inlineCode",{parentName:"p"},"TrieOrChunk")," item from a peer MUST validate it by checking the given Merkle proof against the item hash (which is the tree's root hash), before accepting it."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1c7bd663.c551adb9.js b/assets/js/1c7bd663.c551adb9.js deleted file mode 100644 index 785d136a96..0000000000 --- a/assets/js/1c7bd663.c551adb9.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3549],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return f}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var o=a.createContext({}),c=function(e){var t=a.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(o.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,o=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),h=r,f=d["".concat(o,".").concat(h)]||d[h]||u[h]||s;return n?a.createElement(f,i(i({ref:t},p),{},{components:n})):a.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,i=new Array(s);i[0]=h;var l={};for(var o in t)hasOwnProperty.call(t,o)&&(l[o]=t[o]);l.originalType=e,l[d]="string"==typeof e?e:r,i[1]=l;for(var c=2;c=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var o=a.createContext({}),c=function(e){var t=a.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(o.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,o=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),h=r,f=d["".concat(o,".").concat(h)]||d[h]||u[h]||s;return n?a.createElement(f,i(i({ref:t},p),{},{components:n})):a.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,i=new Array(s);i[0]=h;var l={};for(var o in t)hasOwnProperty.call(t,o)&&(l[o]=t[o]);l.originalType=e,l[d]="string"==typeof e?e:r,i[1]=l;for(var c=2;c=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),y=a,m=u["".concat(p,".").concat(y)]||u[y]||f[y]||o;return r?n.createElement(m,s(s({ref:t},i),{},{components:r})):n.createElement(m,s({ref:t},i))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),m=a,y=u["".concat(p,".").concat(m)]||u[m]||f[m]||o;return r?n.createElement(y,s(s({ref:t},i),{},{components:r})):n.createElement(y,s({ref:t},i))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=m;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),m=a,y=u["".concat(p,".").concat(m)]||u[m]||f[m]||o;return r?n.createElement(y,s(s({ref:t},i),{},{components:r})):n.createElement(y,s({ref:t},i))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=m;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),u=p(n),m=i,h=u["".concat(s,".").concat(m)]||u[m]||d[m]||r;return n?a.createElement(h,l(l({ref:t},c),{},{components:n})):a.createElement(h,l({ref:t},c))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:i,l[1]=o;for(var p=2;p=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),u=p(n),m=i,h=u["".concat(s,".").concat(m)]||u[m]||d[m]||r;return n?a.createElement(h,l(l({ref:t},c),{},{components:n})):a.createElement(h,l({ref:t},c))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:i,l[1]=o;for(var p=2;p=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},l=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=p(e,["components","mdxType","originalType","parentName"]),d=u(r),m=a,f=d["".concat(s,".").concat(m)]||d[m]||c[m]||o;return r?n.createElement(f,i(i({ref:t},l),{},{components:r})):n.createElement(f,i({ref:t},l))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[d]="string"==typeof e?e:a,i[1]=p;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},l=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=p(e,["components","mdxType","originalType","parentName"]),d=u(r),m=a,f=d["".concat(s,".").concat(m)]||d[m]||c[m]||o;return r?n.createElement(f,i(i({ref:t},l),{},{components:r})):n.createElement(f,i({ref:t},l))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[d]="string"==typeof e?e:a,i[1]=p;for(var u=2;u=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=l(n),h=a,y=p["".concat(c,".").concat(h)]||p[h]||u[h]||o;return n?r.createElement(y,i(i({ref:t},d),{},{components:n})):r.createElement(y,i({ref:t},d))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:a,i[1]=s;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=l(n),h=a,y=p["".concat(c,".").concat(h)]||p[h]||u[h]||o;return n?r.createElement(y,i(i({ref:t},d),{},{components:n})):r.createElement(y,i({ref:t},d))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:a,i[1]=s;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var r=o.createContext({}),p=function(e){var t=o.useContext(r),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return o.createElement(r.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,r=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(n),h=a,y=d["".concat(r,".").concat(h)]||d[h]||u[h]||i;return n?o.createElement(y,l(l({ref:t},c),{},{components:n})):o.createElement(y,l({ref:t},c))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=h;var s={};for(var r in t)hasOwnProperty.call(t,r)&&(s[r]=t[r]);s.originalType=e,s[d]="string"==typeof e?e:a,l[1]=s;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var r=o.createContext({}),p=function(e){var t=o.useContext(r),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return o.createElement(r.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,r=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(n),h=a,y=d["".concat(r,".").concat(h)]||d[h]||u[h]||i;return n?o.createElement(y,l(l({ref:t},c),{},{components:n})):o.createElement(y,l({ref:t},c))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=h;var s={};for(var r in t)hasOwnProperty.call(t,r)&&(s[r]=t[r]);s.originalType=e,s[d]="string"==typeof e?e:a,l[1]=s;for(var p=2;p=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(a),h=r,f=p["".concat(l,".").concat(h)]||p[h]||d[h]||o;return a?n.createElement(f,i(i({ref:t},u),{},{components:a})):n.createElement(f,i({ref:t},u))}));function f(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(a),h=r,f=p["".concat(l,".").concat(h)]||p[h]||d[h]||o;return a?n.createElement(f,i(i({ref:t},u),{},{components:a})):n.createElement(f,i({ref:t},u))}));function f(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=p(n),m=r,h=c["".concat(l,".").concat(m)]||c[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},d),{},{components:n})):a.createElement(h,i({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var p=2;p [path_to]/file.tar.zst\n")),(0,o.kt)("h3",{id:"compression-level"},"Compression level"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"-[level]")," argument is the compression level from 1 to 19 (and 20-22 with expansion). In testing, we found 15 to be the sweet spot in compression time vs. size. We recommend lower compression if you plan to transfer the archive only once. If you are creating an archive to be downloaded by many, then the extra time for higher compression may be helpful."),(0,o.kt)("p",null,"Here are some examples of a Mainnet DB compression at block 741160:"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Level"),(0,o.kt)("th",{parentName:"tr",align:null},"Time (min:sec)"),(0,o.kt)("th",{parentName:"tr",align:null},"Size"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"12"),(0,o.kt)("td",{parentName:"tr",align:null},"29:20"),(0,o.kt)("td",{parentName:"tr",align:null},"15.8 GB")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"15"),(0,o.kt)("td",{parentName:"tr",align:null},"46:15"),(0,o.kt)("td",{parentName:"tr",align:null},"13.0 GB")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"17"),(0,o.kt)("td",{parentName:"tr",align:null},"87:42"),(0,o.kt)("td",{parentName:"tr",align:null},"13.0 GB")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"19"),(0,o.kt)("td",{parentName:"tr",align:null},"197:08"),(0,o.kt)("td",{parentName:"tr",align:null},"12.9 GB")))),(0,o.kt)("p",null,"For local backups, using 1-5 is a great compression speed-to-size trade-off."),(0,o.kt)("h3",{id:"thread-count"},"Thread count"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"-T[thread count]")," is the number of threads that ",(0,o.kt)("inlineCode",{parentName:"p"},"zstd")," should use for compression. If running a script or command on varying machines, use ",(0,o.kt)("inlineCode",{parentName:"p"},"T0")," to allow ",(0,o.kt)("inlineCode",{parentName:"p"},"zstd")," to detect the number of cores and run with the same number of threads as the detected cores. A speed-up can be obtained for machines with multiple threads per core by configuring a thread count near the number of threads. It is advisable to stay within the number of CPU threads. The recommendations in this article will use ",(0,o.kt)("inlineCode",{parentName:"p"},"-T0"),"."),(0,o.kt)("h3",{id:"long-distance-matching"},"Long-distance matching"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"--long=31")," argument is where we see the most space gained by the algorithm because it controls the size of the matching window in powers of 2 (2","*","*","31 is 2 GB). The downside is that it requires 2.0 GB memory during compression and decompression as it looks and rebuilds ahead. The default is 27 or 128 MB."),(0,o.kt)("p",null,"At compression 19, we see a 30 GB file using the default 128 MB look ahead, and a 13 GB file using 2 GB look ahead. Since all validators should have 16-32 GB of memory, we keep this at ",(0,o.kt)("inlineCode",{parentName:"p"},"--long=31"),"."),(0,o.kt)("p",null,"An important note is that decompression requires a compatible argument. Trying with a different long-distance matching value will result in an error. However, it will also return the necessary value to provide."),(0,o.kt)("h3",{id:"summary-of-commands"},"Summary of commands"),(0,o.kt)("p",null,"The general command for compression is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"tar -b 4096 -cv --sparse . | zstd -15 -cv -T0 --long=31 > [path_to]/file.tar.zst\n")),(0,o.kt)("p",null,"For local backups, use a lower compression level:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"tar -b 4096 -cv --sparse . | zstd -5 -cv -T0 --long=31 > [path_to]/file.tar.zst\n")),(0,o.kt)("h2",{id:"decompression"},"Decompression"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"zstd -d")," is the command for decompression; however, the same ",(0,o.kt)("inlineCode",{parentName:"p"},"--long")," value used for compression must be specified. For all ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," DB-related decompression, you will likely use this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"zstd -cd --long=31 <.tar.zst file>\n")),(0,o.kt)("p",null,"If ",(0,o.kt)("inlineCode",{parentName:"p"},"--long=31")," is omitted, you might see an error such as this, which also gives you the solution:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"./casper.tar.zst : Decoding error (36) : Frame requires too much memory for decoding\n./casper.tar.zst : Window size larger than maximum : 2147483648 > 134217728\n./casper.tar.zst : Use --long=31 or --memory=2048MB\n")),(0,o.kt)("p",null,"You can then use the ",(0,o.kt)("inlineCode",{parentName:"p"},"zstd")," result to populate a ",(0,o.kt)("inlineCode",{parentName:"p"},"tar -xv")," command. Also, create the decompressed files using ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo -u casper"),", because the files will be used by the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node"),". Run the following command inside an empty DB location:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"zstd -cd --long=31 <.tar.zst file> | sudo -u casper tar -xv\n")),(0,o.kt)("p",null,"To fix ownership, use this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo /etc/casper/node_util.py fix_permissions\n")),(0,o.kt)("h2",{id:"streamed-decompression"},"Streamed Decompression"),(0,o.kt)("p",null,"If a ",(0,o.kt)("inlineCode",{parentName:"p"},".tar.zst")," archive is hosted on a website and you will not need the file after decompressing, you can stream it into the process using ",(0,o.kt)("inlineCode",{parentName:"p"},"curl"),", which can output to stdout with ",(0,o.kt)("inlineCode",{parentName:"p"},"--output")," and stream binary to your terminal."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s --output - \n")),(0,o.kt)("p",null,"If you use the output along with the previous process, you can decompress the files from ",(0,o.kt)("inlineCode",{parentName:"p"},"curl")," directly into a local directory:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s --output - | zstd -d --long=31 | sudo -u casper tar -xv\n")),(0,o.kt)("h2",{id:"starting-a-new-node-with-a-decompressed-db"},"Starting a New Node with a Decompressed DB"),(0,o.kt)("p",null,"If you are starting a node with a decompressed DB, you must tell the node to run at the protocol version of the tip of your DB. You can do this most efficiently with the ",(0,o.kt)("inlineCode",{parentName:"p"},"node_util.py")," script included in the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," installation."),(0,o.kt)("p",null,"For example, if you are using a DB archive from node version 1.4.5, you would run this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo /etc/casper/node_util.py force_run_version 1_4_5\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/23dd64d8.c2310e27.js b/assets/js/23dd64d8.c2310e27.js deleted file mode 100644 index b65daad483..0000000000 --- a/assets/js/23dd64d8.c2310e27.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6717],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=p(n),m=r,h=c["".concat(l,".").concat(m)]||c[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},d),{},{components:n})):a.createElement(h,i({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var p=2;p [path_to]/file.tar.zst\n")),(0,o.kt)("h3",{id:"compression-level"},"Compression level"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"-[level]")," argument is the compression level from 1 to 19 (and 20-22 with expansion). In testing, we found 15 to be the sweet spot in compression time vs. size. We recommend lower compression if you plan to transfer the archive only once. If you are creating an archive to be downloaded by many, then the extra time for higher compression may be helpful."),(0,o.kt)("p",null,"Here are some examples of a Mainnet DB compression at block 741160:"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Level"),(0,o.kt)("th",{parentName:"tr",align:null},"Time (min:sec)"),(0,o.kt)("th",{parentName:"tr",align:null},"Size"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"12"),(0,o.kt)("td",{parentName:"tr",align:null},"29:20"),(0,o.kt)("td",{parentName:"tr",align:null},"15.8 GB")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"15"),(0,o.kt)("td",{parentName:"tr",align:null},"46:15"),(0,o.kt)("td",{parentName:"tr",align:null},"13.0 GB")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"17"),(0,o.kt)("td",{parentName:"tr",align:null},"87:42"),(0,o.kt)("td",{parentName:"tr",align:null},"13.0 GB")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},"19"),(0,o.kt)("td",{parentName:"tr",align:null},"197:08"),(0,o.kt)("td",{parentName:"tr",align:null},"12.9 GB")))),(0,o.kt)("p",null,"For local backups, using 1-5 is a great compression speed-to-size trade-off."),(0,o.kt)("h3",{id:"thread-count"},"Thread count"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"-T[thread count]")," is the number of threads that ",(0,o.kt)("inlineCode",{parentName:"p"},"zstd")," should use for compression. If running a script or command on varying machines, use ",(0,o.kt)("inlineCode",{parentName:"p"},"T0")," to allow ",(0,o.kt)("inlineCode",{parentName:"p"},"zstd")," to detect the number of cores and run with the same number of threads as the detected cores. A speed-up can be obtained for machines with multiple threads per core by configuring a thread count near the number of threads. It is advisable to stay within the number of CPU threads. The recommendations in this article will use ",(0,o.kt)("inlineCode",{parentName:"p"},"-T0"),"."),(0,o.kt)("h3",{id:"long-distance-matching"},"Long-distance matching"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"--long=31")," argument is where we see the most space gained by the algorithm because it controls the size of the matching window in powers of 2 (2","*","*","31 is 2 GB). The downside is that it requires 2.0 GB memory during compression and decompression as it looks and rebuilds ahead. The default is 27 or 128 MB."),(0,o.kt)("p",null,"At compression 19, we see a 30 GB file using the default 128 MB look ahead, and a 13 GB file using 2 GB look ahead. Since all validators should have 16-32 GB of memory, we keep this at ",(0,o.kt)("inlineCode",{parentName:"p"},"--long=31"),"."),(0,o.kt)("p",null,"An important note is that decompression requires a compatible argument. Trying with a different long-distance matching value will result in an error. However, it will also return the necessary value to provide."),(0,o.kt)("h3",{id:"summary-of-commands"},"Summary of commands"),(0,o.kt)("p",null,"The general command for compression is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"tar -b 4096 -cv --sparse . | zstd -15 -cv -T0 --long=31 > [path_to]/file.tar.zst\n")),(0,o.kt)("p",null,"For local backups, use a lower compression level:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"tar -b 4096 -cv --sparse . | zstd -5 -cv -T0 --long=31 > [path_to]/file.tar.zst\n")),(0,o.kt)("h2",{id:"decompression"},"Decompression"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"zstd -d")," is the command for decompression; however, the same ",(0,o.kt)("inlineCode",{parentName:"p"},"--long")," value used for compression must be specified. For all ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," DB-related decompression, you will likely use this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"zstd -cd --long=31 <.tar.zst file>\n")),(0,o.kt)("p",null,"If ",(0,o.kt)("inlineCode",{parentName:"p"},"--long=31")," is omitted, you might see an error such as this, which also gives you the solution:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"./casper.tar.zst : Decoding error (36) : Frame requires too much memory for decoding\n./casper.tar.zst : Window size larger than maximum : 2147483648 > 134217728\n./casper.tar.zst : Use --long=31 or --memory=2048MB\n")),(0,o.kt)("p",null,"You can then use the ",(0,o.kt)("inlineCode",{parentName:"p"},"zstd")," result to populate a ",(0,o.kt)("inlineCode",{parentName:"p"},"tar -xv")," command. Also, create the decompressed files using ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo -u casper"),", because the files will be used by the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node"),". Run the following command inside an empty DB location:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"zstd -cd --long=31 <.tar.zst file> | sudo -u casper tar -xv\n")),(0,o.kt)("p",null,"To fix ownership, use this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo /etc/casper/node_util.py fix_permissions\n")),(0,o.kt)("h2",{id:"streamed-decompression"},"Streamed Decompression"),(0,o.kt)("p",null,"If a ",(0,o.kt)("inlineCode",{parentName:"p"},".tar.zst")," archive is hosted on a website and you will not need the file after decompressing, you can stream it into the process using ",(0,o.kt)("inlineCode",{parentName:"p"},"curl"),", which can output to stdout with ",(0,o.kt)("inlineCode",{parentName:"p"},"--output")," and stream binary to your terminal."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s --output - \n")),(0,o.kt)("p",null,"If you use the output along with the previous process, you can decompress the files from ",(0,o.kt)("inlineCode",{parentName:"p"},"curl")," directly into a local directory:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s --output - | zstd -d --long=31 | sudo -u casper tar -xv\n")),(0,o.kt)("h2",{id:"starting-a-new-node-with-a-decompressed-db"},"Starting a New Node with a Decompressed DB"),(0,o.kt)("p",null,"If you are starting a node with a decompressed DB, you must tell the node to run at the protocol version of the tip of your DB. You can do this most efficiently with the ",(0,o.kt)("inlineCode",{parentName:"p"},"node_util.py")," script included in the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," installation."),(0,o.kt)("p",null,"For example, if you are using a DB archive from node version 1.4.5, you would run this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo /etc/casper/node_util.py force_run_version 1_4_5\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2747ce3a.aec386e3.js b/assets/js/2747ce3a.aec386e3.js deleted file mode 100644 index 21951a285c..0000000000 --- a/assets/js/2747ce3a.aec386e3.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2031],{3905:function(e,t,r){r.d(t,{Zo:function(){return l},kt:function(){return m}});var a=r(7294);function s(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function c(e){for(var t=1;t=0||(s[r]=e[r]);return s}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(s[r]=e[r])}return s}var o=a.createContext({}),i=function(e){var t=a.useContext(o),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},l=function(e){var t=i(e.components);return a.createElement(o.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var r=e.components,s=e.mdxType,n=e.originalType,o=e.parentName,l=p(e,["components","mdxType","originalType","parentName"]),u=i(r),h=s,m=u["".concat(o,".").concat(h)]||u[h]||d[h]||n;return r?a.createElement(m,c(c({ref:t},l),{},{components:r})):a.createElement(m,c({ref:t},l))}));function m(e,t){var r=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var n=r.length,c=new Array(n);c[0]=h;var p={};for(var o in t)hasOwnProperty.call(t,o)&&(p[o]=t[o]);p.originalType=e,p[u]="string"==typeof e?e:s,c[1]=p;for(var i=2;icasper-types",id:"casper-types",level:2},{value:"casper-contract",id:"casper-contract",level:2},{value:"casper-engine-test-support",id:"casper-engine-test-support",level:2},{value:"casper-node",id:"casper-node",level:2},{value:"casper-client",id:"casper-client",level:2},{value:"casper-event-standard",id:"casper-event-standard",level:2},{value:"casper-hashing",id:"casper-hashing",level:2},{value:"casper-wasm-utils",id:"casper-wasm-utils",level:2},{value:"cargo-casper",id:"cargo-casper",level:2},{value:"Other Libraries",id:"other-libraries",level:2}],d={toc:u},h="wrapper";function m(e){var t=e.components,r=(0,s.Z)(e,c);return(0,n.kt)(h,(0,a.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"essential-rust-crates"},"Essential Rust Crates"),(0,n.kt)("p",null,"Several Rust crates are available on ",(0,n.kt)("a",{parentName:"p",href:"https://crates.io/"},"crates.io")," to support smart contract development with Rust. A crate is a compilation unit that can be compiled into a binary or a library. The corresponding documentation is published on ",(0,n.kt)("a",{parentName:"p",href:"https://docs.rs"},"docs.rs"),". The most important crates are listed below."),(0,n.kt)("h2",{id:"casper-types"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-types")),(0,n.kt)("p",null,"Types shared by many Casper crates:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-types"},"https://crates.io/crates/casper-types")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-types/latest"},"https://docs.rs/casper-types/latest"))),(0,n.kt)("h2",{id:"casper-contract"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-contract")),(0,n.kt)("p",null,"A library for developing Casper smart contracts:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-contract"},"https://crates.io/crates/casper-contract")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest"},"https://docs.rs/casper-contract/latest"))),(0,n.kt)("h2",{id:"casper-engine-test-support"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-engine-test-support")),(0,n.kt)("p",null,"The Casper test support library:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-engine-test-support"},"https://crates.io/crates/casper-engine-test-support")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-engine-test-support/"},"https://docs.rs/casper-engine-test-support/"))),(0,n.kt)("h2",{id:"casper-node"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-node")),(0,n.kt)("p",null,"The component for running a node on a Casper network:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-node"},"https://crates.io/crates/casper-node")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-node/latest"},"https://docs.rs/casper-node/latest"))),(0,n.kt)("h2",{id:"casper-client"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-client")),(0,n.kt)("p",null,"A client library for interacting with a Casper network:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-client"},"https://crates.io/crates/casper-client")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-client/latest"},"https://docs.rs/casper-client/latest"))),(0,n.kt)("h2",{id:"casper-event-standard"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-event-standard")),(0,n.kt)("p",null,"A Rust library that provides a simple and standardized way for Casper contracts to emit events:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-event-standard"},"https://crates.io/crates/casper-event-standard")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-event-standard/latest"},"https://docs.rs/casper-event-standard/latest"))),(0,n.kt)("h2",{id:"casper-hashing"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-hashing")),(0,n.kt)("p",null,"A library providing hashing functionality including Merkle Proof utilities:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-hashing"},"https://crates.io/crates/casper-hashing")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-hashing/latest/"},"https://docs.rs/casper-hashing/latest/"))),(0,n.kt)("h2",{id:"casper-wasm-utils"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-wasm-utils")),(0,n.kt)("p",null,"Command-line utilities and corresponding Rust API for producing pwasm-compatible executables:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-wasm-utils"},"https://crates.io/crates/casper-wasm-utils")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-wasm-utils/latest"},"https://docs.rs/casper-wasm-utils/latest"))),(0,n.kt)("h2",{id:"cargo-casper"},(0,n.kt)("inlineCode",{parentName:"h2"},"cargo-casper")),(0,n.kt)("p",null,"A command line tool for creating a Wasm smart contract and tests:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/cargo-casper"},"https://crates.io/crates/cargo-casper")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/crate/cargo-casper/latest"},"https://docs.rs/crate/cargo-casper/latest"))),(0,n.kt)("h2",{id:"other-libraries"},"Other Libraries"),(0,n.kt)("p",null,"The ",(0,n.kt)("a",{parentName:"p",href:"/resources/build-on-casper/casper-open-source-software"},"Open-Source Software")," page provides other community-curated tools and libraries."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2747ce3a.f2ba58ef.js b/assets/js/2747ce3a.f2ba58ef.js new file mode 100644 index 0000000000..64a537b369 --- /dev/null +++ b/assets/js/2747ce3a.f2ba58ef.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2031],{3905:function(e,t,r){r.d(t,{Zo:function(){return l},kt:function(){return m}});var a=r(7294);function s(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function c(e){for(var t=1;t=0||(s[r]=e[r]);return s}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(s[r]=e[r])}return s}var o=a.createContext({}),i=function(e){var t=a.useContext(o),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},l=function(e){var t=i(e.components);return a.createElement(o.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var r=e.components,s=e.mdxType,n=e.originalType,o=e.parentName,l=p(e,["components","mdxType","originalType","parentName"]),u=i(r),h=s,m=u["".concat(o,".").concat(h)]||u[h]||d[h]||n;return r?a.createElement(m,c(c({ref:t},l),{},{components:r})):a.createElement(m,c({ref:t},l))}));function m(e,t){var r=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var n=r.length,c=new Array(n);c[0]=h;var p={};for(var o in t)hasOwnProperty.call(t,o)&&(p[o]=t[o]);p.originalType=e,p[u]="string"==typeof e?e:s,c[1]=p;for(var i=2;icasper-types",id:"casper-types",level:2},{value:"casper-contract",id:"casper-contract",level:2},{value:"casper-engine-test-support",id:"casper-engine-test-support",level:2},{value:"casper-node",id:"casper-node",level:2},{value:"casper-client",id:"casper-client",level:2},{value:"casper-event-standard",id:"casper-event-standard",level:2},{value:"casper-hashing",id:"casper-hashing",level:2},{value:"casper-wasm-utils",id:"casper-wasm-utils",level:2},{value:"cargo-casper",id:"cargo-casper",level:2},{value:"Other Libraries",id:"other-libraries",level:2}],d={toc:u},h="wrapper";function m(e){var t=e.components,r=(0,s.Z)(e,c);return(0,n.kt)(h,(0,a.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"essential-rust-crates"},"Essential Rust Crates"),(0,n.kt)("p",null,"Several Rust crates are available on ",(0,n.kt)("a",{parentName:"p",href:"https://crates.io/"},"crates.io")," to support smart contract development with Rust. A crate is a compilation unit that can be compiled into a binary or a library. The corresponding documentation is published on ",(0,n.kt)("a",{parentName:"p",href:"https://docs.rs"},"docs.rs"),". The most important crates are listed below."),(0,n.kt)("h2",{id:"casper-types"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-types")),(0,n.kt)("p",null,"Types shared by many Casper crates:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-types"},"https://crates.io/crates/casper-types")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-types/latest"},"https://docs.rs/casper-types/latest"))),(0,n.kt)("h2",{id:"casper-contract"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-contract")),(0,n.kt)("p",null,"A library for developing Casper smart contracts:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-contract"},"https://crates.io/crates/casper-contract")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest"},"https://docs.rs/casper-contract/latest"))),(0,n.kt)("h2",{id:"casper-engine-test-support"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-engine-test-support")),(0,n.kt)("p",null,"The Casper test support library:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-engine-test-support"},"https://crates.io/crates/casper-engine-test-support")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-engine-test-support/"},"https://docs.rs/casper-engine-test-support/"))),(0,n.kt)("h2",{id:"casper-node"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-node")),(0,n.kt)("p",null,"The component for running a node on a Casper network:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-node"},"https://crates.io/crates/casper-node")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-node/latest"},"https://docs.rs/casper-node/latest"))),(0,n.kt)("h2",{id:"casper-client"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-client")),(0,n.kt)("p",null,"A client library for interacting with a Casper network:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-client"},"https://crates.io/crates/casper-client")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-client/latest"},"https://docs.rs/casper-client/latest"))),(0,n.kt)("h2",{id:"casper-event-standard"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-event-standard")),(0,n.kt)("p",null,"A Rust library that provides a simple and standardized way for Casper contracts to emit events:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-event-standard"},"https://crates.io/crates/casper-event-standard")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-event-standard/latest"},"https://docs.rs/casper-event-standard/latest"))),(0,n.kt)("h2",{id:"casper-hashing"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-hashing")),(0,n.kt)("p",null,"A library providing hashing functionality including Merkle Proof utilities:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-hashing"},"https://crates.io/crates/casper-hashing")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-hashing/latest/"},"https://docs.rs/casper-hashing/latest/"))),(0,n.kt)("h2",{id:"casper-wasm-utils"},(0,n.kt)("inlineCode",{parentName:"h2"},"casper-wasm-utils")),(0,n.kt)("p",null,"Command-line utilities and corresponding Rust API for producing pwasm-compatible executables:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-wasm-utils"},"https://crates.io/crates/casper-wasm-utils")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/casper-wasm-utils/latest"},"https://docs.rs/casper-wasm-utils/latest"))),(0,n.kt)("h2",{id:"cargo-casper"},(0,n.kt)("inlineCode",{parentName:"h2"},"cargo-casper")),(0,n.kt)("p",null,"A command line tool for creating a Wasm smart contract and tests:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://crates.io/crates/cargo-casper"},"https://crates.io/crates/cargo-casper")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://docs.rs/crate/cargo-casper/latest"},"https://docs.rs/crate/cargo-casper/latest"))),(0,n.kt)("h2",{id:"other-libraries"},"Other Libraries"),(0,n.kt)("p",null,"The ",(0,n.kt)("a",{parentName:"p",href:"/resources/build-on-casper/casper-open-source-software"},"Open-Source Software")," page provides other community-curated tools and libraries."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/27a494b1.33c693e7.js b/assets/js/27a494b1.43fa8b10.js similarity index 51% rename from assets/js/27a494b1.33c693e7.js rename to assets/js/27a494b1.43fa8b10.js index 0f4a3d3774..18431a9d05 100644 --- a/assets/js/27a494b1.33c693e7.js +++ b/assets/js/27a494b1.43fa8b10.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6109],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return h}});var r=n(7294);function s(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var u=r.createContext({}),c=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(u.Provider,{value:t},e.children)},l="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,s=e.mdxType,a=e.originalType,u=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),l=c(n),f=s,h=l["".concat(u,".").concat(f)]||l[f]||d[f]||a;return n?r.createElement(h,o(o({ref:t},p),{},{components:n})):r.createElement(h,o({ref:t},p))}));function h(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var a=n.length,o=new Array(a);o[0]=f;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i[l]="string"==typeof e?e:s,o[1]=i;for(var c=2;c=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var u=r.createContext({}),c=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(u.Provider,{value:t},e.children)},l="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,s=e.mdxType,a=e.originalType,u=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),l=c(n),f=s,h=l["".concat(u,".").concat(f)]||l[f]||d[f]||a;return n?r.createElement(h,o(o({ref:t},p),{},{components:n})):r.createElement(h,o({ref:t},p))}));function h(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var a=n.length,o=new Array(a);o[0]=f;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i[l]="string"==typeof e?e:s,o[1]=i;for(var c=2;c=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),f=r,h=u["".concat(c,".").concat(f)]||u[f]||d[f]||a;return n?o.createElement(h,i(i({ref:t},p),{},{components:n})):o.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var l=2;l /\n--chain-name /\n--secret-key /\n--session-path /\n--payment-amount \n--speculative-exec \n\n")),(0,a.kt)("p",null,"You should receive ",(0,a.kt)("inlineCode",{parentName:"p"},"execution_result"),"s that show a ",(0,a.kt)("inlineCode",{parentName:"p"},"cost"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "id": -4571113357017152230,\n "result": {\n "api_version": "1.0.0",\n "block_hash": "6ca035b08de092e7f5e8fff771b880c5b4d7463a8f7a9b108888aaad958e5b0f",\n "execution_result": {\n "Success": {\n "effect": {\n \n },\n "transfers": [],\n "cost": "87300473670"\n }\n }\n }\n}\n\n')),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"Cost estimates acquired through ",(0,a.kt)("inlineCode",{parentName:"p"},"speculative_exec")," may vary from the cost of sending the same Deploy to a Casper network. Speculative execution is a tool to help narrow down the potential cost of sending a Deploy, but many factors can cause the actual cost to vary.")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/298ce658.9028325a.js b/assets/js/298ce658.9028325a.js new file mode 100644 index 0000000000..33dc587bba --- /dev/null +++ b/assets/js/298ce658.9028325a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2881],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return h}});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),f=r,h=u["".concat(c,".").concat(f)]||u[f]||d[f]||a;return n?o.createElement(h,i(i({ref:t},p),{},{components:n})):o.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=f;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var l=2;l /\n--chain-name /\n--secret-key /\n--session-path /\n--payment-amount \n--speculative-exec \n\n")),(0,a.kt)("p",null,"You should receive ",(0,a.kt)("inlineCode",{parentName:"p"},"execution_result"),"s that show a ",(0,a.kt)("inlineCode",{parentName:"p"},"cost"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "id": -4571113357017152230,\n "result": {\n "api_version": "1.0.0",\n "block_hash": "6ca035b08de092e7f5e8fff771b880c5b4d7463a8f7a9b108888aaad958e5b0f",\n "execution_result": {\n "Success": {\n "effect": {\n \n },\n "transfers": [],\n "cost": "87300473670"\n }\n }\n }\n}\n\n')),(0,a.kt)("admonition",{type:"note"},(0,a.kt)("p",{parentName:"admonition"},"Cost estimates acquired through ",(0,a.kt)("inlineCode",{parentName:"p"},"speculative_exec")," may vary from the cost of sending the same Deploy to a Casper network. Speculative execution is a tool to help narrow down the potential cost of sending a Deploy, but many factors can cause the actual cost to vary.")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2a99fafe.528c3d19.js b/assets/js/2a99fafe.528c3d19.js deleted file mode 100644 index 80101e76cd..0000000000 --- a/assets/js/2a99fafe.528c3d19.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6263],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function c(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),l=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(i,".").concat(h)]||u[h]||d[h]||o;return n?a.createElement(m,c(c({ref:t},p),{},{components:n})):a.createElement(m,c({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=h;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:r,c[1]=s;for(var l=2;l()\n .expect("should be u32.");\n\n assert_eq!(version, 2);\n'))),(0,o.kt)("p",null,"You can also test the new entry point by using the Rust command-line client."),(0,o.kt)("p",null,"Get the NEW state-root-hash:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address http://[NODE_IP]:7777\n")),(0,o.kt)("p",null,"Check the new contract entry points. You should see the ",(0,o.kt)("em",{parentName:"p"},"counter_decrement")," entry point now."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://[NODE_IP]:7777 \\\n --state-root-hash [STATE_ROOT_HASH] \\\n --key [ACCOUNT_HASH] -q "counter"\n')),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example output"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},' {\n "id": 5602352547578277096,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[54054 hex chars]",\n "stored_value": {\n "Contract": {\n "contract_package_hash": "contract-package-wasmc014187ccf3366cca70317d6d567cd56a05ecf1ee50ed3bd02727c2864e3d3a8",\n "contract_wasm_hash": "contract-wasm-64d252f1ab72c7295a85d15c3f456f8bdda586580b0b7106e203fa4fd83f05d7",\n "entry_points": [\n {\n "access": "Public",\n "args": [],\n "entry_point_type": "Contract",\n "name": "counter_decrement",\n "ret": "Unit"\n },\n {\n "access": "Public",\n "args": [],\n "entry_point_type": "Contract",\n "name": "counter_get",\n "ret": "I32"\n },\n {\n "access": "Public",\n "args": [],\n "entry_point_type": "Contract",\n "name": "counter_inc",\n "ret": "Unit"\n }\n ],\n "named_keys": [\n {\n "key": "uref-ca980a2e4c08dc3f233b728b22b909cd4e894295155a7902bf88a59eac1531d1-007",\n "name": "count"\n }\n ],\n "protocol_version": "1.4.13"\n }\n }\n }\n}\n'))),(0,o.kt)("p",null,"Check the version and package details with the latest state root hash:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://[NODE_IP]:7777 \\\n --state-root-hash [STATE_ROOT_HASH] \\\n --key [ACCOUNT_HASH] -q "version"\n')),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example output"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'{\n "id": 9084525900533244372,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[64874 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "02000000",\n "cl_type": "U32",\n "parsed": 2\n }\n }\n }\n\n'))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://[NODE_IP]:7777 \\\n --state-root-hash [STATE_ROOT_HASH] \\\n --key [ACCOUNT_HASH] -q "counter_package_name"\n')),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example output"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'{\n "id": 6933525663267881367,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[52174 hex chars]",\n "stored_value": {\n "ContractPackage": {\n "access_key": "uref-101817ffd5aa47b08ca710649dbdc41edf0a20d7802c736d34053656c0a99eaf-007",\n "disabled_versions": [],\n "groups": [],\n "versions": [\n {\n "contract_hash": "contract-4ee8a4cfbc0a183d189611b6a14c0f7b57e7635fa17a8acfc5c645fec4c36316",\n "contract_version": 1,\n "protocol_version_major": 1\n },\n {\n "contract_hash": "contract-2cd9f6485423ba846fae83729016b03df26d9babb939466906c8f1d168b40949",\n "contract_version": 2,\n "protocol_version_major": 1\n }\n ]\n }\n }\n }\n}\n\n\n'))),(0,o.kt)("p",null,"Call the new entry point, ",(0,o.kt)("em",{parentName:"p"},"counter_decrement"),", using the package name and check the results."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address http://[NODE_IP]:7777 \\\n --chain-name [CHAIN_NAME] \\\n --secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \\\n --payment-amount [PAYMENT_AMOUNT_IN_MOTES] \\\n --session-package-name "counter_package_name" \\\n --session-entry-point "counter_decrement"\n')),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"There are two ways to call versioned contracts:"),(0,o.kt)("ol",{parentName:"admonition"},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/calling-contracts/#StoredVersionedContractByHash"},"Calling Contracts by Package Hash")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/calling-contracts/#StoredVersionedContractByName"},"Calling Contracts by Package Name")))),(0,o.kt)("p",null,"After calling the entry point, the count value should be decremented. You can verify it by querying the network again using the new state root hash."),(0,o.kt)("h2",{id:"disabling-and-enabling-contract-versions"},"Disabling and Enabling Contract Versions"),(0,o.kt)("p",null,"You can disable a contract version within a contract package by using the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.disable_contract_version.html"},"disable_contract_version")," function."),(0,o.kt)("p",null,"Disabled contract versions can no longer be executed. As such, if there is only a single contract version within the package, you will no longer be able to use the contract."),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.enable_contract_version.html"},"Enable_contract_version")," allows you to re-enable a previously disabled contract version."),(0,o.kt)("p",null,"::note"),(0,o.kt)("p",null,"Be aware that calling a contract package will use the most recent contract version. It is not necessary to disable a previous contract version, unless you have a specific need to do so."),(0,o.kt)("p",null,":::"),(0,o.kt)("h2",{id:"locked-contract-package"},"Creating a Locked Contract Package"),(0,o.kt)("p",null,"You can create a locked contract package with the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_locked_contract.html"},"new_locked_contract")," function. This contract can never be upgraded."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'let (stored_contract_hash, _) = storage::new_locked_contract(\n contract_entry_points,\n Some(contract_named_keys),\n Some("contract_package_name".to_string()),\n Some("contract_access_uref".to_string()),\n);\n')),(0,o.kt)("p",null,"Apply the contract entry points and named keys when you call the function. You can also specify a hash_name and uref_name that will be put in the context's named keys. You do not need to save the version number returned since the version of this contract package would always be equal to 1."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Creating a locked contract package is an irreversible decision. To upgrade a contract, use ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_contract.html"},"new_contract")," as Step 1 explains.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2a99fafe.d2eb3836.js b/assets/js/2a99fafe.d2eb3836.js new file mode 100644 index 0000000000..b061c67300 --- /dev/null +++ b/assets/js/2a99fafe.d2eb3836.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6263],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function c(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),l=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(i,".").concat(h)]||u[h]||d[h]||o;return n?a.createElement(m,c(c({ref:t},p),{},{components:n})):a.createElement(m,c({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,c=new Array(o);c[0]=h;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:r,c[1]=s;for(var l=2;l()\n .expect("should be u32.");\n\n assert_eq!(version, 2);\n'))),(0,o.kt)("p",null,"You can also test the new entry point by using the Rust command-line client."),(0,o.kt)("p",null,"Get the NEW state-root-hash:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address http://[NODE_IP]:7777\n")),(0,o.kt)("p",null,"Check the new contract entry points. You should see the ",(0,o.kt)("em",{parentName:"p"},"counter_decrement")," entry point now."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://[NODE_IP]:7777 \\\n --state-root-hash [STATE_ROOT_HASH] \\\n --key [ACCOUNT_HASH] -q "counter"\n')),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example output"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},' {\n "id": 5602352547578277096,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[54054 hex chars]",\n "stored_value": {\n "Contract": {\n "contract_package_hash": "contract-package-wasmc014187ccf3366cca70317d6d567cd56a05ecf1ee50ed3bd02727c2864e3d3a8",\n "contract_wasm_hash": "contract-wasm-64d252f1ab72c7295a85d15c3f456f8bdda586580b0b7106e203fa4fd83f05d7",\n "entry_points": [\n {\n "access": "Public",\n "args": [],\n "entry_point_type": "Contract",\n "name": "counter_decrement",\n "ret": "Unit"\n },\n {\n "access": "Public",\n "args": [],\n "entry_point_type": "Contract",\n "name": "counter_get",\n "ret": "I32"\n },\n {\n "access": "Public",\n "args": [],\n "entry_point_type": "Contract",\n "name": "counter_inc",\n "ret": "Unit"\n }\n ],\n "named_keys": [\n {\n "key": "uref-ca980a2e4c08dc3f233b728b22b909cd4e894295155a7902bf88a59eac1531d1-007",\n "name": "count"\n }\n ],\n "protocol_version": "1.4.13"\n }\n }\n }\n}\n'))),(0,o.kt)("p",null,"Check the version and package details with the latest state root hash:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://[NODE_IP]:7777 \\\n --state-root-hash [STATE_ROOT_HASH] \\\n --key [ACCOUNT_HASH] -q "version"\n')),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example output"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'{\n "id": 9084525900533244372,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[64874 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "02000000",\n "cl_type": "U32",\n "parsed": 2\n }\n }\n }\n\n'))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://[NODE_IP]:7777 \\\n --state-root-hash [STATE_ROOT_HASH] \\\n --key [ACCOUNT_HASH] -q "counter_package_name"\n')),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example output"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'{\n "id": 6933525663267881367,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[52174 hex chars]",\n "stored_value": {\n "ContractPackage": {\n "access_key": "uref-101817ffd5aa47b08ca710649dbdc41edf0a20d7802c736d34053656c0a99eaf-007",\n "disabled_versions": [],\n "groups": [],\n "versions": [\n {\n "contract_hash": "contract-4ee8a4cfbc0a183d189611b6a14c0f7b57e7635fa17a8acfc5c645fec4c36316",\n "contract_version": 1,\n "protocol_version_major": 1\n },\n {\n "contract_hash": "contract-2cd9f6485423ba846fae83729016b03df26d9babb939466906c8f1d168b40949",\n "contract_version": 2,\n "protocol_version_major": 1\n }\n ]\n }\n }\n }\n}\n\n\n'))),(0,o.kt)("p",null,"Call the new entry point, ",(0,o.kt)("em",{parentName:"p"},"counter_decrement"),", using the package name and check the results."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address http://[NODE_IP]:7777 \\\n --chain-name [CHAIN_NAME] \\\n --secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \\\n --payment-amount [PAYMENT_AMOUNT_IN_MOTES] \\\n --session-package-name "counter_package_name" \\\n --session-entry-point "counter_decrement"\n')),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"There are two ways to call versioned contracts:"),(0,o.kt)("ol",{parentName:"admonition"},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/calling-contracts/#StoredVersionedContractByHash"},"Calling Contracts by Package Hash")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/calling-contracts/#StoredVersionedContractByName"},"Calling Contracts by Package Name")))),(0,o.kt)("p",null,"After calling the entry point, the count value should be decremented. You can verify it by querying the network again using the new state root hash."),(0,o.kt)("h2",{id:"disabling-and-enabling-contract-versions"},"Disabling and Enabling Contract Versions"),(0,o.kt)("p",null,"You can disable a contract version within a contract package by using the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.disable_contract_version.html"},"disable_contract_version")," function."),(0,o.kt)("p",null,"Disabled contract versions can no longer be executed. As such, if there is only a single contract version within the package, you will no longer be able to use the contract."),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.enable_contract_version.html"},"Enable_contract_version")," allows you to re-enable a previously disabled contract version."),(0,o.kt)("p",null,"::note"),(0,o.kt)("p",null,"Be aware that calling a contract package will use the most recent contract version. It is not necessary to disable a previous contract version, unless you have a specific need to do so."),(0,o.kt)("p",null,":::"),(0,o.kt)("h2",{id:"locked-contract-package"},"Creating a Locked Contract Package"),(0,o.kt)("p",null,"You can create a locked contract package with the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_locked_contract.html"},"new_locked_contract")," function. This contract can never be upgraded."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'let (stored_contract_hash, _) = storage::new_locked_contract(\n contract_entry_points,\n Some(contract_named_keys),\n Some("contract_package_name".to_string()),\n Some("contract_access_uref".to_string()),\n);\n')),(0,o.kt)("p",null,"Apply the contract entry points and named keys when you call the function. You can also specify a hash_name and uref_name that will be put in the context's named keys. You do not need to save the version number returned since the version of this contract package would always be equal to 1."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Creating a locked contract package is an irreversible decision. To upgrade a contract, use ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_contract.html"},"new_contract")," as Step 1 explains.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2bee511f.5f6d74f7.js b/assets/js/2bee511f.5f6d74f7.js deleted file mode 100644 index 655c06e0d4..0000000000 --- a/assets/js/2bee511f.5f6d74f7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8933],{3905:function(e,t,a){a.d(t,{Zo:function(){return d},kt:function(){return h}});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),m=p(a),k=i,h=m["".concat(s,".").concat(k)]||m[k]||u[k]||l;return a?n.createElement(h,r(r({ref:t},d),{},{components:a})):n.createElement(h,r({ref:t},d))}));function h(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=a.length,r=new Array(l);r[0]=k;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[m]="string"==typeof e?e:i,r[1]=o;for(var p=2;pFailure",id:"failure",level:3},{value:"Success",id:"success",level:3},{value:"Group",id:"group",level:2},{value:"Groups",id:"groups",level:2},{value:"Keys",id:"serialization-standard-state-keys",level:2},{value:"Account identity key",id:"global-state-account-key",level:3},{value:"Hash key",id:"serialization-standard-hash-key",level:3},{value:"Unforgeable Reference (URef)",id:"serialization-standard-uref",level:3},{value:"Transfer Key",id:"serialization-standard-transfer-key",level:3},{value:"DeployInfo Key",id:"serialization-standard-deploy-info-key",level:3},{value:"EraInfo Key",id:"serialization-standard-era-info-key",level:3},{value:"Serialization for Key",id:"serialization-standard-serialization-key",level:3},{value:"Permissions",id:"serialization-standard-permissions",level:2},{value:"NamedArg",id:"namedarg",level:2},{value:"NamedKey",id:"namedkey",level:2},{value:"Operation",id:"operation",level:2},{value:"Parameter",id:"parameter",level:2},{value:"ProtocolVersion",id:"protocolversion",level:2},{value:"PublicKey",id:"publickey",level:2},{value:"RuntimeArgs",id:"runtimeargs",level:2},{value:"SeigniorageAllocation",id:"seigniorageallocation",level:2},{value:"Signature",id:"signature",level:2},{value:"SystemContractRegistry",id:"systemcontractregistry",level:2},{value:"TimeDiff",id:"timediff",level:2},{value:"Timestamp",id:"timestamp",level:2},{value:"TransferAddr",id:"transferaddr",level:2},{value:"Transform",id:"transform",level:2},{value:"TransformEntry",id:"transformentry",level:2},{value:"UnbondingPurse",id:"unbondingpurse",level:2},{value:"Values",id:"serialization-standard-values",level:2},{value:"CLValue",id:"clvalue",level:3},{value:"Boolean",id:"clvalue-boolean",level:4},{value:"Numeric",id:"clvalue-numeric",level:4},{value:"Unit",id:"clvalue-unit",level:4},{value:"String",id:"clvalue-string",level:4},{value:"Option",id:"clvalue-option",level:4},{value:"List",id:"clvalue-list",level:4},{value:"ByteArray",id:"clvalue-ByteArray",level:4},{value:"Result",id:"clvalue-result",level:4},{value:"Tuple",id:"clvalue-tuple",level:4},{value:"Map",id:"clvalue-map",level:4},{value:"URef",id:"clvalue-uref",level:4},{value:"PublicKey",id:"clvalue-publickey",level:4},{value:"Key",id:"clvalue-key",level:4},{value:"CLType",id:"clvalue-cltype",level:4},{value:"CLValue",id:"clvalue-clvalue",level:4},{value:"Contracts",id:"global-state-contracts",level:3},{value:"WithdrawPurse",id:"withdrawpurse",level:2}],u={toc:m},k="wrapper";function h(e){var t=e.components,a=(0,i.Z)(e,r);return(0,l.kt)(k,(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"serialization-standard-head"},"Serialization Standard"),(0,l.kt)("p",null,"We provide a custom implementation to serialize data structures used by the Casper node to their byte representation. This document details how this custom serialization is implemented, allowing developers to build a library that implements the custom serialization."),(0,l.kt)("p",null,"In your smart contracts, you can implement serialization using ",(0,l.kt)("inlineCode",{parentName:"p"},"cltype-any"),"."),(0,l.kt)("h2",{id:"serialization-standard-account"},"Account"),(0,l.kt)("p",null,"An Account is a structure that represents a user on a Casper network. The account structure consists of the following fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#account-hash"},(0,l.kt)("inlineCode",{parentName:"a"},"account_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#namedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"named_keys")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"main_purse")),(0,l.kt)("p",{parentName:"li"},"The account's main purse ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),". You may find information on ",(0,l.kt)("inlineCode",{parentName:"p"},"URef")," serialization ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},"here"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#associated-keys"},(0,l.kt)("inlineCode",{parentName:"a"},"associated_keys")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#action-thresholds"},(0,l.kt)("inlineCode",{parentName:"a"},"action_thresholds"))))),(0,l.kt)("h2",{id:"account-hash"},"Account Hash"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash of the public key, representing the address of a user's account. The account hash serializes as a 32-byte buffer containing the bytes of the account hash."),(0,l.kt)("h2",{id:"action-thresholds"},"Action Thresholds"),(0,l.kt)("p",null,"The minimum weight thresholds that have to be met when executing an action of a certain type. It serializes as two consecutive ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u8")," values")," as follows."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"deployment")," The minimum weight threshold required to perform deployment actions as a ",(0,l.kt)("inlineCode",{parentName:"p"},"u8")," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key_management")," The minimum weight threshold required to perform key management actions as a ",(0,l.kt)("inlineCode",{parentName:"p"},"u8")," value."))),(0,l.kt)("h2",{id:"activation-point"},"Activation Point"),(0,l.kt)("p",null,"The first era to which the associated protocol version applies. It serializes as a single ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u8"))," tag indicating if the era in question is genesis. If it is the genesis era, the following bytes will be a ",(0,l.kt)("inlineCode",{parentName:"p"},"timestamp"),". If not, the bytes represent an ",(0,l.kt)("inlineCode",{parentName:"p"},"era_id"),"."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"era_id")," An ",(0,l.kt)("a",{parentName:"p",href:"#eraid"},"Era ID newtype")," identifying the era when the protocol version will activate.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"timestamp")," A ",(0,l.kt)("a",{parentName:"p",href:"#timestamp"},"timestamp")," if the activation point is of the Genesis variant."))),(0,l.kt)("h2",{id:"approval"},"Approval"),(0,l.kt)("p",null,"A struct containing a signature and the public key of the signer."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"signature")," The approval signature, which serializes as the byte representation of the ",(0,l.kt)("a",{parentName:"p",href:"#signature"},(0,l.kt)("inlineCode",{parentName:"a"},"Signature")),". The first byte within the signature is 1 in the case of an ",(0,l.kt)("inlineCode",{parentName:"p"},"Ed25519")," signature or 2 in the case of ",(0,l.kt)("inlineCode",{parentName:"p"},"Secp256k1"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"signer")," The public key of the approvals signer. It serializes to the byte representation of the ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),". If the ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"p"},"Ed25519")," key, then the first byte within the serialized buffer is 1 followed by the bytes of the key itself; else, in the case of ",(0,l.kt)("inlineCode",{parentName:"p"},"Secp256k1"),", the first byte is 2."))),(0,l.kt)("h2",{id:"associatedkey"},"AssociatedKey"),(0,l.kt)("p",null,"A key granted limited permissions to an Account, for purposes such as multisig. It is serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of keys and weights held within. The remainder consists of a repeating pattern of serialized named keys and then weights of the length dictated by the first four bytes."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"account_hash")," The ",(0,l.kt)("a",{parentName:"p",href:"#account-hash"},"account hash")," of the associated key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"weight")," The weight of an associated key. The weight serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u8")," value"),"."))),(0,l.kt)("h2",{id:"availableblockrange"},"AvailableBlockRange"),(0,l.kt)("p",null,"An unbroken, inclusive range of blocks. It serializes as two consecutive ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64")," values")," containing the following two fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"low")," The inclusive lower bound of the range.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"high")," - The inclusive upper bound of the range."))),(0,l.kt)("h2",{id:"bid"},"Bid"),(0,l.kt)("p",null,"An entry in the validator map. The structure consists of the following fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"validator_public_key")," The validator's public key. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"bonding_purse")," The purse used for bonding. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"Uref")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"staked_amount")," The amount of tokens staked by a validator (not including delegators). It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegation_rate")," The delegation rate of the bid. It serializes as an ",(0,l.kt)("inlineCode",{parentName:"p"},"i32")," signed 32-bit integer primitive.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"vesting_schedule")," The vesting schedule for a genesis validator. ",(0,l.kt)("inlineCode",{parentName:"p"},"None")," if it is a non-genesis validator. It serializes as an ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-option"},(0,l.kt)("inlineCode",{parentName:"a"},"Option")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegators")," The validator's delegators, indexed by their public keys. They are serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey"),"s and delegators held within. The remainder consists of a repeating pattern of serialized ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey"),"s and then delegators of the length dictated by the first four bytes.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"inactive")," If the validator has been evicted. A ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-boolean"},"boolean")," value that serializes as a single byte; ",(0,l.kt)("inlineCode",{parentName:"p"},"true")," maps to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", while ",(0,l.kt)("inlineCode",{parentName:"p"},"false")," maps to ",(0,l.kt)("inlineCode",{parentName:"p"},"0"),"."))),(0,l.kt)("h2",{id:"serialization-standard-block"},"Block"),(0,l.kt)("p",null,"A block is the core component of the Casper linear blockchain, used in two contexts:"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"A data structure containing a collection of transactions. Blocks form the primary structure of the blockchain."),(0,l.kt)("li",{parentName:"ol"},"A message that is exchanged between nodes containing the data structure as explained in (1).")),(0,l.kt)("p",null,"Each block has a globally unique ID, achieved by hashing the contents of the block."),(0,l.kt)("p",null,"Each block points to its parent. An exception is the first block, which has no parent."),(0,l.kt)("p",null,"A block is structurally defined as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"hash"),": A hash over the header of the block."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"header"),": The header of the block that contains information about the contents of the block with additional metadata."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"body"),": The block's body contains the proposer of the block and hashes of deploys and transfers contained within it.")),(0,l.kt)("h3",{id:"block-hash"},"Block hash"),(0,l.kt)("p",null,"The block hash is a ",(0,l.kt)("inlineCode",{parentName:"p"},"Digest")," over the contents of the block Header. The ",(0,l.kt)("inlineCode",{parentName:"p"},"BlockHash")," serializes as the byte representation of the hash itself."),(0,l.kt)("h3",{id:"block-header"},"Block header"),(0,l.kt)("p",null,"The header portion of a block, structurally, is defined as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"parent_hash"),": is the hash of the parent block. It serializes to the byte representation of the parent hash. The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"li"},"parent_hash")," is 32 bytes long."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"state_root_hash"),": is the global state root hash produced by executing this block's body. It serializes to the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"state root hash"),". The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"li"},"state_root_hash")," is 32 bytes long."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"body_hash"),": the hash of the block body. It serializes to the byte representation of the body hash. The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"li"},"body_hash")," is 32 bytes long."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"random_bit"),": is a boolean needed for initializing a future era. It is serialized as a single byte; true maps to 1, while false maps to 0."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"accumulated_seed"),": A seed needed for initializing a future era. It serializes to the byte representation of the parent Hash. The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"li"},"accumulated_hash")," is 32 bytes long."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"era_end"),": contains equivocation and reward information to be included in the terminal finalized block. It is an optional field. Thus if the field is set as ",(0,l.kt)("inlineCode",{parentName:"li"},"None"),", it serializes to ",(0,l.kt)("em",{parentName:"li"},"0"),". The serialization of the other case is described in the EraEnd."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"timestamp"),": The timestamp from when the block was proposed. It serializes as a single ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value. The serialization of a ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value is described in the CLValues section."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"era_id"),": Era ID in which this block was created. It serializes as a single ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"height"),": The height of this block, i.e., the number of ancestors. It serializes as a single ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"protocol_version"),": The version of the Casper network when this block was proposed. It is 3-element tuple containing ",(0,l.kt)("inlineCode",{parentName:"li"},"u32")," values. It serializes as a buffer containing the three ",(0,l.kt)("inlineCode",{parentName:"li"},"u32")," serialized values. Refer to the CLValues section on how ",(0,l.kt)("inlineCode",{parentName:"li"},"u32")," values are serialized.")),(0,l.kt)("h3",{id:"serialization-standard-era-end"},"EraEnd"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"EraEnd")," as represented within the block header, is a struct containing two fields."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"era_report"),": The first field is termed as ",(0,l.kt)("inlineCode",{parentName:"li"},"EraReport")," and contains information about equivocators and rewards for an era."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"next_era_validator_weights"),": The second field is map for the validators and their weights for the era to follow.")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"EraReport")," itself contains two fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"equivocators"),": A vector of ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey"),"."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"rewards"),": A Binary Tree Map of ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," and ",(0,l.kt)("inlineCode",{parentName:"li"},"u64"),".")),(0,l.kt)("p",null,"When serializing an EraReport, the buffer is first filled with the individual serialization of the PublicKey contained within the vector."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key, the first byte within the buffer is a ",(0,l.kt)("inlineCode",{parentName:"li"},"1")," followed by the individual bytes of the serialized key."),(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1")," key, the first byte within the buffer is a ",(0,l.kt)("inlineCode",{parentName:"li"},"2")," followed by the individual bytes of the serialized key.")),(0,l.kt)("p",null,"When serializing the overarching struct of ",(0,l.kt)("inlineCode",{parentName:"p"},"EraEnd"),", we first allocate a buffer, which contains the serialized representation of the ",(0,l.kt)("inlineCode",{parentName:"p"},"EraReport")," as described above, followed by the serialized BTreeMap."),(0,l.kt)("p",null,"Note that ",(0,l.kt)("inlineCode",{parentName:"p"},"EraEnd")," is an optional field. Thus the above scheme only applies if there is an ",(0,l.kt)("inlineCode",{parentName:"p"},"EraEnd"),"; if there is no era end, the field simply serializes to ",(0,l.kt)("em",{parentName:"p"},"0"),"."),(0,l.kt)("h3",{id:"body"},"Body"),(0,l.kt)("p",null,"The body portion of the block is structurally defined as:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"proposer"),": The PublicKey which proposed this block."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"deploy_hashes"),": Is a vector of hex-encoded hashes identifying Deploys included in this block."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"transfer_hashes"),": Is a vector of hex-encoded hashes identifying Transfers included in this block.")),(0,l.kt)("p",null,"When we serialize the ",(0,l.kt)("inlineCode",{parentName:"p"},"BlockBody"),", we create a buffer that contains the serialized representations of the individual fields present within the block."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"proposer"),": serializes to the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey"),". If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key, then the first byte within the serialized buffer is 1 followed by the bytes of the key itself; else, in the case of ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1"),", the first byte is 2."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"deploy_hashes"),": serializes to the byte representation of all the deploy_hashes within the block header. Its length is ",(0,l.kt)("inlineCode",{parentName:"li"},"32 * n"),", where n denotes the number of deploy hashes present within the body."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"transfer_hashes"),": serializes to the byte representation of all the deploy_hashes within the block header. Its length is ",(0,l.kt)("inlineCode",{parentName:"li"},"32 * n"),", where n denotes the number of transfers present within the body.")),(0,l.kt)("h2",{id:"blockidentifier"},"BlockIdentifier"),(0,l.kt)("p",null,"Identifier for possible ways to retrieve a Block. It can consist of any of the following in most situations:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#block-hash"},(0,l.kt)("inlineCode",{parentName:"a"},"hash"))," Identify and retrieve a Block with its hash. The ",(0,l.kt)("inlineCode",{parentName:"p"},"BlockHash")," serializes as the byte representation of the hash itself.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"height")," Identify and retrieve the Block with its height. Height serializes as a single ",(0,l.kt)("inlineCode",{parentName:"p"},"u64")," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"state_root_hash")," Identify and retrieve the Block with its state root hash. It serializes to the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"p"},"state root hash"),". The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"p"},"state_root_hash")," is 32 bytes long."))),(0,l.kt)("h2",{id:"chainspecregistry"},"ChainspecRegistry"),(0,l.kt)("p",null,"ChainspecRegistry is a unique key variant which contains a mapping of file names to the hash of the file itself. This map includes ",(0,l.kt)("em",{parentName:"p"},"Chainspec.toml")," and may include ",(0,l.kt)("em",{parentName:"p"},"Accounts.toml")," and ",(0,l.kt)("em",{parentName:"p"},"GlobalState.toml"),". It is serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of names as strings and ",(0,l.kt)("a",{parentName:"p",href:"#digest"},"digests")," held within. The remainder consists of a repeating pattern of serialized strings and then digests of the length dictated by the first four bytes. Digests and their inclusion criteria are as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"chainspec_raw_hash")," will always be included.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"genesis_accounts_raw_hash")," may be included in specific circumstances.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"global_state_raw_hash")," may be included in specific circumstances."))),(0,l.kt)("h2",{id:"contract"},"Contract"),(0,l.kt)("p",null,"A contract struct containing the following fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contractpackagehash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_package_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contractwasmhash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_wasm_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#namedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"named_keys")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#entrypoint"},(0,l.kt)("inlineCode",{parentName:"a"},"entry_points")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#protocolversion"},(0,l.kt)("inlineCode",{parentName:"a"},"protocol_version"))))),(0,l.kt)("h2",{id:"contracthash"},"ContractHash"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash of a contract. The contract hash serializes as a 32-byte buffer containing the bytes of the contract hash."),(0,l.kt)("h2",{id:"contractpackagehash"},"ContractPackageHash"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash of a contract package. The contract package hash serializes as a 32-byte buffer containing the bytes of the contract package hash."),(0,l.kt)("h2",{id:"contractversion"},"ContractVersion"),(0,l.kt)("p",null,"The version of the contract."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contracthash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_hash"))," The contract hash of the contract.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract_version")," The version of the contract within the protocol major version. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version_major")," The major element of the protocol version this contract is compatible with. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32")," value"),"."))),(0,l.kt)("h2",{id:"contractwasmhash"},"ContractWasmHash"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash of a contract's Wasm. The contract's Wasm hash serializes as a 32-byte buffer containing the bytes of the contract's Wasm hash."),(0,l.kt)("h2",{id:"delegator"},"Delegator"),(0,l.kt)("p",null,'Represents a party delegating their stake to a validator (or "delegatee"). The structure consists of the following fields:'),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegator_public_key")," The public key of the delegator, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"staked_amount")," The amount staked by the delegator, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"bonding_purse")," The bonding purse associated with the delegation. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"validator_public_key")," The public key of the validator that the delegator will be delegating to, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"vesting_schedule")," The vesting schedule for the provided delegator bid. ",(0,l.kt)("inlineCode",{parentName:"p"},"None")," if it is a non-genesis validator. It serializes as an ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-option"},(0,l.kt)("inlineCode",{parentName:"a"},"Option")),"."))),(0,l.kt)("h2",{id:"serialization-standard-deploy"},"Deploy"),(0,l.kt)("p",null,"A deploy is a data structure containing a smart contract and the requester's signature(s). Additionally, the deploy header contains additional metadata about the deploy itself. A deploy is structurally defined as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"hash"),": The hash of the deploy header."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"header"),": Contains metadata about the deploy. The structure of the header is detailed further in this document."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"payment"),": The payment code for contained smart contract."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"session"),": The stored contract itself."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"approvals"),": A list of signatures:")),(0,l.kt)("h3",{id:"deploy-hash"},"Deploy-Hash"),(0,l.kt)("p",null,"The deploy hash is a digest over the contents of the deploy header. The deploy hash serializes as the byte representation of the hash itself."),(0,l.kt)("h3",{id:"deploy-header"},"Deploy-Header"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"account"),": A supported public key variant (currently either ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," or ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1"),"). An ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key is serialized as a buffer of bytes, with the leading byte being ",(0,l.kt)("inlineCode",{parentName:"li"},"1")," for ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519"),", with remainder of the buffer containing the byte representation of the signature. Correspondingly, a ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1")," key is serialized as a buffer of bytes, with the leading byte being ",(0,l.kt)("inlineCode",{parentName:"li"},"2"),"."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"timestamp"),": A timestamp is a struct that is a unary tuple containing a ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value. This value is a count of the milliseconds since the UNIX epoch. Thus the value ",(0,l.kt)("inlineCode",{parentName:"li"},"1603994401469")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0xbd3a847575010000")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"ttl"),": The ",(0,l.kt)("strong",{parentName:"li"},"Time to live")," is defined as the amount of time for which deploy is considered valid. The ",(0,l.kt)("inlineCode",{parentName:"li"},"ttl")," serializes in the same manner as the timestamp."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"gas_price"),": The gas is ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value which is serialized as ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," CLValue discussed below."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"body_hash"),": Body hash is a hash over the contents of the deploy body, which includes the payment, session, and approval fields. Its serialization is the byte representation of the hash itself."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"dependencies"),": Dependencies is a vector of deploy hashes referencing deploys that must execute before the current deploy can be executed. It serializes as a buffer containing the individual serialization of each DeployHash within the Vector."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"chain_name"),": Chain name is a human-readable string describing the name of the chain as detailed in the chainspec. It is serialized as a String CLValue described below.")),(0,l.kt)("h3",{id:"payment--session"},"Payment & Session"),(0,l.kt)("p",null,"Payment and Session are both defined as ",(0,l.kt)("inlineCode",{parentName:"p"},"ExecutableDeployItems"),". More information on ",(0,l.kt)("inlineCode",{parentName:"p"},"ExecutableDeployItems")," can be found ",(0,l.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/calling-contracts"},"here")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"Module Bytes are serialized such that the first byte within the serialized buffer is ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," with the rest of the buffer containing the bytes present."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'ModuleBytes { module_bytes: "[72 bytes]", args: 434705a38470ec2b008bb693426f47f330802f3bd63588ee275e943407649d3bab1898897ab0400d7fa09fe02ab7b7e8ea443d28069ca557e206916515a7e21d15e5be5eb46235f5 }')," will serialize to"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x0048000000420481b0d5a665c8a7678398103d4333c684461a71e9ee2a13f6e859fb6cd419ed5f8876fc6c3e12dce4385acc777edf42dcf8d8d844bf6a704e5b2446750559911a4a328d649ddd48000000434705a38470ec2b008bb693426f47f330802f3bd63588ee275e943407649d3bab1898897ab0400d7fa09fe02ab7b7e8ea443d28069ca557e206916515a7e21d15e5be5eb46235f5")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"StoredContractByHash serializes such that the first byte within the serialized buffer is 1u8. This is followed by the byte representation of the remaining fields."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'StoredContractByHash { hash: c4c411864f7b717c27839e56f6f1ebe5da3f35ec0043f437324325d65a22afa4, entry_point: "pclphXwfYmCmdITj8hnh", args: d8b59728274edd2334ea328b3292ed15eaf9134f9a00dce31a87d9050570fb0267a4002c85f3a8384d2502733b2e46f44981df85fed5e4854200bbca313e3bca8d888a84a76a1c5b1b3d236a12401a2999d3cad003c9b9d98c92ab1850 }')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x01c4c411864f7b717c27839e56f6f1ebe5da3f35ec0043f437324325d65a22afa41400000070636c7068587766596d436d6449546a38686e685d000000d8b59728274edd2334ea328b3292ed15eaf9134f9a00dce31a87d9050570fb0267a4002c85f3a8384d2502733b2e46f44981df85fed5e4854200bbca313e3bca8d888a84a76a1c5b1b3d236a12401a2999d3cad003c9b9d98c92ab1850")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"StoredContractByName serializes such that the first byte within the serialized buffer is 2u8. This is followed by the individual byte representation of the remaining fields."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'StoredContractByName { name: "U5A74bSZH8abT8HqVaK9", entry_point: "gIetSxltnRDvMhWdxTqQ", args: 07beadc3da884faa17454a }')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x0214000000553541373462535a483861625438487156614b39140000006749657453786c746e5244764d685764785471510b00000007beadc3da884faa17454a")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"StoredVersionedContractByHash serializes such that the first byte within the serialized buffer is 3u8. However, the field version within the enum serializes as an ",(0,l.kt)("a",{parentName:"p",href:"#option-clvalue-option"},"Option")," CLValue."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'StoredVersionedContractByHash { hash: b348fdd0d0b3f66468687df93141b5924f6bb957d5893c08b60d5a78d0b9a423, version: None, entry_point: "PsLz5c7JsqT8BK8ll0kF", args: 3d0d7f193f70740386cb78b383e2e30c4f976cf3fa834bafbda4ed9dbfeb52ce1777817e8ed8868cfac6462b7cd31028aa5a7a60066db35371a2f8 }')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x03b348fdd0d0b3f66468687df93141b5924f6bb957d5893c08b60d5a78d0b9a423001400000050734c7a3563374a73715438424b386c6c306b463b0000003d0d7f193f70740386cb78b383e2e30c4f976cf3fa834bafbda4ed9dbfeb52ce1777817e8ed8868cfac6462b7cd31028aa5a7a60066db35371a2f8")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"StoredVersionedContractByName serializes such that the first byte within the serialized buffer is 4u8. The name and entry_point are serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#string-clvalue-string"},"String")," CLValue, with the version field serializing as an ",(0,l.kt)("a",{parentName:"p",href:"#option-clvalue-option"},"Option"),"."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'StoredVersionedContractByName { name: "lWJWKdZUEudSakJzw1tn", version: Some(1632552656), entry_point: "S1cXRT3E1jyFlWBAIVQ8", args: 9975e6957ea6b07176c7d8471478fb28df9f02a61689ef58234b1a3cffaebf9f303e3ef60ae0d8 }')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x04140000006c574a574b645a5545756453616b4a7a7731746e01d0c64e61140000005331635852543345316a79466c57424149565138270000009975e6957ea6b07176c7d8471478fb28df9f02a61689ef58234b1a3cffaebf9f303e3ef60ae0d8")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"Transfer serializes such that the first byte within the serialized buffer contains is 5u8, with the remaining bytes of the buffer containing the bytes contained within the args field of Transfer."))),(0,l.kt)("h3",{id:"approval"},"Approval"),(0,l.kt)("p",null,"Approval contains two fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"signer"),": The public key of the approvals signer. It serializes to the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey"),". If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key, then the first byte within the serialized buffer is 1 followed by the bytes of the key itself; else, in the case of ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1"),", the first byte is 2."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"signature"),": The approval signature, which serializes as the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"Signature"),". The first byte within the signature is 1 in the case of an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," signature or 2 in the case of ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1"),".")),(0,l.kt)("h2",{id:"deployinfo"},"DeployInfo"),(0,l.kt)("p",null,"Information relating to a given deploy. The structure consists of the following fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"deploy_hash")," The hash of the relevant deploy, serialized as a byte representation of the hash itself.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"transfers")," Transfers performed by the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"from")," The account identifier of the creator of the deploy, serialized as an ",(0,l.kt)("a",{parentName:"p",href:"#account-hash"},(0,l.kt)("inlineCode",{parentName:"a"},"account_hash")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"source")," The source purse used for payment of the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"gas")," The gas cost of executing the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")),"."))),(0,l.kt)("h2",{id:"digest"},"Digest"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash digest. The digest serializes as a byte representation of the hash itself."),(0,l.kt)("h2",{id:"disabledversions"},"DisabledVersions"),(0,l.kt)("p",null,"Disabled contract versions, containing the following:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract_version")," The version of the contract within the protocol major version. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version_major")," The major element of the protocol version this contract is compatible with. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32")," value"),"."))),(0,l.kt)("h2",{id:"entrypoint"},"EntryPoint"),(0,l.kt)("p",null,"A type of signature method. Order of arguments matters, since this can be referenced by index as well as name."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," The name of the entry point, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"args")," Arguments for this method. They serialize as a list of the ",(0,l.kt)("a",{parentName:"p",href:"#parameter"},(0,l.kt)("inlineCode",{parentName:"a"},"Parameter")),"s, where each parameter represents an argument passed to the entrypoint.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"ret")," The return type of the method, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-unit"},(0,l.kt)("inlineCode",{parentName:"a"},"Unit")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"access")," An enum describing the possible access control options for a contract entry point. It serializes as a 1 for public or a 1 followed by a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List"))," of authorized users.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point_type")," Identifies the type of entry point. It serializes as a ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," for Session and a ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," for Contract."))),(0,l.kt)("h2",{id:"eraid"},"EraID"),(0,l.kt)("p",null,"An Era ID newtype. It serializes as a single ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64")," value"),"."),(0,l.kt)("h2",{id:"erainfo"},"EraInfo"),(0,l.kt)("p",null,"Auction metadata, intended to be recorded each era. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List"))," of ",(0,l.kt)("a",{parentName:"p",href:"#seigniorageallocation"},"seigniorage allocations"),"."),(0,l.kt)("h2",{id:"executioneffect"},"ExecutionEffect"),(0,l.kt)("p",null,"The journal of execution transforms from a single deploy."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"operations")," The resulting operations, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List"))," of ",(0,l.kt)("a",{parentName:"p",href:"#operation"},"operations"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"transforms")," The actual ",(0,l.kt)("a",{parentName:"p",href:"#transform"},"transformation")," performed while executing a deploy."))),(0,l.kt)("h2",{id:"executionresult"},"ExecutionResult"),(0,l.kt)("p",null,"The result of a single deploy. It serializes as a ",(0,l.kt)("inlineCode",{parentName:"p"},"u8")," tag indicating either ",(0,l.kt)("inlineCode",{parentName:"p"},"Failure")," as a 0 or ",(0,l.kt)("inlineCode",{parentName:"p"},"Success")," as a 1. This is followed by the appropriate structure below:"),(0,l.kt)("h3",{id:"failure"},(0,l.kt)("inlineCode",{parentName:"h3"},"Failure")),(0,l.kt)("p",null,"The result of a failed execution."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"effect")," The ",(0,l.kt)("a",{parentName:"p",href:"#executioneffect"},"effect")," of executing the deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"transfers")," A record of transfers performed while executing the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"cost")," The cost of executing the deploy, serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512"))," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"error_message")," The error message associated with executing the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String")),"."))),(0,l.kt)("h3",{id:"success"},(0,l.kt)("inlineCode",{parentName:"h3"},"Success")),(0,l.kt)("p",null,"The result of a successful execution."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"effect")," The ",(0,l.kt)("a",{parentName:"p",href:"#executioneffect"},"effect")," of executing the deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"transfers")," A record of transfers performed while executing the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"cost")," The cost of executing the deploy, serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512"))," value."))),(0,l.kt)("h2",{id:"group"},"Group"),(0,l.kt)("p",null,'A (labeled) "user group". Each method of a versioned contract may be associated with one or more user groups which are allowed to call it. User groups are serialized as a ',(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},"String"),"."),(0,l.kt)("h2",{id:"groups"},"Groups"),(0,l.kt)("p",null,"They are serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of user groups and ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeSets")," of ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),"s held within. The remainder consists of a repeating pattern of serialized user groups and ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeSets")," of the length dictated by the first four bytes."),(0,l.kt)("h2",{id:"serialization-standard-state-keys"},"Keys"),(0,l.kt)("p",null,'In this chapter, we describe what constitutes a "key", the permissions model for the keys, and how they are serialized.'),(0,l.kt)("p",null,"A ",(0,l.kt)("em",{parentName:"p"},"key")," in ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#global-state-head"},"Global State")," is one of the following data types:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},'32-byte account identifier (called an "account identity key")'),(0,l.kt)("li",{parentName:"ul"},'32-byte immutable contract identifier (called a "hash key")'),(0,l.kt)("li",{parentName:"ul"},'32-byte reference identifier (called an "unforgeable reference")'),(0,l.kt)("li",{parentName:"ul"},"32-byte transfer identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte deploy information identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte purse balance identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte Auction bid identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte Auction withdrawal identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte Dictionary identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte System Contract Registry"),(0,l.kt)("li",{parentName:"ul"},"32-byte Auction unbond identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte Chainspec Registry")),(0,l.kt)("p",null,"The one exception to note here is the identifier for ",(0,l.kt)("a",{parentName:"p",href:"#erainfo"},(0,l.kt)("inlineCode",{parentName:"a"},"EraInfo")),", which actually serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value with an additional byte for the tag."),(0,l.kt)("h3",{id:"global-state-account-key"},"Account identity key"),(0,l.kt)("p",null,"This key type is used specifically for accounts in the global state. All accounts in the system must be stored under an account identity key, and no other types. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the public key used to create the associated account (see ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-associated-keys-weights"},"Accounts")," for more information)."),(0,l.kt)("h3",{id:"serialization-standard-hash-key"},"Hash key"),(0,l.kt)("p",null,"This key type is used for storing contracts immutably. Once a contract is written under a hash key, that contract can never change. The 32-byte identifier representing this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the deploy hash (see ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"block-structure-head")," for more information) concatenated with a 4-byte sequential ID. The ID begins at zero for each deploy and increments by one each time a contract is stored. The purpose of this ID is to allow each contract stored in the same deploy to have a unique key."),(0,l.kt)("h3",{id:"serialization-standard-uref"},"Unforgeable Reference (",(0,l.kt)("inlineCode",{parentName:"h3"},"URef"),")"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"URef")," broadly speaking can be used to store values and manage permissions to interact with the value stored under the ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),". ",(0,l.kt)("inlineCode",{parentName:"p"},"URef")," is a tuple which contains the address under which the values are stored and the Access rights to the ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),". Refer to the ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#uref-head"},"Unforgeable Reference")," section for details on how ",(0,l.kt)("inlineCode",{parentName:"p"},"URefs")," are managed."),(0,l.kt)("h3",{id:"serialization-standard-transfer-key"},"Transfer Key"),(0,l.kt)("p",null,"This key type is used specifically for transfers in the global state. All transfers in the system must be stored under a transfer key and no other type. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the transfer address associated with the given transfer"),(0,l.kt)("h3",{id:"serialization-standard-deploy-info-key"},"DeployInfo Key"),(0,l.kt)("p",null,"This key type is used specifically for storing information related to deploys in the global state. Information for a given deploy is stored under this key only. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the deploy itself."),(0,l.kt)("h3",{id:"serialization-standard-era-info-key"},"EraInfo Key"),(0,l.kt)("p",null,"This key type is used specifically for storing information related to the ",(0,l.kt)("inlineCode",{parentName:"p"},"Auction")," metadata for a particular era. The underlying data type stored under this is a vector of the allocation of seigniorage for that given era. The identifier for this key is a new type that wraps around the primitive ",(0,l.kt)("inlineCode",{parentName:"p"},"u64")," data type and co-relates to the era number when the auction information was stored."),(0,l.kt)("p",null,"This key type is used specifically for storing information related to auction bids in the global state. Information for the bids is stored under this key only. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the public key used to create the associated account (see ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-associated-keys-weights"},"Accounts")," for more information)."),(0,l.kt)("p",null,"This key type is used specifically for storing information related to auction withdraws in the global state. Information for the withdrawals is stored under this key only. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the public key used to create the associated account (see ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-associated-keys-weights"},"Accounts")," for more information)."),(0,l.kt)("h3",{id:"serialization-standard-serialization-key"},"Serialization for ",(0,l.kt)("inlineCode",{parentName:"h3"},"Key")),(0,l.kt)("p",null,"Given the different variants for the over-arching ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," data-type, each of the different variants is serialized differently. This section of this chapter details how the individual variants are serialized. The leading byte of the serialized buffer acts as a tag indicating the serialized variant."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"th"},"Key")),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization Tag"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Account")),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Hash")),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"URef")),(0,l.kt)("td",{parentName:"tr",align:null},"2")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Transfer")),(0,l.kt)("td",{parentName:"tr",align:null},"3")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"DeployInfo")),(0,l.kt)("td",{parentName:"tr",align:null},"4")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"EraInfo")),(0,l.kt)("td",{parentName:"tr",align:null},"5")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Balance")),(0,l.kt)("td",{parentName:"tr",align:null},"6")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Bid")),(0,l.kt)("td",{parentName:"tr",align:null},"7")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Withdraw")),(0,l.kt)("td",{parentName:"tr",align:null},"8")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Dictionary")),(0,l.kt)("td",{parentName:"tr",align:null},"9")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"SystemContractRegistry")),(0,l.kt)("td",{parentName:"tr",align:null},"10")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Unbond")),(0,l.kt)("td",{parentName:"tr",align:null},"11")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ChainspecRegistry")),(0,l.kt)("td",{parentName:"tr",align:null},"12")))),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Account")," serializes as a 32 byte long buffer containing the byte representation of the underlying ",(0,l.kt)("inlineCode",{parentName:"li"},"AccountHash")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Hash")," serializes as a 32 byte long buffer containing the byte representation of the underlying ",(0,l.kt)("inlineCode",{parentName:"li"},"Hash")," itself."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"URef")," is a tuple that contains the address of the URef and the access rights to that ",(0,l.kt)("inlineCode",{parentName:"li"},"URef"),". The serialized representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"URef")," is 33 bytes long. The first 32 bytes are the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"URef")," address, and the last byte contains the bits corresponding to the access rights of the ",(0,l.kt)("inlineCode",{parentName:"li"},"URef"),". Refer to the ",(0,l.kt)("a",{parentName:"li",href:"#serialization-standard-values"},"CLValue")," section of this chapter for details on how ",(0,l.kt)("inlineCode",{parentName:"li"},"AccessRights")," are serialized."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Transfer")," serializes as a 32 byte long buffer containing the byte representation of the hash of the transfer."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"DeployInfo")," serializes as 32 byte long buffer containing the byte representation of the Deploy hash. See the Deploy section above for how Deploy hashes are serialized."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"EraInfo")," serializes a ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," primitive type containing the little-endian byte representation of ",(0,l.kt)("inlineCode",{parentName:"li"},"u64"),"."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Balance")," serializes as 32 byte long buffer containing the byte representation of the URef address."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Bid")," and ",(0,l.kt)("inlineCode",{parentName:"li"},"Withdraw")," both contain the ",(0,l.kt)("inlineCode",{parentName:"li"},"AccountHash")," as their identifier; therefore, they serialize in the same manner as the ",(0,l.kt)("inlineCode",{parentName:"li"},"Account")," variant."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Dictionary")," as the 32 byte long buffer containing the byte representation of the seed URef hashed with the identifying name of the dictionary item."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"SystemContractRegistry")," as a 32 byte long buffer of zeros."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Unbond")," contains the ",(0,l.kt)("inlineCode",{parentName:"li"},"AccountHash")," as its identifier; therefore, it serialize in the same manner as the ",(0,l.kt)("inlineCode",{parentName:"li"},"Account")," variant."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"ChainspecRegistry")," as a 32 byte long buffer of ones.")),(0,l.kt)("h2",{id:"serialization-standard-permissions"},"Permissions"),(0,l.kt)("p",null,"There are three types of actions that can be done on a value: read, write, add. The reason for ",(0,l.kt)("em",{parentName:"p"},"add")," to be called out separately from ",(0,l.kt)("em",{parentName:"p"},"write")," is to allow for commutativity checking. The available actions depend on the key type and the context. Some key types only allow controlled access by smart contracts via the contract API, and other key types refer to values produced and used by the system itself and are not accessible to smart contracts at all but can be read via off-chain queries. This is summarized in the table below:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Key"),(0,l.kt)("th",{parentName:"tr",align:null},"Type Available Actions"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Account"),(0,l.kt)("td",{parentName:"tr",align:null},"Read + Add (via API)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Hash"),(0,l.kt)("td",{parentName:"tr",align:null},"Read")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"URef"),(0,l.kt)("td",{parentName:"tr",align:null},"Read + Write and/or Add")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Transfer"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Deploy"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"EraInfo"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Balance"),(0,l.kt)("td",{parentName:"tr",align:null},"Read (via API)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Bid"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Withdraw"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Dictionary"),(0,l.kt)("td",{parentName:"tr",align:null},"Read (via API)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"SystemContractRegistry"),(0,l.kt)("td",{parentName:"tr",align:null},"Read (via API)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Unbond"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"ChainspecRegistry"),(0,l.kt)("td",{parentName:"tr",align:null},"Read (via API)")))),(0,l.kt)("hr",null),(0,l.kt)("p",null,"Refer to ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#uref-permissions"},"URef permissions")," on how permissions are handled in the case of ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),"s."),(0,l.kt)("h2",{id:"namedarg"},"NamedArg"),(0,l.kt)("p",null,"Named arguments to a contract. It is serialized by the combination of a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String"))," followed by the associated ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-clvalue"},(0,l.kt)("inlineCode",{parentName:"a"},"CLValue")),"."),(0,l.kt)("h2",{id:"namedkey"},"NamedKey"),(0,l.kt)("p",null,"A mapping of string identifiers to a Casper ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," type. It is serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of named keys and values held within. The remainder consists of a repeating pattern of serialized named keys and then values of the length dictated by the first four bytes."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," The name of the entry. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"string")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The value of the entry, which is a Casper ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," type."))),(0,l.kt)("p",null,"The named keys portion of the account structure serializes as a mapping of a string to Casper ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," values as described ",(0,l.kt)("a",{parentName:"p",href:"#serialization-standard-serialization-key"},"here"),"."),(0,l.kt)("h2",{id:"operation"},"Operation"),(0,l.kt)("p",null,"An operation performed while executing a deploy. It contains:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The formatted string of the key, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"kind")," OpKind, The type of operation performed. It serializes as a single byte based on the following table:"))),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"OpKind"),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Read"),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write"),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add"),(0,l.kt)("td",{parentName:"tr",align:null},"2")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"NoOp"),(0,l.kt)("td",{parentName:"tr",align:null},"3")))),(0,l.kt)("h2",{id:"parameter"},"Parameter"),(0,l.kt)("p",null,"Parameter to a method, structured as a name followed by a ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType"),". It is serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String"))," followed by a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-cltype"},(0,l.kt)("inlineCode",{parentName:"a"},"CLType")),"."),(0,l.kt)("h2",{id:"protocolversion"},"ProtocolVersion"),(0,l.kt)("p",null,"A newtype indicating the Casper Platform protocol version. It is serialized as three ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32"))," values indicating major, minor and patch versions in that order."),(0,l.kt)("h2",{id:"publickey"},"PublicKey"),(0,l.kt)("p",null,"Hex-encoded cryptographic public key, including the algorithm tag prefix. Serialization can be found under ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),"."),(0,l.kt)("h2",{id:"runtimeargs"},"RuntimeArgs"),(0,l.kt)("p",null,"Represents a collection of arguments passed to a smart contract. They serialize as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List"))," comprised of ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-tuple"},(0,l.kt)("inlineCode",{parentName:"a"},"Tuples")),"."),(0,l.kt)("h2",{id:"seigniorageallocation"},"SeigniorageAllocation"),(0,l.kt)("p",null,"Information about seigniorage allocation."),(0,l.kt)("p",null,"If the seigniorage allocation in question is for a validator, it serializes as the validator's ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey"))," followed by the ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")," amount"),"."),(0,l.kt)("p",null,"If it is a delegator, it serializes as the delegator's ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),", followed by the validator's ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey"))," and finally the ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")," amount"),"."),(0,l.kt)("h2",{id:"signature"},"Signature"),(0,l.kt)("p",null,"The signature serializes the byte representation of the underlying cryptographic primitive signature. The first byte within the signature is 1 in the case of an ",(0,l.kt)("inlineCode",{parentName:"p"},"Ed25519")," signature or 2 in the case of ",(0,l.kt)("inlineCode",{parentName:"p"},"Secp256k1"),"."),(0,l.kt)("h2",{id:"systemcontractregistry"},"SystemContractRegistry"),(0,l.kt)("p",null,"SystemContractRegistry is a unique ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," under which a mapping of the names and ",(0,l.kt)("inlineCode",{parentName:"p"},"ContractHashes")," for system contracts. This includes ",(0,l.kt)("inlineCode",{parentName:"p"},"Mint"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Auction"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"HandlePayment")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"StandardPayment"),". It is serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of names as strings and ",(0,l.kt)("a",{parentName:"p",href:"#contracthash"},"ContractHashes")," held within. The remainder consists of a repeating pattern of serialized strings and then ContractHashes of the length dictated by the first four bytes."),(0,l.kt)("h2",{id:"timediff"},"TimeDiff"),(0,l.kt)("p",null,"A human-readable duration between two timestamps. It serializes as a single ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value."),(0,l.kt)("h2",{id:"timestamp"},"Timestamp"),(0,l.kt)("p",null,"A timestamp formatted as per RFC 3339 and serialized as a single ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value."),(0,l.kt)("h2",{id:"transferaddr"},"TransferAddr"),(0,l.kt)("p",null,"Hex-encoded transfer address, which serializes as a byte representation of itself."),(0,l.kt)("h2",{id:"transform"},"Transform"),(0,l.kt)("p",null,"The actual transformation performed while executing a deploy. It serializes as a single ",(0,l.kt)("inlineCode",{parentName:"p"},"u8")," value indicating the type of transform performed as per the following table. The remaining bytes represent the information and serialization as listed."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Transform Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Identity"),(0,l.kt)("td",{parentName:"tr",align:null},"0"),(0,l.kt)("td",{parentName:"tr",align:null},"A transform having no effect.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_CLValue"),(0,l.kt)("td",{parentName:"tr",align:null},"1"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-calvalue"},(0,l.kt)("inlineCode",{parentName:"a"},"CLValue"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Account"),(0,l.kt)("td",{parentName:"tr",align:null},"2"),(0,l.kt)("td",{parentName:"tr",align:null},"Write the given ",(0,l.kt)("a",{parentName:"td",href:"#account-hash"},(0,l.kt)("inlineCode",{parentName:"a"},"Account"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Contract_WASM"),(0,l.kt)("td",{parentName:"tr",align:null},"3"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes a smart ",(0,l.kt)("a",{parentName:"td",href:"#contractwasmhash"},"contract as Wasm")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Contract"),(0,l.kt)("td",{parentName:"tr",align:null},"4"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes a smart ",(0,l.kt)("a",{parentName:"td",href:"#contracthash"},"contract")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Contract_Package"),(0,l.kt)("td",{parentName:"tr",align:null},"5"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes a smart ",(0,l.kt)("a",{parentName:"td",href:"#contractpackagehash"},"contract package")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Deploy_Info"),(0,l.kt)("td",{parentName:"tr",align:null},"6"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#deployinfo"},(0,l.kt)("inlineCode",{parentName:"a"},"DeployInfo"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Transfer"),(0,l.kt)("td",{parentName:"tr",align:null},"7"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#transferaddr"},"Transfer")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Era_Info"),(0,l.kt)("td",{parentName:"tr",align:null},"8"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#erainfo"},(0,l.kt)("inlineCode",{parentName:"a"},"EraInfo"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Bid"),(0,l.kt)("td",{parentName:"tr",align:null},"9"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#bid"},(0,l.kt)("inlineCode",{parentName:"a"},"Bid"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Withdraw"),(0,l.kt)("td",{parentName:"tr",align:null},"10"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#unbondingpurse"},"Withdraw")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_INT32"),(0,l.kt)("td",{parentName:"tr",align:null},"11"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"i32")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_UINT64"),(0,l.kt)("td",{parentName:"tr",align:null},"12"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_UINT128"),(0,l.kt)("td",{parentName:"tr",align:null},"13"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U128")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_UINT256"),(0,l.kt)("td",{parentName:"tr",align:null},"14"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U256")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_UINT512"),(0,l.kt)("td",{parentName:"tr",align:null},"15"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_Keys"),(0,l.kt)("td",{parentName:"tr",align:null},"16"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given collection of ",(0,l.kt)("a",{parentName:"td",href:"#namedkey"},"named keys"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Failure"),(0,l.kt)("td",{parentName:"tr",align:null},"17"),(0,l.kt)("td",{parentName:"tr",align:null},"A failed transformation, containing an error message.")))),(0,l.kt)("h2",{id:"transformentry"},"TransformEntry"),(0,l.kt)("p",null,"A transformation performed while executing a deploy."),(0,l.kt)("h2",{id:"unbondingpurse"},"UnbondingPurse"),(0,l.kt)("p",null,"A purse used for unbonding. The structure consists of the following:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"bonding_purse")," The bonding purse, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"validator_public_key")," The public key of the validator, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"unbonder_public_key")," The public key of the unbonder, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"era_of_creation")," Era in which this unbonding request was created, as an ",(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"EraId"))," newtype, which serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"amount")," The unbonding amount, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512"))," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"new_validator")," The validator public key to redelegate to, serialized as an ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-option"},(0,l.kt)("inlineCode",{parentName:"a"},"Option"))," containing the public key."))),(0,l.kt)("h2",{id:"serialization-standard-values"},"Values"),(0,l.kt)("p",null,"A value stored in the global state is a ",(0,l.kt)("inlineCode",{parentName:"p"},"StoredValue"),". A ",(0,l.kt)("inlineCode",{parentName:"p"},"StoredValue")," is one of three possible variants:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"A ",(0,l.kt)("inlineCode",{parentName:"li"},"CLValue")),(0,l.kt)("li",{parentName:"ul"},"A contract"),(0,l.kt)("li",{parentName:"ul"},"An account")),(0,l.kt)("p",null,"We discuss ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," and contract in more detail below. Details about accounts can be found in ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"accounts-head"),"."),(0,l.kt)("p",null,"Each ",(0,l.kt)("inlineCode",{parentName:"p"},"StoredValue")," is serialized when written to the global state. The serialization format consists of a single byte tag, indicating which variant of ",(0,l.kt)("inlineCode",{parentName:"p"},"StoredValue")," it is, followed by the serialization of that variant. The tag for each variant is as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"CLValue")," is ",(0,l.kt)("inlineCode",{parentName:"li"},"0")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Account")," is ",(0,l.kt)("inlineCode",{parentName:"li"},"1")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Contract")," is ",(0,l.kt)("inlineCode",{parentName:"li"},"2"))),(0,l.kt)("p",null,"The details of ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," serialization are in the following section. Using the serialization format for ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," as a basis, we can succinctly write the serialization rules for contracts and accounts:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"contracts serialize in the same way as data with ",(0,l.kt)("inlineCode",{parentName:"li"},"CLType")," equal to ",(0,l.kt)("inlineCode",{parentName:"li"},"Tuple3(List(U8), Map(String, Key), Tuple3(U32, U32, U32))"),";"),(0,l.kt)("li",{parentName:"ul"},"accounts serialize in the same way as data with ",(0,l.kt)("inlineCode",{parentName:"li"},"CLType")," equal to ",(0,l.kt)("inlineCode",{parentName:"li"},"Tuple5(ByteArray(U8, 32), Map(String, Key), URef, Map(ByteArray(U8, 32), U8), Tuple2(U8, U8))"),".")),(0,l.kt)("p",null,"Note: ",(0,l.kt)("inlineCode",{parentName:"p"},"Tuple5")," is not a presently supported ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType"),". However, it is clear how to generalize the rules for ",(0,l.kt)("inlineCode",{parentName:"p"},"Tuple1"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Tuple2"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Tuple3")," to any size tuple."),(0,l.kt)("h3",{id:"clvalue"},(0,l.kt)("inlineCode",{parentName:"h3"},"CLValue")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," is used to describe data that is used by smart contracts. This could be as a local state variable, input argument, or return value. A ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," consists of two parts: a ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," describing the type of the value and an array of bytes representing the data in our serialization format."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," is described by the following recursive data type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-rust"},'enum CLType {\n Bool, // boolean primitive\n I32, // signed 32-bit integer primitive\n I64, // signed 64-bit integer primitive\n U8, // unsigned 8-bit integer primitive\n U32, // unsigned 32-bit integer primitive\n U64, // unsigned 64-bit integer primitive\n U128, // unsigned 128-bit integer primitive\n U256, // unsigned 256-bit integer primitive\n U512, // unsigned 512-bit integer primitive\n Unit, // singleton value without additional semantics\n String, // e.g. "Hello, World!"\n URef, // unforgeable reference (see above)\n Key, // global state key (see above)\n PublicKey // A Casper system PublicKey type\n Option(CLType), // optional value of the given type\n List(CLType), // list of values of the given type (e.g. Vec in rust)\n ByteArray(CLType, u32), // same as `List` above, but number of elements\n // is statically known (e.g. arrays in rust)\n Result(CLType, CLType), // co-product of the given types;\n // one variant meaning success, the other failure\n Map(CLType, CLType), // key-value association where keys and values have the given types\n Tuple1(CLType), // single value of the given type\n Tuple2(CLType, CLType), // pair consisting of elements of the given types\n Tuple3(CLType, CLType, CLType), // triple consisting of elements of the given types\n Any // Indicates the type is not known\n}\n')),(0,l.kt)("p",null,"All data which can be assigned a (non-",(0,l.kt)("inlineCode",{parentName:"p"},"Any"),") ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," can be serialized according to the following rules (this defines the Casper serialization format):"),(0,l.kt)("h4",{id:"clvalue-boolean"},"Boolean"),(0,l.kt)("p",null,"Boolean values serialize as a single byte; ",(0,l.kt)("inlineCode",{parentName:"p"},"true")," maps to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", while ",(0,l.kt)("inlineCode",{parentName:"p"},"false")," maps to ",(0,l.kt)("inlineCode",{parentName:"p"},"0"),"."),(0,l.kt)("h4",{id:"clvalue-numeric"},"Numeric"),(0,l.kt)("p",null,"Numeric values consisting of 64 bits or less serialize in the two's complement representation with little-endian byte order, and the appropriate number of bytes for the bit-width."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"7u8")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x07"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"7u32")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x07000000"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"1024u32")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x00040000"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"Wider numeric values (i.e. ",(0,l.kt)("inlineCode",{parentName:"p"},"U128"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"U256"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"U512"),") serialize as one byte given the length of the next number (in bytes), followed by the two's complement representation with little-endian byte order. The number of bytes should be chosen as small as possible to represent the given number. This is done to reduce the serialization size when small numbers are represented within a wide data type.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"U512::from(7)")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x0107"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"U512::from(1024)")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x020004"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},'U512::from("123456789101112131415")')," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x0957ff1ada959f4eb106")))),(0,l.kt)("h4",{id:"clvalue-unit"},"Unit"),(0,l.kt)("p",null,"Unit serializes to an empty byte array."),(0,l.kt)("h4",{id:"clvalue-string"},"String"),(0,l.kt)("p",null,"Strings serialize as a 32-bit integer representing the length in bytes (note: this might be different than the number of characters since special characters, such as emojis, take more than one byte), followed by the UTF-8 encoding of the characters in the string."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},'"Hello, World!"')," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x0d00000048656c6c6f2c20576f726c6421"))),(0,l.kt)("h4",{id:"clvalue-option"},"Option"),(0,l.kt)("p",null,"Optional values serialize with a single byte tag, followed by the serialization of the value itself. The tag is equal to ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," if the value is missing, and ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," if it is present."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"None")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x00")),(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"Some(10u32)")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x010a000000"))),(0,l.kt)("h4",{id:"clvalue-list"},"List"),(0,l.kt)("p",null,"A list of values serializes as a 32-bit integer representing the number of elements in the list (note this differs from strings where it gives the number of ",(0,l.kt)("em",{parentName:"p"},"bytes"),"), followed by the concatenation of each serialized element."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"List()")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x00000000")),(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"List(1u32, 2u32, 3u32)")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x03000000010000000200000003000000"))),(0,l.kt)("h4",{id:"clvalue-ByteArray"},"ByteArray"),(0,l.kt)("p",null,"A fixed-length list of values serializes as the concatenation of the serialized elements. Unlike a variable-length list, the length is not included in the serialization because it is statically known by the type of the value."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"[1u32, 2u32, 3u32]")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x010000000200000003000000"))),(0,l.kt)("h4",{id:"clvalue-result"},"Result"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"Result")," serializes as a single byte tag followed by the serialization of the contained value. The tag is equal to ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," for the success variant and ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," for the error variant."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},'- E.g. `Ok(314u64)` serializes as `0x013a01000000000000`\n- E.g. `Err("Uh oh")` serializes as `0x00050000005568206f68`\n')),(0,l.kt)("h4",{id:"clvalue-tuple"},"Tuple"),(0,l.kt)("p",null,"Tuples serialize as the concatenation of their serialized elements. Similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"ByteArray")," the number of elements is not included in the serialization because it is statically known in the type."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},'- E.g. `(1u32, "Hello, World!", true)` serializes as `0x010000000d00000048656c6c6f2c20576f726c642101`\n')),(0,l.kt)("h4",{id:"clvalue-map"},"Map"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"Map")," serializes as a list of key-value tuples. There must be a well-defined ordering on the keys, and in the serialization, the pairs are listed in ascending order. This is done to ensure determinism in the serialization, as ",(0,l.kt)("inlineCode",{parentName:"p"},"Map")," data structures can be unordered."),(0,l.kt)("h4",{id:"clvalue-uref"},"URef"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"URef")," values serialize as the concatenation of its address (which is a fixed-length list of ",(0,l.kt)("inlineCode",{parentName:"p"},"u8"),") and a single byte tag representing the access rights. Access rights are converted as follows:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Access Rights"),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"NONE")),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"READ")),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"WRITE")),(0,l.kt)("td",{parentName:"tr",align:null},"2")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"READ_WRITE")),(0,l.kt)("td",{parentName:"tr",align:null},"3")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ADD")),(0,l.kt)("td",{parentName:"tr",align:null},"4")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"READ_ADD")),(0,l.kt)("td",{parentName:"tr",align:null},"5")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ADD_WRITE")),(0,l.kt)("td",{parentName:"tr",align:null},"6")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"READ_ADD_WRITE")),(0,l.kt)("td",{parentName:"tr",align:null},"7")))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"- E.g. `uref-974019c976b5f26412ce486158d2431967af35d91387dae8cbcd43c20fce6452-007` shows a `URef` with full `READ_ADD_WRITE` rights.\n")),(0,l.kt)("admonition",{type:"warning"},(0,l.kt)("p",{parentName:"admonition"},"When passing a URef to another entity on chain, you must ensure that the ",(0,l.kt)("inlineCode",{parentName:"p"},"AccessRights")," are set correctly. If the URef represents a ",(0,l.kt)("a",{parentName:"p",href:"/concepts/glossary/P#purse-purse"},"purse"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"AccessRights")," impact who can deposit and withdraw CSPR.")),(0,l.kt)("p",null,"If a passed URef contains ",(0,l.kt)("inlineCode",{parentName:"p"},"ADD")," permissions, the entity receiving the URef will then be able to deposit CSPR into the associated purse. ",(0,l.kt)("inlineCode",{parentName:"p"},"WRITE")," permissions allow for withdrawing CSPR. As of 1.4.5, passing a main purse URef as a runtime argument will cause the host to automatically remove ",(0,l.kt)("inlineCode",{parentName:"p"},"WRITE")," permissions. In this event, ",(0,l.kt)("inlineCode",{parentName:"p"},"READ")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"ADD")," permissions will remain. Regardless, all due diligence should be performed to avoid passing a URef with ",(0,l.kt)("inlineCode",{parentName:"p"},"WRITE")," permissions unintentionally."),(0,l.kt)("h4",{id:"clvalue-publickey"},"PublicKey"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey")," serializes as a single byte tag representing the algorithm followed by 32 bytes of the ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey")," itself:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is a ",(0,l.kt)("inlineCode",{parentName:"li"},"System")," key, the single tag byte is ",(0,l.kt)("inlineCode",{parentName:"li"},"0"),". With this variant, the single byte of ",(0,l.kt)("inlineCode",{parentName:"li"},"0")," is the entire key."),(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key, the single tag byte is ",(0,l.kt)("inlineCode",{parentName:"li"},"1")," followed by the individual bytes of the serialized key."),(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is a ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1")," key, the single tag byte is a ",(0,l.kt)("inlineCode",{parentName:"li"},"2")," followed by the individual bytes of the serialized key.")),(0,l.kt)("h4",{id:"clvalue-key"},"Key"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"Key")," values serialize as a single byte tag representing the variant, followed by the serialization of the data that variant contains. For most variants, this is simply a fixed-length 32-byte array. The exception is ",(0,l.kt)("inlineCode",{parentName:"p"},"Key::URef"),", which contains a ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),"; so its data serializes per the description above. The tags are as follows: ",(0,l.kt)("inlineCode",{parentName:"p"},"Key::Account")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Key::Hash")," as ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Key::URef")," as ",(0,l.kt)("inlineCode",{parentName:"p"},"2"),"."),(0,l.kt)("h4",{id:"clvalue-cltype"},"CLType"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," itself also has rules for serialization. A ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," serializes as a single-byte tag, followed by the concatenation of serialized inner types, if any (e.g., lists and tuples have inner types). ",(0,l.kt)("inlineCode",{parentName:"p"},"ByteArray")," is a minor exception because it also includes the length in the type. However, the length is included in the serialization (as a 32-bit integer, per the serialization rules above), following the serialization of the inner type. The tags are as follows:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"th"},"CLType")),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization Tag"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Bool")),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"I32")),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"I64")),(0,l.kt)("td",{parentName:"tr",align:null},"2")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U8")),(0,l.kt)("td",{parentName:"tr",align:null},"3")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U32")),(0,l.kt)("td",{parentName:"tr",align:null},"4")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U64")),(0,l.kt)("td",{parentName:"tr",align:null},"5")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U128")),(0,l.kt)("td",{parentName:"tr",align:null},"6")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U256")),(0,l.kt)("td",{parentName:"tr",align:null},"7")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U512")),(0,l.kt)("td",{parentName:"tr",align:null},"8")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Unit")),(0,l.kt)("td",{parentName:"tr",align:null},"9")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"String")),(0,l.kt)("td",{parentName:"tr",align:null},"10")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Key")),(0,l.kt)("td",{parentName:"tr",align:null},"11")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"URef")),(0,l.kt)("td",{parentName:"tr",align:null},"12")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Option")),(0,l.kt)("td",{parentName:"tr",align:null},"13")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"List")),(0,l.kt)("td",{parentName:"tr",align:null},"14")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ByteArray")),(0,l.kt)("td",{parentName:"tr",align:null},"15")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Result")),(0,l.kt)("td",{parentName:"tr",align:null},"16")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Map")),(0,l.kt)("td",{parentName:"tr",align:null},"17")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Tuple1")),(0,l.kt)("td",{parentName:"tr",align:null},"18")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Tuple2")),(0,l.kt)("td",{parentName:"tr",align:null},"19")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Tuple3")),(0,l.kt)("td",{parentName:"tr",align:null},"20")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Any")),(0,l.kt)("td",{parentName:"tr",align:null},"21")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"PublicKey")),(0,l.kt)("td",{parentName:"tr",align:null},"22")))),(0,l.kt)("h4",{id:"clvalue-clvalue"},"CLValue"),(0,l.kt)("p",null,"A complete ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue"),", including both the data and the type, can also be serialized (to store it in the global state). This is done by concatenating: the serialization of the length (as a 32-bit integer) of the serialized data (in bytes), the serialized data itself, and the serialization of the type."),(0,l.kt)("h3",{id:"global-state-contracts"},"Contracts"),(0,l.kt)("p",null,"Contracts are a special value type because they contain the on-chain logic of the applications running on a Casper network. A ",(0,l.kt)("em",{parentName:"p"},"contract")," contains the following data:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"a ",(0,l.kt)("a",{parentName:"li",href:"https://webassembly.github.io/spec/core/syntax/modules.html"},"wasm module")),(0,l.kt)("li",{parentName:"ul"},"a collection of named keys"),(0,l.kt)("li",{parentName:"ul"},"a protocol version")),(0,l.kt)("p",null,"The wasm module must contain a function named ",(0,l.kt)("inlineCode",{parentName:"p"},"call"),", which takes no arguments and returns no values. This is the main entry point into the contract. Moreover, the module may import any of the functions supported by the ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#execution-semantics-runtime"},"Casper runtime"),"."),(0,l.kt)("p",null,"Note: though the ",(0,l.kt)("inlineCode",{parentName:"p"},"call")," function signature has no arguments and no return value, within the ",(0,l.kt)("inlineCode",{parentName:"p"},"call")," function body, the ",(0,l.kt)("inlineCode",{parentName:"p"},"get_named_arg")," runtime function can be used to accept arguments (by ordinal), and the ",(0,l.kt)("inlineCode",{parentName:"p"},"ret")," runtime function can be used to return a single ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," to the caller."),(0,l.kt)("p",null,"The named keys are used to give human-readable names to keys in the global state, which are essential to the contract. For example, the hash key of another contract it frequently calls may be stored under a meaningful name. It is also used to store the ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),"s, which are known to the contract (see the section on Permissions for details)."),(0,l.kt)("p",null,"Each contract specifies the Casper protocol version that was active when the contract was written to the global state."),(0,l.kt)("h2",{id:"withdrawpurse"},"WithdrawPurse"),(0,l.kt)("p",null,"A purse used for unbonding, replaced in 1.5 by ",(0,l.kt)("a",{parentName:"p",href:"#unbondingpurse"},"UnbondingPurse"),". WithdrawPurses prior to 1.5 were known as UnbondingPurses and now consist of historical data."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"bonding_purse")," The bonding purse, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"validator_public_key")," The public key of the validator, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"unbonder_public_key")," The public key of the unbonder, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"era_of_creation")," Era in which this unbonding request was created, as an ",(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"EraId"))," newtype, which serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"amount")," The unbonding amount, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512"))," value."))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2bee511f.7e5892e8.js b/assets/js/2bee511f.7e5892e8.js new file mode 100644 index 0000000000..8aff1b3905 --- /dev/null +++ b/assets/js/2bee511f.7e5892e8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8933],{3905:function(e,t,a){a.d(t,{Zo:function(){return d},kt:function(){return h}});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),m=p(a),k=i,h=m["".concat(s,".").concat(k)]||m[k]||u[k]||l;return a?n.createElement(h,r(r({ref:t},d),{},{components:a})):n.createElement(h,r({ref:t},d))}));function h(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=a.length,r=new Array(l);r[0]=k;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[m]="string"==typeof e?e:i,r[1]=o;for(var p=2;pFailure",id:"failure",level:3},{value:"Success",id:"success",level:3},{value:"Group",id:"group",level:2},{value:"Groups",id:"groups",level:2},{value:"Keys",id:"serialization-standard-state-keys",level:2},{value:"Account identity key",id:"global-state-account-key",level:3},{value:"Hash key",id:"serialization-standard-hash-key",level:3},{value:"Unforgeable Reference (URef)",id:"serialization-standard-uref",level:3},{value:"Transfer Key",id:"serialization-standard-transfer-key",level:3},{value:"DeployInfo Key",id:"serialization-standard-deploy-info-key",level:3},{value:"EraInfo Key",id:"serialization-standard-era-info-key",level:3},{value:"Serialization for Key",id:"serialization-standard-serialization-key",level:3},{value:"Permissions",id:"serialization-standard-permissions",level:2},{value:"NamedArg",id:"namedarg",level:2},{value:"NamedKey",id:"namedkey",level:2},{value:"Operation",id:"operation",level:2},{value:"Parameter",id:"parameter",level:2},{value:"ProtocolVersion",id:"protocolversion",level:2},{value:"PublicKey",id:"publickey",level:2},{value:"RuntimeArgs",id:"runtimeargs",level:2},{value:"SeigniorageAllocation",id:"seigniorageallocation",level:2},{value:"Signature",id:"signature",level:2},{value:"SystemContractRegistry",id:"systemcontractregistry",level:2},{value:"TimeDiff",id:"timediff",level:2},{value:"Timestamp",id:"timestamp",level:2},{value:"TransferAddr",id:"transferaddr",level:2},{value:"Transform",id:"transform",level:2},{value:"TransformEntry",id:"transformentry",level:2},{value:"UnbondingPurse",id:"unbondingpurse",level:2},{value:"Values",id:"serialization-standard-values",level:2},{value:"CLValue",id:"clvalue",level:3},{value:"Boolean",id:"clvalue-boolean",level:4},{value:"Numeric",id:"clvalue-numeric",level:4},{value:"Unit",id:"clvalue-unit",level:4},{value:"String",id:"clvalue-string",level:4},{value:"Option",id:"clvalue-option",level:4},{value:"List",id:"clvalue-list",level:4},{value:"ByteArray",id:"clvalue-ByteArray",level:4},{value:"Result",id:"clvalue-result",level:4},{value:"Tuple",id:"clvalue-tuple",level:4},{value:"Map",id:"clvalue-map",level:4},{value:"URef",id:"clvalue-uref",level:4},{value:"PublicKey",id:"clvalue-publickey",level:4},{value:"Key",id:"clvalue-key",level:4},{value:"CLType",id:"clvalue-cltype",level:4},{value:"CLValue",id:"clvalue-clvalue",level:4},{value:"Contracts",id:"global-state-contracts",level:3},{value:"WithdrawPurse",id:"withdrawpurse",level:2}],u={toc:m},k="wrapper";function h(e){var t=e.components,a=(0,i.Z)(e,r);return(0,l.kt)(k,(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"serialization-standard-head"},"Serialization Standard"),(0,l.kt)("p",null,"We provide a custom implementation to serialize data structures used by the Casper node to their byte representation. This document details how this custom serialization is implemented, allowing developers to build a library that implements the custom serialization."),(0,l.kt)("p",null,"In your smart contracts, you can implement serialization using ",(0,l.kt)("inlineCode",{parentName:"p"},"cltype-any"),"."),(0,l.kt)("h2",{id:"serialization-standard-account"},"Account"),(0,l.kt)("p",null,"An Account is a structure that represents a user on a Casper network. The account structure consists of the following fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#account-hash"},(0,l.kt)("inlineCode",{parentName:"a"},"account_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#namedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"named_keys")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"main_purse")),(0,l.kt)("p",{parentName:"li"},"The account's main purse ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),". You may find information on ",(0,l.kt)("inlineCode",{parentName:"p"},"URef")," serialization ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},"here"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#associated-keys"},(0,l.kt)("inlineCode",{parentName:"a"},"associated_keys")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#action-thresholds"},(0,l.kt)("inlineCode",{parentName:"a"},"action_thresholds"))))),(0,l.kt)("h2",{id:"account-hash"},"Account Hash"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash of the public key, representing the address of a user's account. The account hash serializes as a 32-byte buffer containing the bytes of the account hash."),(0,l.kt)("h2",{id:"action-thresholds"},"Action Thresholds"),(0,l.kt)("p",null,"The minimum weight thresholds that have to be met when executing an action of a certain type. It serializes as two consecutive ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u8")," values")," as follows."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"deployment")," The minimum weight threshold required to perform deployment actions as a ",(0,l.kt)("inlineCode",{parentName:"p"},"u8")," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key_management")," The minimum weight threshold required to perform key management actions as a ",(0,l.kt)("inlineCode",{parentName:"p"},"u8")," value."))),(0,l.kt)("h2",{id:"activation-point"},"Activation Point"),(0,l.kt)("p",null,"The first era to which the associated protocol version applies. It serializes as a single ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u8"))," tag indicating if the era in question is genesis. If it is the genesis era, the following bytes will be a ",(0,l.kt)("inlineCode",{parentName:"p"},"timestamp"),". If not, the bytes represent an ",(0,l.kt)("inlineCode",{parentName:"p"},"era_id"),"."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"era_id")," An ",(0,l.kt)("a",{parentName:"p",href:"#eraid"},"Era ID newtype")," identifying the era when the protocol version will activate.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"timestamp")," A ",(0,l.kt)("a",{parentName:"p",href:"#timestamp"},"timestamp")," if the activation point is of the Genesis variant."))),(0,l.kt)("h2",{id:"approval"},"Approval"),(0,l.kt)("p",null,"A struct containing a signature and the public key of the signer."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"signature")," The approval signature, which serializes as the byte representation of the ",(0,l.kt)("a",{parentName:"p",href:"#signature"},(0,l.kt)("inlineCode",{parentName:"a"},"Signature")),". The first byte within the signature is 1 in the case of an ",(0,l.kt)("inlineCode",{parentName:"p"},"Ed25519")," signature or 2 in the case of ",(0,l.kt)("inlineCode",{parentName:"p"},"Secp256k1"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"signer")," The public key of the approvals signer. It serializes to the byte representation of the ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),". If the ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"p"},"Ed25519")," key, then the first byte within the serialized buffer is 1 followed by the bytes of the key itself; else, in the case of ",(0,l.kt)("inlineCode",{parentName:"p"},"Secp256k1"),", the first byte is 2."))),(0,l.kt)("h2",{id:"associatedkey"},"AssociatedKey"),(0,l.kt)("p",null,"A key granted limited permissions to an Account, for purposes such as multisig. It is serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of keys and weights held within. The remainder consists of a repeating pattern of serialized named keys and then weights of the length dictated by the first four bytes."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"account_hash")," The ",(0,l.kt)("a",{parentName:"p",href:"#account-hash"},"account hash")," of the associated key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"weight")," The weight of an associated key. The weight serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u8")," value"),"."))),(0,l.kt)("h2",{id:"availableblockrange"},"AvailableBlockRange"),(0,l.kt)("p",null,"An unbroken, inclusive range of blocks. It serializes as two consecutive ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64")," values")," containing the following two fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"low")," The inclusive lower bound of the range.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"high")," - The inclusive upper bound of the range."))),(0,l.kt)("h2",{id:"bid"},"Bid"),(0,l.kt)("p",null,"An entry in the validator map. The structure consists of the following fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"validator_public_key")," The validator's public key. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"bonding_purse")," The purse used for bonding. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"Uref")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"staked_amount")," The amount of tokens staked by a validator (not including delegators). It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegation_rate")," The delegation rate of the bid. It serializes as an ",(0,l.kt)("inlineCode",{parentName:"p"},"i32")," signed 32-bit integer primitive.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"vesting_schedule")," The vesting schedule for a genesis validator. ",(0,l.kt)("inlineCode",{parentName:"p"},"None")," if it is a non-genesis validator. It serializes as an ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-option"},(0,l.kt)("inlineCode",{parentName:"a"},"Option")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegators")," The validator's delegators, indexed by their public keys. They are serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey"),"s and delegators held within. The remainder consists of a repeating pattern of serialized ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey"),"s and then delegators of the length dictated by the first four bytes.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"inactive")," If the validator has been evicted. A ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-boolean"},"boolean")," value that serializes as a single byte; ",(0,l.kt)("inlineCode",{parentName:"p"},"true")," maps to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", while ",(0,l.kt)("inlineCode",{parentName:"p"},"false")," maps to ",(0,l.kt)("inlineCode",{parentName:"p"},"0"),"."))),(0,l.kt)("h2",{id:"serialization-standard-block"},"Block"),(0,l.kt)("p",null,"A block is the core component of the Casper linear blockchain, used in two contexts:"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"A data structure containing a collection of transactions. Blocks form the primary structure of the blockchain."),(0,l.kt)("li",{parentName:"ol"},"A message that is exchanged between nodes containing the data structure as explained in (1).")),(0,l.kt)("p",null,"Each block has a globally unique ID, achieved by hashing the contents of the block."),(0,l.kt)("p",null,"Each block points to its parent. An exception is the first block, which has no parent."),(0,l.kt)("p",null,"A block is structurally defined as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"hash"),": A hash over the header of the block."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"header"),": The header of the block that contains information about the contents of the block with additional metadata."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"body"),": The block's body contains the proposer of the block and hashes of deploys and transfers contained within it.")),(0,l.kt)("h3",{id:"block-hash"},"Block hash"),(0,l.kt)("p",null,"The block hash is a ",(0,l.kt)("inlineCode",{parentName:"p"},"Digest")," over the contents of the block Header. The ",(0,l.kt)("inlineCode",{parentName:"p"},"BlockHash")," serializes as the byte representation of the hash itself."),(0,l.kt)("h3",{id:"block-header"},"Block header"),(0,l.kt)("p",null,"The header portion of a block, structurally, is defined as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"parent_hash"),": is the hash of the parent block. It serializes to the byte representation of the parent hash. The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"li"},"parent_hash")," is 32 bytes long."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"state_root_hash"),": is the global state root hash produced by executing this block's body. It serializes to the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"state root hash"),". The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"li"},"state_root_hash")," is 32 bytes long."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"body_hash"),": the hash of the block body. It serializes to the byte representation of the body hash. The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"li"},"body_hash")," is 32 bytes long."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"random_bit"),": is a boolean needed for initializing a future era. It is serialized as a single byte; true maps to 1, while false maps to 0."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"accumulated_seed"),": A seed needed for initializing a future era. It serializes to the byte representation of the parent Hash. The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"li"},"accumulated_hash")," is 32 bytes long."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"era_end"),": contains equivocation and reward information to be included in the terminal finalized block. It is an optional field. Thus if the field is set as ",(0,l.kt)("inlineCode",{parentName:"li"},"None"),", it serializes to ",(0,l.kt)("em",{parentName:"li"},"0"),". The serialization of the other case is described in the EraEnd."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"timestamp"),": The timestamp from when the block was proposed. It serializes as a single ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value. The serialization of a ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value is described in the CLValues section."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"era_id"),": Era ID in which this block was created. It serializes as a single ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"height"),": The height of this block, i.e., the number of ancestors. It serializes as a single ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"protocol_version"),": The version of the Casper network when this block was proposed. It is 3-element tuple containing ",(0,l.kt)("inlineCode",{parentName:"li"},"u32")," values. It serializes as a buffer containing the three ",(0,l.kt)("inlineCode",{parentName:"li"},"u32")," serialized values. Refer to the CLValues section on how ",(0,l.kt)("inlineCode",{parentName:"li"},"u32")," values are serialized.")),(0,l.kt)("h3",{id:"serialization-standard-era-end"},"EraEnd"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"EraEnd")," as represented within the block header, is a struct containing two fields."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"era_report"),": The first field is termed as ",(0,l.kt)("inlineCode",{parentName:"li"},"EraReport")," and contains information about equivocators and rewards for an era."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"next_era_validator_weights"),": The second field is map for the validators and their weights for the era to follow.")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"EraReport")," itself contains two fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"equivocators"),": A vector of ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey"),"."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"rewards"),": A Binary Tree Map of ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," and ",(0,l.kt)("inlineCode",{parentName:"li"},"u64"),".")),(0,l.kt)("p",null,"When serializing an EraReport, the buffer is first filled with the individual serialization of the PublicKey contained within the vector."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key, the first byte within the buffer is a ",(0,l.kt)("inlineCode",{parentName:"li"},"1")," followed by the individual bytes of the serialized key."),(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1")," key, the first byte within the buffer is a ",(0,l.kt)("inlineCode",{parentName:"li"},"2")," followed by the individual bytes of the serialized key.")),(0,l.kt)("p",null,"When serializing the overarching struct of ",(0,l.kt)("inlineCode",{parentName:"p"},"EraEnd"),", we first allocate a buffer, which contains the serialized representation of the ",(0,l.kt)("inlineCode",{parentName:"p"},"EraReport")," as described above, followed by the serialized BTreeMap."),(0,l.kt)("p",null,"Note that ",(0,l.kt)("inlineCode",{parentName:"p"},"EraEnd")," is an optional field. Thus the above scheme only applies if there is an ",(0,l.kt)("inlineCode",{parentName:"p"},"EraEnd"),"; if there is no era end, the field simply serializes to ",(0,l.kt)("em",{parentName:"p"},"0"),"."),(0,l.kt)("h3",{id:"body"},"Body"),(0,l.kt)("p",null,"The body portion of the block is structurally defined as:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"proposer"),": The PublicKey which proposed this block."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"deploy_hashes"),": Is a vector of hex-encoded hashes identifying Deploys included in this block."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"transfer_hashes"),": Is a vector of hex-encoded hashes identifying Transfers included in this block.")),(0,l.kt)("p",null,"When we serialize the ",(0,l.kt)("inlineCode",{parentName:"p"},"BlockBody"),", we create a buffer that contains the serialized representations of the individual fields present within the block."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"proposer"),": serializes to the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey"),". If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key, then the first byte within the serialized buffer is 1 followed by the bytes of the key itself; else, in the case of ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1"),", the first byte is 2."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"deploy_hashes"),": serializes to the byte representation of all the deploy_hashes within the block header. Its length is ",(0,l.kt)("inlineCode",{parentName:"li"},"32 * n"),", where n denotes the number of deploy hashes present within the body."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"transfer_hashes"),": serializes to the byte representation of all the deploy_hashes within the block header. Its length is ",(0,l.kt)("inlineCode",{parentName:"li"},"32 * n"),", where n denotes the number of transfers present within the body.")),(0,l.kt)("h2",{id:"blockidentifier"},"BlockIdentifier"),(0,l.kt)("p",null,"Identifier for possible ways to retrieve a Block. It can consist of any of the following in most situations:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#block-hash"},(0,l.kt)("inlineCode",{parentName:"a"},"hash"))," Identify and retrieve a Block with its hash. The ",(0,l.kt)("inlineCode",{parentName:"p"},"BlockHash")," serializes as the byte representation of the hash itself.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"height")," Identify and retrieve the Block with its height. Height serializes as a single ",(0,l.kt)("inlineCode",{parentName:"p"},"u64")," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"state_root_hash")," Identify and retrieve the Block with its state root hash. It serializes to the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"p"},"state root hash"),". The serialized buffer of the ",(0,l.kt)("inlineCode",{parentName:"p"},"state_root_hash")," is 32 bytes long."))),(0,l.kt)("h2",{id:"chainspecregistry"},"ChainspecRegistry"),(0,l.kt)("p",null,"ChainspecRegistry is a unique key variant which contains a mapping of file names to the hash of the file itself. This map includes ",(0,l.kt)("em",{parentName:"p"},"Chainspec.toml")," and may include ",(0,l.kt)("em",{parentName:"p"},"Accounts.toml")," and ",(0,l.kt)("em",{parentName:"p"},"GlobalState.toml"),". It is serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of names as strings and ",(0,l.kt)("a",{parentName:"p",href:"#digest"},"digests")," held within. The remainder consists of a repeating pattern of serialized strings and then digests of the length dictated by the first four bytes. Digests and their inclusion criteria are as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"chainspec_raw_hash")," will always be included.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"genesis_accounts_raw_hash")," may be included in specific circumstances.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"global_state_raw_hash")," may be included in specific circumstances."))),(0,l.kt)("h2",{id:"contract"},"Contract"),(0,l.kt)("p",null,"A contract struct containing the following fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contractpackagehash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_package_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contractwasmhash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_wasm_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#namedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"named_keys")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#entrypoint"},(0,l.kt)("inlineCode",{parentName:"a"},"entry_points")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#protocolversion"},(0,l.kt)("inlineCode",{parentName:"a"},"protocol_version"))))),(0,l.kt)("h2",{id:"contracthash"},"ContractHash"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash of a contract. The contract hash serializes as a 32-byte buffer containing the bytes of the contract hash."),(0,l.kt)("h2",{id:"contractpackagehash"},"ContractPackageHash"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash of a contract package. The contract package hash serializes as a 32-byte buffer containing the bytes of the contract package hash."),(0,l.kt)("h2",{id:"contractversion"},"ContractVersion"),(0,l.kt)("p",null,"The version of the contract."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contracthash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_hash"))," The contract hash of the contract.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract_version")," The version of the contract within the protocol major version. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version_major")," The major element of the protocol version this contract is compatible with. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32")," value"),"."))),(0,l.kt)("h2",{id:"contractwasmhash"},"ContractWasmHash"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash of a contract's Wasm. The contract's Wasm hash serializes as a 32-byte buffer containing the bytes of the contract's Wasm hash."),(0,l.kt)("h2",{id:"delegator"},"Delegator"),(0,l.kt)("p",null,'Represents a party delegating their stake to a validator (or "delegatee"). The structure consists of the following fields:'),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegator_public_key")," The public key of the delegator, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"staked_amount")," The amount staked by the delegator, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"bonding_purse")," The bonding purse associated with the delegation. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"validator_public_key")," The public key of the validator that the delegator will be delegating to, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"vesting_schedule")," The vesting schedule for the provided delegator bid. ",(0,l.kt)("inlineCode",{parentName:"p"},"None")," if it is a non-genesis validator. It serializes as an ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-option"},(0,l.kt)("inlineCode",{parentName:"a"},"Option")),"."))),(0,l.kt)("h2",{id:"serialization-standard-deploy"},"Deploy"),(0,l.kt)("p",null,"A deploy is a data structure containing a smart contract and the requester's signature(s). Additionally, the deploy header contains additional metadata about the deploy itself. A deploy is structurally defined as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"hash"),": The hash of the deploy header."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"header"),": Contains metadata about the deploy. The structure of the header is detailed further in this document."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"payment"),": The payment code for contained smart contract."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"session"),": The stored contract itself."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"approvals"),": A list of signatures:")),(0,l.kt)("h3",{id:"deploy-hash"},"Deploy-Hash"),(0,l.kt)("p",null,"The deploy hash is a digest over the contents of the deploy header. The deploy hash serializes as the byte representation of the hash itself."),(0,l.kt)("h3",{id:"deploy-header"},"Deploy-Header"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"account"),": A supported public key variant (currently either ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," or ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1"),"). An ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key is serialized as a buffer of bytes, with the leading byte being ",(0,l.kt)("inlineCode",{parentName:"li"},"1")," for ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519"),", with remainder of the buffer containing the byte representation of the signature. Correspondingly, a ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1")," key is serialized as a buffer of bytes, with the leading byte being ",(0,l.kt)("inlineCode",{parentName:"li"},"2"),"."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"timestamp"),": A timestamp is a struct that is a unary tuple containing a ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value. This value is a count of the milliseconds since the UNIX epoch. Thus the value ",(0,l.kt)("inlineCode",{parentName:"li"},"1603994401469")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0xbd3a847575010000")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"ttl"),": The ",(0,l.kt)("strong",{parentName:"li"},"Time to live")," is defined as the amount of time for which deploy is considered valid. The ",(0,l.kt)("inlineCode",{parentName:"li"},"ttl")," serializes in the same manner as the timestamp."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"gas_price"),": The gas is ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," value which is serialized as ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," CLValue discussed below."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"body_hash"),": Body hash is a hash over the contents of the deploy body, which includes the payment, session, and approval fields. Its serialization is the byte representation of the hash itself."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"dependencies"),": Dependencies is a vector of deploy hashes referencing deploys that must execute before the current deploy can be executed. It serializes as a buffer containing the individual serialization of each DeployHash within the Vector."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"chain_name"),": Chain name is a human-readable string describing the name of the chain as detailed in the chainspec. It is serialized as a String CLValue described below.")),(0,l.kt)("h3",{id:"payment--session"},"Payment & Session"),(0,l.kt)("p",null,"Payment and Session are both defined as ",(0,l.kt)("inlineCode",{parentName:"p"},"ExecutableDeployItems"),". More information on ",(0,l.kt)("inlineCode",{parentName:"p"},"ExecutableDeployItems")," can be found ",(0,l.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/calling-contracts"},"here")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"Module Bytes are serialized such that the first byte within the serialized buffer is ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," with the rest of the buffer containing the bytes present."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'ModuleBytes { module_bytes: "[72 bytes]", args: 434705a38470ec2b008bb693426f47f330802f3bd63588ee275e943407649d3bab1898897ab0400d7fa09fe02ab7b7e8ea443d28069ca557e206916515a7e21d15e5be5eb46235f5 }')," will serialize to"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x0048000000420481b0d5a665c8a7678398103d4333c684461a71e9ee2a13f6e859fb6cd419ed5f8876fc6c3e12dce4385acc777edf42dcf8d8d844bf6a704e5b2446750559911a4a328d649ddd48000000434705a38470ec2b008bb693426f47f330802f3bd63588ee275e943407649d3bab1898897ab0400d7fa09fe02ab7b7e8ea443d28069ca557e206916515a7e21d15e5be5eb46235f5")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"StoredContractByHash serializes such that the first byte within the serialized buffer is 1u8. This is followed by the byte representation of the remaining fields."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'StoredContractByHash { hash: c4c411864f7b717c27839e56f6f1ebe5da3f35ec0043f437324325d65a22afa4, entry_point: "pclphXwfYmCmdITj8hnh", args: d8b59728274edd2334ea328b3292ed15eaf9134f9a00dce31a87d9050570fb0267a4002c85f3a8384d2502733b2e46f44981df85fed5e4854200bbca313e3bca8d888a84a76a1c5b1b3d236a12401a2999d3cad003c9b9d98c92ab1850 }')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x01c4c411864f7b717c27839e56f6f1ebe5da3f35ec0043f437324325d65a22afa41400000070636c7068587766596d436d6449546a38686e685d000000d8b59728274edd2334ea328b3292ed15eaf9134f9a00dce31a87d9050570fb0267a4002c85f3a8384d2502733b2e46f44981df85fed5e4854200bbca313e3bca8d888a84a76a1c5b1b3d236a12401a2999d3cad003c9b9d98c92ab1850")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"StoredContractByName serializes such that the first byte within the serialized buffer is 2u8. This is followed by the individual byte representation of the remaining fields."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'StoredContractByName { name: "U5A74bSZH8abT8HqVaK9", entry_point: "gIetSxltnRDvMhWdxTqQ", args: 07beadc3da884faa17454a }')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x0214000000553541373462535a483861625438487156614b39140000006749657453786c746e5244764d685764785471510b00000007beadc3da884faa17454a")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"StoredVersionedContractByHash serializes such that the first byte within the serialized buffer is 3u8. However, the field version within the enum serializes as an ",(0,l.kt)("a",{parentName:"p",href:"#option-clvalue-option"},"Option")," CLValue."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'StoredVersionedContractByHash { hash: b348fdd0d0b3f66468687df93141b5924f6bb957d5893c08b60d5a78d0b9a423, version: None, entry_point: "PsLz5c7JsqT8BK8ll0kF", args: 3d0d7f193f70740386cb78b383e2e30c4f976cf3fa834bafbda4ed9dbfeb52ce1777817e8ed8868cfac6462b7cd31028aa5a7a60066db35371a2f8 }')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x03b348fdd0d0b3f66468687df93141b5924f6bb957d5893c08b60d5a78d0b9a423001400000050734c7a3563374a73715438424b386c6c306b463b0000003d0d7f193f70740386cb78b383e2e30c4f976cf3fa834bafbda4ed9dbfeb52ce1777817e8ed8868cfac6462b7cd31028aa5a7a60066db35371a2f8")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"StoredVersionedContractByName serializes such that the first byte within the serialized buffer is 4u8. The name and entry_point are serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#string-clvalue-string"},"String")," CLValue, with the version field serializing as an ",(0,l.kt)("a",{parentName:"p",href:"#option-clvalue-option"},"Option"),"."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},'StoredVersionedContractByName { name: "lWJWKdZUEudSakJzw1tn", version: Some(1632552656), entry_point: "S1cXRT3E1jyFlWBAIVQ8", args: 9975e6957ea6b07176c7d8471478fb28df9f02a61689ef58234b1a3cffaebf9f303e3ef60ae0d8 }')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"0x04140000006c574a574b645a5545756453616b4a7a7731746e01d0c64e61140000005331635852543345316a79466c57424149565138270000009975e6957ea6b07176c7d8471478fb28df9f02a61689ef58234b1a3cffaebf9f303e3ef60ae0d8")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"Transfer serializes such that the first byte within the serialized buffer contains is 5u8, with the remaining bytes of the buffer containing the bytes contained within the args field of Transfer."))),(0,l.kt)("h3",{id:"approval"},"Approval"),(0,l.kt)("p",null,"Approval contains two fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"signer"),": The public key of the approvals signer. It serializes to the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey"),". If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key, then the first byte within the serialized buffer is 1 followed by the bytes of the key itself; else, in the case of ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1"),", the first byte is 2."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"signature"),": The approval signature, which serializes as the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"Signature"),". The first byte within the signature is 1 in the case of an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," signature or 2 in the case of ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1"),".")),(0,l.kt)("h2",{id:"deployinfo"},"DeployInfo"),(0,l.kt)("p",null,"Information relating to a given deploy. The structure consists of the following fields:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"deploy_hash")," The hash of the relevant deploy, serialized as a byte representation of the hash itself.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"transfers")," Transfers performed by the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"from")," The account identifier of the creator of the deploy, serialized as an ",(0,l.kt)("a",{parentName:"p",href:"#account-hash"},(0,l.kt)("inlineCode",{parentName:"a"},"account_hash")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"source")," The source purse used for payment of the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"gas")," The gas cost of executing the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")),"."))),(0,l.kt)("h2",{id:"digest"},"Digest"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b")," hash digest. The digest serializes as a byte representation of the hash itself."),(0,l.kt)("h2",{id:"disabledversions"},"DisabledVersions"),(0,l.kt)("p",null,"Disabled contract versions, containing the following:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract_version")," The version of the contract within the protocol major version. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32")," value"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version_major")," The major element of the protocol version this contract is compatible with. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32")," value"),"."))),(0,l.kt)("h2",{id:"entrypoint"},"EntryPoint"),(0,l.kt)("p",null,"A type of signature method. Order of arguments matters, since this can be referenced by index as well as name."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," The name of the entry point, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"args")," Arguments for this method. They serialize as a list of the ",(0,l.kt)("a",{parentName:"p",href:"#parameter"},(0,l.kt)("inlineCode",{parentName:"a"},"Parameter")),"s, where each parameter represents an argument passed to the entrypoint.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"ret")," The return type of the method, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-unit"},(0,l.kt)("inlineCode",{parentName:"a"},"Unit")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"access")," An enum describing the possible access control options for a contract entry point. It serializes as a 1 for public or a 1 followed by a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List"))," of authorized users.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point_type")," Identifies the type of entry point. It serializes as a ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," for Session and a ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," for Contract."))),(0,l.kt)("h2",{id:"eraid"},"EraID"),(0,l.kt)("p",null,"An Era ID newtype. It serializes as a single ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64")," value"),"."),(0,l.kt)("h2",{id:"erainfo"},"EraInfo"),(0,l.kt)("p",null,"Auction metadata, intended to be recorded each era. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List"))," of ",(0,l.kt)("a",{parentName:"p",href:"#seigniorageallocation"},"seigniorage allocations"),"."),(0,l.kt)("h2",{id:"executioneffect"},"ExecutionEffect"),(0,l.kt)("p",null,"The journal of execution transforms from a single deploy."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"operations")," The resulting operations, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List"))," of ",(0,l.kt)("a",{parentName:"p",href:"#operation"},"operations"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"transforms")," The actual ",(0,l.kt)("a",{parentName:"p",href:"#transform"},"transformation")," performed while executing a deploy."))),(0,l.kt)("h2",{id:"executionresult"},"ExecutionResult"),(0,l.kt)("p",null,"The result of a single deploy. It serializes as a ",(0,l.kt)("inlineCode",{parentName:"p"},"u8")," tag indicating either ",(0,l.kt)("inlineCode",{parentName:"p"},"Failure")," as a 0 or ",(0,l.kt)("inlineCode",{parentName:"p"},"Success")," as a 1. This is followed by the appropriate structure below:"),(0,l.kt)("h3",{id:"failure"},(0,l.kt)("inlineCode",{parentName:"h3"},"Failure")),(0,l.kt)("p",null,"The result of a failed execution."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"effect")," The ",(0,l.kt)("a",{parentName:"p",href:"#executioneffect"},"effect")," of executing the deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"transfers")," A record of transfers performed while executing the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"cost")," The cost of executing the deploy, serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512"))," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"error_message")," The error message associated with executing the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String")),"."))),(0,l.kt)("h3",{id:"success"},(0,l.kt)("inlineCode",{parentName:"h3"},"Success")),(0,l.kt)("p",null,"The result of a successful execution."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"effect")," The ",(0,l.kt)("a",{parentName:"p",href:"#executioneffect"},"effect")," of executing the deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"transfers")," A record of transfers performed while executing the deploy, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"cost")," The cost of executing the deploy, serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512"))," value."))),(0,l.kt)("h2",{id:"group"},"Group"),(0,l.kt)("p",null,'A (labeled) "user group". Each method of a versioned contract may be associated with one or more user groups which are allowed to call it. User groups are serialized as a ',(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},"String"),"."),(0,l.kt)("h2",{id:"groups"},"Groups"),(0,l.kt)("p",null,"They are serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of user groups and ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeSets")," of ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),"s held within. The remainder consists of a repeating pattern of serialized user groups and ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeSets")," of the length dictated by the first four bytes."),(0,l.kt)("h2",{id:"serialization-standard-state-keys"},"Keys"),(0,l.kt)("p",null,'In this chapter, we describe what constitutes a "key", the permissions model for the keys, and how they are serialized.'),(0,l.kt)("p",null,"A ",(0,l.kt)("em",{parentName:"p"},"key")," in ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#global-state-head"},"Global State")," is one of the following data types:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},'32-byte account identifier (called an "account identity key")'),(0,l.kt)("li",{parentName:"ul"},'32-byte immutable contract identifier (called a "hash key")'),(0,l.kt)("li",{parentName:"ul"},'32-byte reference identifier (called an "unforgeable reference")'),(0,l.kt)("li",{parentName:"ul"},"32-byte transfer identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte deploy information identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte purse balance identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte Auction bid identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte Auction withdrawal identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte Dictionary identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte System Contract Registry"),(0,l.kt)("li",{parentName:"ul"},"32-byte Auction unbond identifier"),(0,l.kt)("li",{parentName:"ul"},"32-byte Chainspec Registry")),(0,l.kt)("p",null,"The one exception to note here is the identifier for ",(0,l.kt)("a",{parentName:"p",href:"#erainfo"},(0,l.kt)("inlineCode",{parentName:"a"},"EraInfo")),", which actually serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value with an additional byte for the tag."),(0,l.kt)("h3",{id:"global-state-account-key"},"Account identity key"),(0,l.kt)("p",null,"This key type is used specifically for accounts in the global state. All accounts in the system must be stored under an account identity key, and no other types. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the public key used to create the associated account (see ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-associated-keys-weights"},"Accounts")," for more information)."),(0,l.kt)("h3",{id:"serialization-standard-hash-key"},"Hash key"),(0,l.kt)("p",null,"This key type is used for storing contracts immutably. Once a contract is written under a hash key, that contract can never change. The 32-byte identifier representing this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the deploy hash (see ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#block-structure-head"},"block-structure-head")," for more information) concatenated with a 4-byte sequential ID. The ID begins at zero for each deploy and increments by one each time a contract is stored. The purpose of this ID is to allow each contract stored in the same deploy to have a unique key."),(0,l.kt)("h3",{id:"serialization-standard-uref"},"Unforgeable Reference (",(0,l.kt)("inlineCode",{parentName:"h3"},"URef"),")"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"URef")," broadly speaking can be used to store values and manage permissions to interact with the value stored under the ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),". ",(0,l.kt)("inlineCode",{parentName:"p"},"URef")," is a tuple which contains the address under which the values are stored and the Access rights to the ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),". Refer to the ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#uref-head"},"Unforgeable Reference")," section for details on how ",(0,l.kt)("inlineCode",{parentName:"p"},"URefs")," are managed."),(0,l.kt)("h3",{id:"serialization-standard-transfer-key"},"Transfer Key"),(0,l.kt)("p",null,"This key type is used specifically for transfers in the global state. All transfers in the system must be stored under a transfer key and no other type. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the transfer address associated with the given transfer"),(0,l.kt)("h3",{id:"serialization-standard-deploy-info-key"},"DeployInfo Key"),(0,l.kt)("p",null,"This key type is used specifically for storing information related to deploys in the global state. Information for a given deploy is stored under this key only. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the deploy itself."),(0,l.kt)("h3",{id:"serialization-standard-era-info-key"},"EraInfo Key"),(0,l.kt)("p",null,"This key type is used specifically for storing information related to the ",(0,l.kt)("inlineCode",{parentName:"p"},"Auction")," metadata for a particular era. The underlying data type stored under this is a vector of the allocation of seigniorage for that given era. The identifier for this key is a new type that wraps around the primitive ",(0,l.kt)("inlineCode",{parentName:"p"},"u64")," data type and co-relates to the era number when the auction information was stored."),(0,l.kt)("p",null,"This key type is used specifically for storing information related to auction bids in the global state. Information for the bids is stored under this key only. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the public key used to create the associated account (see ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-associated-keys-weights"},"Accounts")," for more information)."),(0,l.kt)("p",null,"This key type is used specifically for storing information related to auction withdraws in the global state. Information for the withdrawals is stored under this key only. The 32-byte identifier which represents this key is derived from the ",(0,l.kt)("inlineCode",{parentName:"p"},"blake2b256")," hash of the public key used to create the associated account (see ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-associated-keys-weights"},"Accounts")," for more information)."),(0,l.kt)("h3",{id:"serialization-standard-serialization-key"},"Serialization for ",(0,l.kt)("inlineCode",{parentName:"h3"},"Key")),(0,l.kt)("p",null,"Given the different variants for the over-arching ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," data-type, each of the different variants is serialized differently. This section of this chapter details how the individual variants are serialized. The leading byte of the serialized buffer acts as a tag indicating the serialized variant."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"th"},"Key")),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization Tag"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Account")),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Hash")),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"URef")),(0,l.kt)("td",{parentName:"tr",align:null},"2")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Transfer")),(0,l.kt)("td",{parentName:"tr",align:null},"3")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"DeployInfo")),(0,l.kt)("td",{parentName:"tr",align:null},"4")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"EraInfo")),(0,l.kt)("td",{parentName:"tr",align:null},"5")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Balance")),(0,l.kt)("td",{parentName:"tr",align:null},"6")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Bid")),(0,l.kt)("td",{parentName:"tr",align:null},"7")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Withdraw")),(0,l.kt)("td",{parentName:"tr",align:null},"8")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Dictionary")),(0,l.kt)("td",{parentName:"tr",align:null},"9")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"SystemContractRegistry")),(0,l.kt)("td",{parentName:"tr",align:null},"10")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Unbond")),(0,l.kt)("td",{parentName:"tr",align:null},"11")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ChainspecRegistry")),(0,l.kt)("td",{parentName:"tr",align:null},"12")))),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Account")," serializes as a 32 byte long buffer containing the byte representation of the underlying ",(0,l.kt)("inlineCode",{parentName:"li"},"AccountHash")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Hash")," serializes as a 32 byte long buffer containing the byte representation of the underlying ",(0,l.kt)("inlineCode",{parentName:"li"},"Hash")," itself."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"URef")," is a tuple that contains the address of the URef and the access rights to that ",(0,l.kt)("inlineCode",{parentName:"li"},"URef"),". The serialized representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"URef")," is 33 bytes long. The first 32 bytes are the byte representation of the ",(0,l.kt)("inlineCode",{parentName:"li"},"URef")," address, and the last byte contains the bits corresponding to the access rights of the ",(0,l.kt)("inlineCode",{parentName:"li"},"URef"),". Refer to the ",(0,l.kt)("a",{parentName:"li",href:"#serialization-standard-values"},"CLValue")," section of this chapter for details on how ",(0,l.kt)("inlineCode",{parentName:"li"},"AccessRights")," are serialized."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Transfer")," serializes as a 32 byte long buffer containing the byte representation of the hash of the transfer."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"DeployInfo")," serializes as 32 byte long buffer containing the byte representation of the Deploy hash. See the Deploy section above for how Deploy hashes are serialized."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"EraInfo")," serializes a ",(0,l.kt)("inlineCode",{parentName:"li"},"u64")," primitive type containing the little-endian byte representation of ",(0,l.kt)("inlineCode",{parentName:"li"},"u64"),"."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Balance")," serializes as 32 byte long buffer containing the byte representation of the URef address."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Bid")," and ",(0,l.kt)("inlineCode",{parentName:"li"},"Withdraw")," both contain the ",(0,l.kt)("inlineCode",{parentName:"li"},"AccountHash")," as their identifier; therefore, they serialize in the same manner as the ",(0,l.kt)("inlineCode",{parentName:"li"},"Account")," variant."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Dictionary")," as the 32 byte long buffer containing the byte representation of the seed URef hashed with the identifying name of the dictionary item."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"SystemContractRegistry")," as a 32 byte long buffer of zeros."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Unbond")," contains the ",(0,l.kt)("inlineCode",{parentName:"li"},"AccountHash")," as its identifier; therefore, it serialize in the same manner as the ",(0,l.kt)("inlineCode",{parentName:"li"},"Account")," variant."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"ChainspecRegistry")," as a 32 byte long buffer of ones.")),(0,l.kt)("h2",{id:"serialization-standard-permissions"},"Permissions"),(0,l.kt)("p",null,"There are three types of actions that can be done on a value: read, write, add. The reason for ",(0,l.kt)("em",{parentName:"p"},"add")," to be called out separately from ",(0,l.kt)("em",{parentName:"p"},"write")," is to allow for commutativity checking. The available actions depend on the key type and the context. Some key types only allow controlled access by smart contracts via the contract API, and other key types refer to values produced and used by the system itself and are not accessible to smart contracts at all but can be read via off-chain queries. This is summarized in the table below:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Key"),(0,l.kt)("th",{parentName:"tr",align:null},"Type Available Actions"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Account"),(0,l.kt)("td",{parentName:"tr",align:null},"Read + Add (via API)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Hash"),(0,l.kt)("td",{parentName:"tr",align:null},"Read")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"URef"),(0,l.kt)("td",{parentName:"tr",align:null},"Read + Write and/or Add")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Transfer"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Deploy"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"EraInfo"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Balance"),(0,l.kt)("td",{parentName:"tr",align:null},"Read (via API)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Bid"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Withdraw"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Dictionary"),(0,l.kt)("td",{parentName:"tr",align:null},"Read (via API)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"SystemContractRegistry"),(0,l.kt)("td",{parentName:"tr",align:null},"Read (via API)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Unbond"),(0,l.kt)("td",{parentName:"tr",align:null},"System")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"ChainspecRegistry"),(0,l.kt)("td",{parentName:"tr",align:null},"Read (via API)")))),(0,l.kt)("hr",null),(0,l.kt)("p",null,"Refer to ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#uref-permissions"},"URef permissions")," on how permissions are handled in the case of ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),"s."),(0,l.kt)("h2",{id:"namedarg"},"NamedArg"),(0,l.kt)("p",null,"Named arguments to a contract. It is serialized by the combination of a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String"))," followed by the associated ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-clvalue"},(0,l.kt)("inlineCode",{parentName:"a"},"CLValue")),"."),(0,l.kt)("h2",{id:"namedkey"},"NamedKey"),(0,l.kt)("p",null,"A mapping of string identifiers to a Casper ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," type. It is serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of named keys and values held within. The remainder consists of a repeating pattern of serialized named keys and then values of the length dictated by the first four bytes."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," The name of the entry. It serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"string")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The value of the entry, which is a Casper ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," type."))),(0,l.kt)("p",null,"The named keys portion of the account structure serializes as a mapping of a string to Casper ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," values as described ",(0,l.kt)("a",{parentName:"p",href:"#serialization-standard-serialization-key"},"here"),"."),(0,l.kt)("h2",{id:"operation"},"Operation"),(0,l.kt)("p",null,"An operation performed while executing a deploy. It contains:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The formatted string of the key, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"kind")," OpKind, The type of operation performed. It serializes as a single byte based on the following table:"))),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"OpKind"),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Read"),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write"),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add"),(0,l.kt)("td",{parentName:"tr",align:null},"2")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"NoOp"),(0,l.kt)("td",{parentName:"tr",align:null},"3")))),(0,l.kt)("h2",{id:"parameter"},"Parameter"),(0,l.kt)("p",null,"Parameter to a method, structured as a name followed by a ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType"),". It is serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-string"},(0,l.kt)("inlineCode",{parentName:"a"},"String"))," followed by a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-cltype"},(0,l.kt)("inlineCode",{parentName:"a"},"CLType")),"."),(0,l.kt)("h2",{id:"protocolversion"},"ProtocolVersion"),(0,l.kt)("p",null,"A newtype indicating the Casper Platform protocol version. It is serialized as three ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u32"))," values indicating major, minor and patch versions in that order."),(0,l.kt)("h2",{id:"publickey"},"PublicKey"),(0,l.kt)("p",null,"Hex-encoded cryptographic public key, including the algorithm tag prefix. Serialization can be found under ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),"."),(0,l.kt)("h2",{id:"runtimeargs"},"RuntimeArgs"),(0,l.kt)("p",null,"Represents a collection of arguments passed to a smart contract. They serialize as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-list"},(0,l.kt)("inlineCode",{parentName:"a"},"List"))," comprised of ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-tuple"},(0,l.kt)("inlineCode",{parentName:"a"},"Tuples")),"."),(0,l.kt)("h2",{id:"seigniorageallocation"},"SeigniorageAllocation"),(0,l.kt)("p",null,"Information about seigniorage allocation."),(0,l.kt)("p",null,"If the seigniorage allocation in question is for a validator, it serializes as the validator's ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey"))," followed by the ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")," amount"),"."),(0,l.kt)("p",null,"If it is a delegator, it serializes as the delegator's ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),", followed by the validator's ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey"))," and finally the ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")," amount"),"."),(0,l.kt)("h2",{id:"signature"},"Signature"),(0,l.kt)("p",null,"The signature serializes the byte representation of the underlying cryptographic primitive signature. The first byte within the signature is 1 in the case of an ",(0,l.kt)("inlineCode",{parentName:"p"},"Ed25519")," signature or 2 in the case of ",(0,l.kt)("inlineCode",{parentName:"p"},"Secp256k1"),"."),(0,l.kt)("h2",{id:"systemcontractregistry"},"SystemContractRegistry"),(0,l.kt)("p",null,"SystemContractRegistry is a unique ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," under which a mapping of the names and ",(0,l.kt)("inlineCode",{parentName:"p"},"ContractHashes")," for system contracts. This includes ",(0,l.kt)("inlineCode",{parentName:"p"},"Mint"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Auction"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"HandlePayment")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"StandardPayment"),". It is serialized as a ",(0,l.kt)("inlineCode",{parentName:"p"},"BTreeMap")," where the first 4 bytes represent a ",(0,l.kt)("inlineCode",{parentName:"p"},"u32")," value describing the number of names as strings and ",(0,l.kt)("a",{parentName:"p",href:"#contracthash"},"ContractHashes")," held within. The remainder consists of a repeating pattern of serialized strings and then ContractHashes of the length dictated by the first four bytes."),(0,l.kt)("h2",{id:"timediff"},"TimeDiff"),(0,l.kt)("p",null,"A human-readable duration between two timestamps. It serializes as a single ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value."),(0,l.kt)("h2",{id:"timestamp"},"Timestamp"),(0,l.kt)("p",null,"A timestamp formatted as per RFC 3339 and serialized as a single ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value."),(0,l.kt)("h2",{id:"transferaddr"},"TransferAddr"),(0,l.kt)("p",null,"Hex-encoded transfer address, which serializes as a byte representation of itself."),(0,l.kt)("h2",{id:"transform"},"Transform"),(0,l.kt)("p",null,"The actual transformation performed while executing a deploy. It serializes as a single ",(0,l.kt)("inlineCode",{parentName:"p"},"u8")," value indicating the type of transform performed as per the following table. The remaining bytes represent the information and serialization as listed."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Transform Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Identity"),(0,l.kt)("td",{parentName:"tr",align:null},"0"),(0,l.kt)("td",{parentName:"tr",align:null},"A transform having no effect.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_CLValue"),(0,l.kt)("td",{parentName:"tr",align:null},"1"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-calvalue"},(0,l.kt)("inlineCode",{parentName:"a"},"CLValue"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Account"),(0,l.kt)("td",{parentName:"tr",align:null},"2"),(0,l.kt)("td",{parentName:"tr",align:null},"Write the given ",(0,l.kt)("a",{parentName:"td",href:"#account-hash"},(0,l.kt)("inlineCode",{parentName:"a"},"Account"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Contract_WASM"),(0,l.kt)("td",{parentName:"tr",align:null},"3"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes a smart ",(0,l.kt)("a",{parentName:"td",href:"#contractwasmhash"},"contract as Wasm")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Contract"),(0,l.kt)("td",{parentName:"tr",align:null},"4"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes a smart ",(0,l.kt)("a",{parentName:"td",href:"#contracthash"},"contract")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Contract_Package"),(0,l.kt)("td",{parentName:"tr",align:null},"5"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes a smart ",(0,l.kt)("a",{parentName:"td",href:"#contractpackagehash"},"contract package")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Deploy_Info"),(0,l.kt)("td",{parentName:"tr",align:null},"6"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#deployinfo"},(0,l.kt)("inlineCode",{parentName:"a"},"DeployInfo"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Transfer"),(0,l.kt)("td",{parentName:"tr",align:null},"7"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#transferaddr"},"Transfer")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Era_Info"),(0,l.kt)("td",{parentName:"tr",align:null},"8"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#erainfo"},(0,l.kt)("inlineCode",{parentName:"a"},"EraInfo"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Bid"),(0,l.kt)("td",{parentName:"tr",align:null},"9"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#bid"},(0,l.kt)("inlineCode",{parentName:"a"},"Bid"))," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Write_Withdraw"),(0,l.kt)("td",{parentName:"tr",align:null},"10"),(0,l.kt)("td",{parentName:"tr",align:null},"Writes the given ",(0,l.kt)("a",{parentName:"td",href:"#unbondingpurse"},"Withdraw")," to global state.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_INT32"),(0,l.kt)("td",{parentName:"tr",align:null},"11"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"i32")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_UINT64"),(0,l.kt)("td",{parentName:"tr",align:null},"12"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_UINT128"),(0,l.kt)("td",{parentName:"tr",align:null},"13"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U128")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_UINT256"),(0,l.kt)("td",{parentName:"tr",align:null},"14"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U256")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_UINT512"),(0,l.kt)("td",{parentName:"tr",align:null},"15"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given ",(0,l.kt)("a",{parentName:"td",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Add_Keys"),(0,l.kt)("td",{parentName:"tr",align:null},"16"),(0,l.kt)("td",{parentName:"tr",align:null},"Adds the given collection of ",(0,l.kt)("a",{parentName:"td",href:"#namedkey"},"named keys"),".")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Failure"),(0,l.kt)("td",{parentName:"tr",align:null},"17"),(0,l.kt)("td",{parentName:"tr",align:null},"A failed transformation, containing an error message.")))),(0,l.kt)("h2",{id:"transformentry"},"TransformEntry"),(0,l.kt)("p",null,"A transformation performed while executing a deploy."),(0,l.kt)("h2",{id:"unbondingpurse"},"UnbondingPurse"),(0,l.kt)("p",null,"A purse used for unbonding. The structure consists of the following:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"bonding_purse")," The bonding purse, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"validator_public_key")," The public key of the validator, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"unbonder_public_key")," The public key of the unbonder, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"era_of_creation")," Era in which this unbonding request was created, as an ",(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"EraId"))," newtype, which serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"amount")," The unbonding amount, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512"))," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"new_validator")," The validator public key to redelegate to, serialized as an ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-option"},(0,l.kt)("inlineCode",{parentName:"a"},"Option"))," containing the public key."))),(0,l.kt)("h2",{id:"serialization-standard-values"},"Values"),(0,l.kt)("p",null,"A value stored in the global state is a ",(0,l.kt)("inlineCode",{parentName:"p"},"StoredValue"),". A ",(0,l.kt)("inlineCode",{parentName:"p"},"StoredValue")," is one of three possible variants:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"A ",(0,l.kt)("inlineCode",{parentName:"li"},"CLValue")),(0,l.kt)("li",{parentName:"ul"},"A contract"),(0,l.kt)("li",{parentName:"ul"},"An account")),(0,l.kt)("p",null,"We discuss ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," and contract in more detail below. Details about accounts can be found in ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"accounts-head"),"."),(0,l.kt)("p",null,"Each ",(0,l.kt)("inlineCode",{parentName:"p"},"StoredValue")," is serialized when written to the global state. The serialization format consists of a single byte tag, indicating which variant of ",(0,l.kt)("inlineCode",{parentName:"p"},"StoredValue")," it is, followed by the serialization of that variant. The tag for each variant is as follows:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"CLValue")," is ",(0,l.kt)("inlineCode",{parentName:"li"},"0")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Account")," is ",(0,l.kt)("inlineCode",{parentName:"li"},"1")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Contract")," is ",(0,l.kt)("inlineCode",{parentName:"li"},"2"))),(0,l.kt)("p",null,"The details of ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," serialization are in the following section. Using the serialization format for ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," as a basis, we can succinctly write the serialization rules for contracts and accounts:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"contracts serialize in the same way as data with ",(0,l.kt)("inlineCode",{parentName:"li"},"CLType")," equal to ",(0,l.kt)("inlineCode",{parentName:"li"},"Tuple3(List(U8), Map(String, Key), Tuple3(U32, U32, U32))"),";"),(0,l.kt)("li",{parentName:"ul"},"accounts serialize in the same way as data with ",(0,l.kt)("inlineCode",{parentName:"li"},"CLType")," equal to ",(0,l.kt)("inlineCode",{parentName:"li"},"Tuple5(ByteArray(U8, 32), Map(String, Key), URef, Map(ByteArray(U8, 32), U8), Tuple2(U8, U8))"),".")),(0,l.kt)("p",null,"Note: ",(0,l.kt)("inlineCode",{parentName:"p"},"Tuple5")," is not a presently supported ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType"),". However, it is clear how to generalize the rules for ",(0,l.kt)("inlineCode",{parentName:"p"},"Tuple1"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Tuple2"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Tuple3")," to any size tuple."),(0,l.kt)("h3",{id:"clvalue"},(0,l.kt)("inlineCode",{parentName:"h3"},"CLValue")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," is used to describe data that is used by smart contracts. This could be as a local state variable, input argument, or return value. A ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," consists of two parts: a ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," describing the type of the value and an array of bytes representing the data in our serialization format."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," is described by the following recursive data type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-rust"},'enum CLType {\n Bool, // boolean primitive\n I32, // signed 32-bit integer primitive\n I64, // signed 64-bit integer primitive\n U8, // unsigned 8-bit integer primitive\n U32, // unsigned 32-bit integer primitive\n U64, // unsigned 64-bit integer primitive\n U128, // unsigned 128-bit integer primitive\n U256, // unsigned 256-bit integer primitive\n U512, // unsigned 512-bit integer primitive\n Unit, // singleton value without additional semantics\n String, // e.g. "Hello, World!"\n URef, // unforgeable reference (see above)\n Key, // global state key (see above)\n PublicKey // A Casper system PublicKey type\n Option(CLType), // optional value of the given type\n List(CLType), // list of values of the given type (e.g. Vec in rust)\n ByteArray(CLType, u32), // same as `List` above, but number of elements\n // is statically known (e.g. arrays in rust)\n Result(CLType, CLType), // co-product of the given types;\n // one variant meaning success, the other failure\n Map(CLType, CLType), // key-value association where keys and values have the given types\n Tuple1(CLType), // single value of the given type\n Tuple2(CLType, CLType), // pair consisting of elements of the given types\n Tuple3(CLType, CLType, CLType), // triple consisting of elements of the given types\n Any // Indicates the type is not known\n}\n')),(0,l.kt)("p",null,"All data which can be assigned a (non-",(0,l.kt)("inlineCode",{parentName:"p"},"Any"),") ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," can be serialized according to the following rules (this defines the Casper serialization format):"),(0,l.kt)("h4",{id:"clvalue-boolean"},"Boolean"),(0,l.kt)("p",null,"Boolean values serialize as a single byte; ",(0,l.kt)("inlineCode",{parentName:"p"},"true")," maps to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", while ",(0,l.kt)("inlineCode",{parentName:"p"},"false")," maps to ",(0,l.kt)("inlineCode",{parentName:"p"},"0"),"."),(0,l.kt)("h4",{id:"clvalue-numeric"},"Numeric"),(0,l.kt)("p",null,"Numeric values consisting of 64 bits or less serialize in the two's complement representation with little-endian byte order, and the appropriate number of bytes for the bit-width."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"7u8")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x07"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"7u32")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x07000000"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"1024u32")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x00040000"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"Wider numeric values (i.e. ",(0,l.kt)("inlineCode",{parentName:"p"},"U128"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"U256"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"U512"),") serialize as one byte given the length of the next number (in bytes), followed by the two's complement representation with little-endian byte order. The number of bytes should be chosen as small as possible to represent the given number. This is done to reduce the serialization size when small numbers are represented within a wide data type.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"U512::from(7)")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x0107"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"U512::from(1024)")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x020004"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"p"},'U512::from("123456789101112131415")')," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0x0957ff1ada959f4eb106")))),(0,l.kt)("h4",{id:"clvalue-unit"},"Unit"),(0,l.kt)("p",null,"Unit serializes to an empty byte array."),(0,l.kt)("h4",{id:"clvalue-string"},"String"),(0,l.kt)("p",null,"Strings serialize as a 32-bit integer representing the length in bytes (note: this might be different than the number of characters since special characters, such as emojis, take more than one byte), followed by the UTF-8 encoding of the characters in the string."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},'"Hello, World!"')," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x0d00000048656c6c6f2c20576f726c6421"))),(0,l.kt)("h4",{id:"clvalue-option"},"Option"),(0,l.kt)("p",null,"Optional values serialize with a single byte tag, followed by the serialization of the value itself. The tag is equal to ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," if the value is missing, and ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," if it is present."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"None")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x00")),(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"Some(10u32)")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x010a000000"))),(0,l.kt)("h4",{id:"clvalue-list"},"List"),(0,l.kt)("p",null,"A list of values serializes as a 32-bit integer representing the number of elements in the list (note this differs from strings where it gives the number of ",(0,l.kt)("em",{parentName:"p"},"bytes"),"), followed by the concatenation of each serialized element."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"List()")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x00000000")),(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"List(1u32, 2u32, 3u32)")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x03000000010000000200000003000000"))),(0,l.kt)("h4",{id:"clvalue-ByteArray"},"ByteArray"),(0,l.kt)("p",null,"A fixed-length list of values serializes as the concatenation of the serialized elements. Unlike a variable-length list, the length is not included in the serialization because it is statically known by the type of the value."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"E.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"[1u32, 2u32, 3u32]")," serializes as ",(0,l.kt)("inlineCode",{parentName:"li"},"0x010000000200000003000000"))),(0,l.kt)("h4",{id:"clvalue-result"},"Result"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"Result")," serializes as a single byte tag followed by the serialization of the contained value. The tag is equal to ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," for the success variant and ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," for the error variant."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},'- E.g. `Ok(314u64)` serializes as `0x013a01000000000000`\n- E.g. `Err("Uh oh")` serializes as `0x00050000005568206f68`\n')),(0,l.kt)("h4",{id:"clvalue-tuple"},"Tuple"),(0,l.kt)("p",null,"Tuples serialize as the concatenation of their serialized elements. Similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"ByteArray")," the number of elements is not included in the serialization because it is statically known in the type."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},'- E.g. `(1u32, "Hello, World!", true)` serializes as `0x010000000d00000048656c6c6f2c20576f726c642101`\n')),(0,l.kt)("h4",{id:"clvalue-map"},"Map"),(0,l.kt)("p",null,"A ",(0,l.kt)("inlineCode",{parentName:"p"},"Map")," serializes as a list of key-value tuples. There must be a well-defined ordering on the keys, and in the serialization, the pairs are listed in ascending order. This is done to ensure determinism in the serialization, as ",(0,l.kt)("inlineCode",{parentName:"p"},"Map")," data structures can be unordered."),(0,l.kt)("h4",{id:"clvalue-uref"},"URef"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"URef")," values serialize as the concatenation of its address (which is a fixed-length list of ",(0,l.kt)("inlineCode",{parentName:"p"},"u8"),") and a single byte tag representing the access rights. Access rights are converted as follows:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Access Rights"),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"NONE")),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"READ")),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"WRITE")),(0,l.kt)("td",{parentName:"tr",align:null},"2")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"READ_WRITE")),(0,l.kt)("td",{parentName:"tr",align:null},"3")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ADD")),(0,l.kt)("td",{parentName:"tr",align:null},"4")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"READ_ADD")),(0,l.kt)("td",{parentName:"tr",align:null},"5")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ADD_WRITE")),(0,l.kt)("td",{parentName:"tr",align:null},"6")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"READ_ADD_WRITE")),(0,l.kt)("td",{parentName:"tr",align:null},"7")))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"- E.g. `uref-974019c976b5f26412ce486158d2431967af35d91387dae8cbcd43c20fce6452-007` shows a `URef` with full `READ_ADD_WRITE` rights.\n")),(0,l.kt)("admonition",{type:"warning"},(0,l.kt)("p",{parentName:"admonition"},"When passing a URef to another entity on chain, you must ensure that the ",(0,l.kt)("inlineCode",{parentName:"p"},"AccessRights")," are set correctly. If the URef represents a ",(0,l.kt)("a",{parentName:"p",href:"/concepts/glossary/P#purse-purse"},"purse"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"AccessRights")," impact who can deposit and withdraw CSPR.")),(0,l.kt)("p",null,"If a passed URef contains ",(0,l.kt)("inlineCode",{parentName:"p"},"ADD")," permissions, the entity receiving the URef will then be able to deposit CSPR into the associated purse. ",(0,l.kt)("inlineCode",{parentName:"p"},"WRITE")," permissions allow for withdrawing CSPR. As of 1.4.5, passing a main purse URef as a runtime argument will cause the host to automatically remove ",(0,l.kt)("inlineCode",{parentName:"p"},"WRITE")," permissions. In this event, ",(0,l.kt)("inlineCode",{parentName:"p"},"READ")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"ADD")," permissions will remain. Regardless, all due diligence should be performed to avoid passing a URef with ",(0,l.kt)("inlineCode",{parentName:"p"},"WRITE")," permissions unintentionally."),(0,l.kt)("h4",{id:"clvalue-publickey"},"PublicKey"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey")," serializes as a single byte tag representing the algorithm followed by 32 bytes of the ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey")," itself:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is a ",(0,l.kt)("inlineCode",{parentName:"li"},"System")," key, the single tag byte is ",(0,l.kt)("inlineCode",{parentName:"li"},"0"),". With this variant, the single byte of ",(0,l.kt)("inlineCode",{parentName:"li"},"0")," is the entire key."),(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is an ",(0,l.kt)("inlineCode",{parentName:"li"},"Ed25519")," key, the single tag byte is ",(0,l.kt)("inlineCode",{parentName:"li"},"1")," followed by the individual bytes of the serialized key."),(0,l.kt)("li",{parentName:"ul"},"If the ",(0,l.kt)("inlineCode",{parentName:"li"},"PublicKey")," is a ",(0,l.kt)("inlineCode",{parentName:"li"},"Secp256k1")," key, the single tag byte is a ",(0,l.kt)("inlineCode",{parentName:"li"},"2")," followed by the individual bytes of the serialized key.")),(0,l.kt)("h4",{id:"clvalue-key"},"Key"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"Key")," values serialize as a single byte tag representing the variant, followed by the serialization of the data that variant contains. For most variants, this is simply a fixed-length 32-byte array. The exception is ",(0,l.kt)("inlineCode",{parentName:"p"},"Key::URef"),", which contains a ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),"; so its data serializes per the description above. The tags are as follows: ",(0,l.kt)("inlineCode",{parentName:"p"},"Key::Account")," serializes as ",(0,l.kt)("inlineCode",{parentName:"p"},"0"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Key::Hash")," as ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Key::URef")," as ",(0,l.kt)("inlineCode",{parentName:"p"},"2"),"."),(0,l.kt)("h4",{id:"clvalue-cltype"},"CLType"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," itself also has rules for serialization. A ",(0,l.kt)("inlineCode",{parentName:"p"},"CLType")," serializes as a single-byte tag, followed by the concatenation of serialized inner types, if any (e.g., lists and tuples have inner types). ",(0,l.kt)("inlineCode",{parentName:"p"},"ByteArray")," is a minor exception because it also includes the length in the type. However, the length is included in the serialization (as a 32-bit integer, per the serialization rules above), following the serialization of the inner type. The tags are as follows:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"th"},"CLType")),(0,l.kt)("th",{parentName:"tr",align:null},"Serialization Tag"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Bool")),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"I32")),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"I64")),(0,l.kt)("td",{parentName:"tr",align:null},"2")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U8")),(0,l.kt)("td",{parentName:"tr",align:null},"3")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U32")),(0,l.kt)("td",{parentName:"tr",align:null},"4")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U64")),(0,l.kt)("td",{parentName:"tr",align:null},"5")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U128")),(0,l.kt)("td",{parentName:"tr",align:null},"6")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U256")),(0,l.kt)("td",{parentName:"tr",align:null},"7")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"U512")),(0,l.kt)("td",{parentName:"tr",align:null},"8")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Unit")),(0,l.kt)("td",{parentName:"tr",align:null},"9")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"String")),(0,l.kt)("td",{parentName:"tr",align:null},"10")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Key")),(0,l.kt)("td",{parentName:"tr",align:null},"11")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"URef")),(0,l.kt)("td",{parentName:"tr",align:null},"12")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Option")),(0,l.kt)("td",{parentName:"tr",align:null},"13")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"List")),(0,l.kt)("td",{parentName:"tr",align:null},"14")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"ByteArray")),(0,l.kt)("td",{parentName:"tr",align:null},"15")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Result")),(0,l.kt)("td",{parentName:"tr",align:null},"16")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Map")),(0,l.kt)("td",{parentName:"tr",align:null},"17")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Tuple1")),(0,l.kt)("td",{parentName:"tr",align:null},"18")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Tuple2")),(0,l.kt)("td",{parentName:"tr",align:null},"19")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Tuple3")),(0,l.kt)("td",{parentName:"tr",align:null},"20")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"Any")),(0,l.kt)("td",{parentName:"tr",align:null},"21")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"PublicKey")),(0,l.kt)("td",{parentName:"tr",align:null},"22")))),(0,l.kt)("h4",{id:"clvalue-clvalue"},"CLValue"),(0,l.kt)("p",null,"A complete ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue"),", including both the data and the type, can also be serialized (to store it in the global state). This is done by concatenating: the serialization of the length (as a 32-bit integer) of the serialized data (in bytes), the serialized data itself, and the serialization of the type."),(0,l.kt)("h3",{id:"global-state-contracts"},"Contracts"),(0,l.kt)("p",null,"Contracts are a special value type because they contain the on-chain logic of the applications running on a Casper network. A ",(0,l.kt)("em",{parentName:"p"},"contract")," contains the following data:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"a ",(0,l.kt)("a",{parentName:"li",href:"https://webassembly.github.io/spec/core/syntax/modules.html"},"wasm module")),(0,l.kt)("li",{parentName:"ul"},"a collection of named keys"),(0,l.kt)("li",{parentName:"ul"},"a protocol version")),(0,l.kt)("p",null,"The wasm module must contain a function named ",(0,l.kt)("inlineCode",{parentName:"p"},"call"),", which takes no arguments and returns no values. This is the main entry point into the contract. Moreover, the module may import any of the functions supported by the ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#execution-semantics-runtime"},"Casper runtime"),"."),(0,l.kt)("p",null,"Note: though the ",(0,l.kt)("inlineCode",{parentName:"p"},"call")," function signature has no arguments and no return value, within the ",(0,l.kt)("inlineCode",{parentName:"p"},"call")," function body, the ",(0,l.kt)("inlineCode",{parentName:"p"},"get_named_arg")," runtime function can be used to accept arguments (by ordinal), and the ",(0,l.kt)("inlineCode",{parentName:"p"},"ret")," runtime function can be used to return a single ",(0,l.kt)("inlineCode",{parentName:"p"},"CLValue")," to the caller."),(0,l.kt)("p",null,"The named keys are used to give human-readable names to keys in the global state, which are essential to the contract. For example, the hash key of another contract it frequently calls may be stored under a meaningful name. It is also used to store the ",(0,l.kt)("inlineCode",{parentName:"p"},"URef"),"s, which are known to the contract (see the section on Permissions for details)."),(0,l.kt)("p",null,"Each contract specifies the Casper protocol version that was active when the contract was written to the global state."),(0,l.kt)("h2",{id:"withdrawpurse"},"WithdrawPurse"),(0,l.kt)("p",null,"A purse used for unbonding, replaced in 1.5 by ",(0,l.kt)("a",{parentName:"p",href:"#unbondingpurse"},"UnbondingPurse"),". WithdrawPurses prior to 1.5 were known as UnbondingPurses and now consist of historical data."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"bonding_purse")," The bonding purse, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"validator_public_key")," The public key of the validator, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"unbonder_public_key")," The public key of the unbonder, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"era_of_creation")," Era in which this unbonding request was created, as an ",(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"EraId"))," newtype, which serializes as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"u64"))," value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"amount")," The unbonding amount, serialized as a ",(0,l.kt)("a",{parentName:"p",href:"#clvalue-numeric"},(0,l.kt)("inlineCode",{parentName:"a"},"U512"))," value."))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2c99ca03.fac42c78.js b/assets/js/2c99ca03.bab7db00.js similarity index 60% rename from assets/js/2c99ca03.fac42c78.js rename to assets/js/2c99ca03.bab7db00.js index 20130f9f14..68fd4cdbc3 100644 --- a/assets/js/2c99ca03.fac42c78.js +++ b/assets/js/2c99ca03.bab7db00.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1258],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return f}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(f,i(i({ref:t},l),{},{components:n})):r.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:a,i[1]=c;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(f,i(i({ref:t},l),{},{components:n})):r.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:a,i[1]=c;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=l(n),g=a,h=u["".concat(s,".").concat(g)]||u[g]||d[g]||o;return n?r.createElement(h,i(i({ref:t},p),{},{components:n})):r.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=g;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:a,i[1]=c;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=l(n),g=a,h=u["".concat(s,".").concat(g)]||u[g]||d[g]||o;return n?r.createElement(h,i(i({ref:t},p),{},{components:n})):r.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=g;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:a,i[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(r),f=a,m=p["".concat(s,".").concat(f)]||p[f]||d[f]||o;return r?n.createElement(m,i(i({ref:t},c),{},{components:r})):n.createElement(m,i({ref:t},c))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:a,i[1]=l;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(r),f=a,m=p["".concat(s,".").concat(f)]||p[f]||d[f]||o;return r?n.createElement(m,i(i({ref:t},c),{},{components:r})):n.createElement(m,i({ref:t},c))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:a,i[1]=l;for(var u=2;u=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(n),h=r,f=p["".concat(l,".").concat(h)]||p[h]||d[h]||o;return n?a.createElement(f,i(i({ref:t},u),{},{components:n})):a.createElement(f,i({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:p(n);return function(e){var t=(0,c.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function h(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function f(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,o=(0,s.k6)(),i=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,l._X)(i),(0,r.useCallback)((function(e){if(i){var t=new URLSearchParams(o.location.search);t.set(i,e),o.replace(Object.assign({},o.location,{search:t.toString()}))}}),[i,o])]}function m(e){var t,n,a,o,i=e.defaultValue,s=e.queryString,l=void 0!==s&&s,c=e.groupId,p=d(e),m=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!h({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:i,tabValues:p})})),b=m[0],v=m[1],y=f({queryString:l,groupId:c}),g=y[0],k=y[1],w=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:c}.groupId),n=(0,u.Nk)(t),a=n[0],o=n[1],[a,(0,r.useCallback)((function(e){t&&o.set(e)}),[t,o])]),T=w[0],N=w[1],C=function(){var e=null!=g?g:T;return h({value:e,tabValues:p})?e:null}();return(0,r.useLayoutEffect)((function(){C&&v(C)}),[C]),{selectedValue:b,selectValue:(0,r.useCallback)((function(e){if(!h({value:e,tabValues:p}))throw new Error("Can't select invalid tab value="+e);v(e),k(e),N(e)}),[k,N,p]),tabValues:p}}var b=n(2389),v={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function y(e){var t=e.className,n=e.block,s=e.selectedValue,l=e.selectValue,c=e.tabValues,u=[],p=(0,i.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,n=u.indexOf(t),a=c[n].value;a!==s&&(p(t),l(a))},h=function(e){var t,n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var a,r=u.indexOf(e.currentTarget)+1;n=null!=(a=u[r])?a:u[0];break;case"ArrowLeft":var o,i=u.indexOf(e.currentTarget)-1;n=null!=(o=u[i])?o:u[u.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":n},t)},c.map((function(e){var t=e.value,n=e.label,i=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:s===t?0:-1,"aria-selected":s===t,key:t,ref:function(e){return u.push(e)},onKeyDown:h,onClick:d},i,{className:(0,o.Z)("tabs__item",v.tabItem,null==i?void 0:i.className,{"tabs__item--active":s===t})}),null!=n?n:t)})))}function g(e){var t=e.lazy,n=e.children,a=e.selectedValue,o=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var i=o.find((function(e){return e.props.value===a}));return i?(0,r.cloneElement)(i,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},o.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function k(e){var t=m(e);return r.createElement("div",{className:(0,o.Z)("tabs-container",v.tabList)},r.createElement(y,(0,a.Z)({},e,t)),r.createElement(g,(0,a.Z)({},e,t)))}function w(e){var t=(0,b.Z)();return r.createElement(k,(0,a.Z)({key:String(t)},e))}},8438:function(e,t,n){n.r(t),n.d(t,{assets:function(){return d},contentTitle:function(){return u},default:function(){return b},frontMatter:function(){return c},metadata:function(){return p},toc:function(){return h}});var a=n(7462),r=n(3366),o=(n(7294),n(3905)),i=n(4866),s=n(5162),l=["components"],c={},u="dApp Technology Stack",p={unversionedId:"developers/dapps/technology-stack",id:"developers/dapps/technology-stack",title:"dApp Technology Stack",description:"There are 3 layers to building a decentralized application that interacts with a Casper network: Front-end, backend, and on-chain logic. This document outlines lists the requirements for each.",source:"@site/source/docs/casper/developers/dapps/technology-stack.md",sourceDirName:"developers/dapps",slug:"/developers/dapps/technology-stack",permalink:"/developers/dapps/technology-stack",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/dapps/technology-stack.md",tags:[],version:"current",lastUpdatedAt:1707229568,formattedLastUpdatedAt:"Feb 6, 2024",frontMatter:{},sidebar:"developers",previous:{title:"Python SDK",permalink:"/developers/dapps/sdk/python-sdk"},next:{title:"Front-end in React",permalink:"/developers/dapps/template-frontend"}},d={},h=[{value:"Front-End",id:"front-end",level:2},{value:"Signing Transactions",id:"signing-transactions",level:3},{value:"Querying Global State",id:"querying-global-state",level:3},{value:"Backend",id:"backend",level:2},{value:"Blockchain",id:"blockchain",level:2}],f={toc:h},m="wrapper";function b(e){var t=e.components,n=(0,r.Z)(e,l);return(0,o.kt)(m,(0,a.Z)({},f,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"dapp-technology-stack"},"dApp Technology Stack"),(0,o.kt)("p",null,"There are 3 layers to building a decentralized application that interacts with a Casper network: Front-end, backend, and on-chain logic. This document outlines lists the requirements for each."),(0,o.kt)("h2",{id:"front-end"},"Front-End"),(0,o.kt)("p",null,"The front-end, or ",(0,o.kt)("em",{parentName:"p"},"client-side")," of a dApp consists of the interface that the user uses to interact with smart contracts on a Casper Network. This interface usually comes in the form of a website/webpage, mobile device application or computer program, but could also include APIs with endpoints that may be called or queried."),(0,o.kt)("p",null,"You will need to choose a Casper-compatible SDK for the language you are using to call and query smart contracts on a Casper network. Casper's SDKs have methods available for constructing Deploys and gathering global state data. While these interactions can be prepared on the front-end, they must be sent to the backend of your application before being sent off to a network, so as to fulfill ",(0,o.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"CORS")," requirements."),(0,o.kt)("h3",{id:"signing-transactions"},"Signing Transactions"),(0,o.kt)("p",null,"The signing of transactions will, in many cases, need to be performed by the user on the front-end, for which you have a couple options:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"The Casper Wallet"),(0,o.kt)("p",{parentName:"li"},"Use the ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/develop"},"Casper Wallet")," to sign deploys for a Casper network. Deploy objects are first converted to JSON, then sent to the Wallet to be signed, then must be sent to the backend and forwarded to a node."),(0,o.kt)("admonition",{parentName:"li",type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"The Casper Signer has been deprecated and replaced with the ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io"},"Casper Wallet"),". We are in the process of updating this page. Meanwhile, visit the guide on ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/develop"},"Building with the Casper Wallet"),"."))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Third-party signers"),(0,o.kt)("p",{parentName:"li"},"Third-party signers may be used as well. A JSON representation of the unsigned transaction should be forwarded to the third-party signer and accept a callback containing the signed deploy object."))),(0,o.kt)("h3",{id:"querying-global-state"},"Querying Global State"),(0,o.kt)("p",null,"To execute a query of global state, such as retrieving smart contract data or getting current chain information, the preparation may be done on the front-end, but the query to a node must ultimately originate from your application's backend. This preparatory stage comes only in the form of defining a contract hash and the path which you'd like to query data. Alternately, for chain information, you must define the endpoint you'd like to query."),(0,o.kt)("h2",{id:"backend"},"Backend"),(0,o.kt)("p",null,"The backend of a dApp consists of the server-side code that connects the blockchain to the front-end interface and deals with data-parsing and application-layer communication. A backend server is necessary for building dApps on Casper as Casper's nodes expect ",(0,o.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"CORS headers")," from a specified origin on the HTTP requests they receive. Backend servers are helpful for other reasons too, such as queueing requests and analyzing the traffic moving between your dApp and the blockchain."),(0,o.kt)("p",null,"As the backend server of a dApp is the software communicating with Casper nodes (the blockchain), it needs to receive information such as which node and endpoint to connect to."),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'const client = new CasperClient("http://NODE_ADDRESS:7777/rpc");\n'))),(0,o.kt)(s.Z,{value:"py",label:"Python",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'client = NodeClient(NodeConnection((host = "NODE_ADDRESS"), (port_rpc = 7777)));\n')))),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"You can find online peers for Mainnet at ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live"},"cspr.live")," or testnet at ",(0,o.kt)("a",{parentName:"p",href:"https://testnet.cspr.live"},"testnet.cspr.live"))),(0,o.kt)("p",null,"There are two main types of blockchain interactions that will originate from the front-end: deploys and queries. In the case of a dApp, both of these will pass through the back-end."),(0,o.kt)("p",null,"Blockchain interaction for state queries is handled solely on the backend. On the front-end, a user simply chooses the path at which they want to query data. This path is sent to the backend where the server will perform the state query and send the result back to the front-end."),(0,o.kt)("p",null,"In the case of a user-signed transaction originating from the dApp's front-end, the backend will need to accept this transaction and forward it to a Casper network. This is often accomplished by opening a POST endpoint that accepts JSON formatted transactions and forwards them along."),(0,o.kt)("h2",{id:"blockchain"},"Blockchain"),(0,o.kt)("p",null,"The last stop for a deploy or query is the blockchain itself. Like the majority of smart contract blockchains, Casper networks maintain a forever-growing, immutable ledger that can be read and written to. When building a dApp for a Casper network, user interactions in the form of queries and deploys originate from the front-end, are forwarded to the backend, and are then sent to a Casper node for interaction with the blockchain. You can communicate with Casper nodes using JSON RPC calls, and have a variety of open ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/json-rpc-transactional"},"transactional"),", ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/json-rpc-informational"},"informational"),", and ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/json-rpc-pos"},"Proof-of-Stake")," endpoints. By utilizing an SDK on the backend, you won't need to construct these JSON RPC calls yourself, they'll be done for you within the available methods."),(0,o.kt)("p",null,"More than likely, you will want your dApp to perform personalized functions, store custom data, and perhaps even store or transact upon tokens with monetary value. All of these behaviors can be implemented by writing custom smart contracts for your application. Smart contracts on a Casper network can perform any function that a classical computer can. Casper's smart contracts are executed as ",(0,o.kt)("a",{parentName:"p",href:"https://webassembly.org/"},"WebAssembly")," binaries, and can be written in any language that compiles to WebAssembly. Currently, most developers choose to write their smart contracts in ",(0,o.kt)("a",{parentName:"p",href:"https://www.rust-lang.org/"},"Rust")," for its reliability and ease-of-use. Additionally, Casper's smart contract documentation is written for Rust."),(0,o.kt)("p",null,"To learn how to write smart contracts for your dApp, read the ",(0,o.kt)("a",{parentName:"p",href:"/writing-contracts"},"smart contract documentation"),"."))}b.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/303f2c49.38a128da.js b/assets/js/303f2c49.38a128da.js new file mode 100644 index 0000000000..965a2b2b2f --- /dev/null +++ b/assets/js/303f2c49.38a128da.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2882],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return f}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(n),h=r,f=p["".concat(l,".").concat(h)]||p[h]||d[h]||o;return n?a.createElement(f,i(i({ref:t},u),{},{components:n})):a.createElement(f,i({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:p(n);return function(e){var t=(0,c.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function h(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function f(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,o=(0,s.k6)(),i=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,l._X)(i),(0,r.useCallback)((function(e){if(i){var t=new URLSearchParams(o.location.search);t.set(i,e),o.replace(Object.assign({},o.location,{search:t.toString()}))}}),[i,o])]}function m(e){var t,n,a,o,i=e.defaultValue,s=e.queryString,l=void 0!==s&&s,c=e.groupId,p=d(e),m=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!h({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:i,tabValues:p})})),b=m[0],v=m[1],y=f({queryString:l,groupId:c}),g=y[0],k=y[1],w=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:c}.groupId),n=(0,u.Nk)(t),a=n[0],o=n[1],[a,(0,r.useCallback)((function(e){t&&o.set(e)}),[t,o])]),T=w[0],N=w[1],C=function(){var e=null!=g?g:T;return h({value:e,tabValues:p})?e:null}();return(0,r.useLayoutEffect)((function(){C&&v(C)}),[C]),{selectedValue:b,selectValue:(0,r.useCallback)((function(e){if(!h({value:e,tabValues:p}))throw new Error("Can't select invalid tab value="+e);v(e),k(e),N(e)}),[k,N,p]),tabValues:p}}var b=n(2389),v={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function y(e){var t=e.className,n=e.block,s=e.selectedValue,l=e.selectValue,c=e.tabValues,u=[],p=(0,i.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,n=u.indexOf(t),a=c[n].value;a!==s&&(p(t),l(a))},h=function(e){var t,n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var a,r=u.indexOf(e.currentTarget)+1;n=null!=(a=u[r])?a:u[0];break;case"ArrowLeft":var o,i=u.indexOf(e.currentTarget)-1;n=null!=(o=u[i])?o:u[u.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":n},t)},c.map((function(e){var t=e.value,n=e.label,i=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:s===t?0:-1,"aria-selected":s===t,key:t,ref:function(e){return u.push(e)},onKeyDown:h,onClick:d},i,{className:(0,o.Z)("tabs__item",v.tabItem,null==i?void 0:i.className,{"tabs__item--active":s===t})}),null!=n?n:t)})))}function g(e){var t=e.lazy,n=e.children,a=e.selectedValue,o=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var i=o.find((function(e){return e.props.value===a}));return i?(0,r.cloneElement)(i,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},o.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function k(e){var t=m(e);return r.createElement("div",{className:(0,o.Z)("tabs-container",v.tabList)},r.createElement(y,(0,a.Z)({},e,t)),r.createElement(g,(0,a.Z)({},e,t)))}function w(e){var t=(0,b.Z)();return r.createElement(k,(0,a.Z)({key:String(t)},e))}},8438:function(e,t,n){n.r(t),n.d(t,{assets:function(){return d},contentTitle:function(){return u},default:function(){return b},frontMatter:function(){return c},metadata:function(){return p},toc:function(){return h}});var a=n(7462),r=n(3366),o=(n(7294),n(3905)),i=n(4866),s=n(5162),l=["components"],c={},u="dApp Technology Stack",p={unversionedId:"developers/dapps/technology-stack",id:"developers/dapps/technology-stack",title:"dApp Technology Stack",description:"There are 3 layers to building a decentralized application that interacts with a Casper network: Front-end, backend, and on-chain logic. This document outlines lists the requirements for each.",source:"@site/source/docs/casper/developers/dapps/technology-stack.md",sourceDirName:"developers/dapps",slug:"/developers/dapps/technology-stack",permalink:"/developers/dapps/technology-stack",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/dapps/technology-stack.md",tags:[],version:"current",lastUpdatedAt:1707837031,formattedLastUpdatedAt:"Feb 13, 2024",frontMatter:{},sidebar:"developers",previous:{title:"Python SDK",permalink:"/developers/dapps/sdk/python-sdk"},next:{title:"Front-end in React",permalink:"/developers/dapps/template-frontend"}},d={},h=[{value:"Front-End",id:"front-end",level:2},{value:"Signing Transactions",id:"signing-transactions",level:3},{value:"Querying Global State",id:"querying-global-state",level:3},{value:"Backend",id:"backend",level:2},{value:"Blockchain",id:"blockchain",level:2}],f={toc:h},m="wrapper";function b(e){var t=e.components,n=(0,r.Z)(e,l);return(0,o.kt)(m,(0,a.Z)({},f,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"dapp-technology-stack"},"dApp Technology Stack"),(0,o.kt)("p",null,"There are 3 layers to building a decentralized application that interacts with a Casper network: Front-end, backend, and on-chain logic. This document outlines lists the requirements for each."),(0,o.kt)("h2",{id:"front-end"},"Front-End"),(0,o.kt)("p",null,"The front-end, or ",(0,o.kt)("em",{parentName:"p"},"client-side")," of a dApp consists of the interface that the user uses to interact with smart contracts on a Casper Network. This interface usually comes in the form of a website/webpage, mobile device application or computer program, but could also include APIs with endpoints that may be called or queried."),(0,o.kt)("p",null,"You will need to choose a Casper-compatible SDK for the language you are using to call and query smart contracts on a Casper network. Casper's SDKs have methods available for constructing Deploys and gathering global state data. While these interactions can be prepared on the front-end, they must be sent to the backend of your application before being sent off to a network, so as to fulfill ",(0,o.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"CORS")," requirements."),(0,o.kt)("h3",{id:"signing-transactions"},"Signing Transactions"),(0,o.kt)("p",null,"The signing of transactions will, in many cases, need to be performed by the user on the front-end, for which you have a couple options:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"The Casper Wallet"),(0,o.kt)("p",{parentName:"li"},"Use the ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/develop"},"Casper Wallet")," to sign deploys for a Casper network. Deploy objects are first converted to JSON, then sent to the Wallet to be signed, then must be sent to the backend and forwarded to a node."),(0,o.kt)("admonition",{parentName:"li",type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"The Casper Signer has been deprecated and replaced with the ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io"},"Casper Wallet"),". We are in the process of updating this page. Meanwhile, visit the guide on ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/develop"},"Building with the Casper Wallet"),"."))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Third-party signers"),(0,o.kt)("p",{parentName:"li"},"Third-party signers may be used as well. A JSON representation of the unsigned transaction should be forwarded to the third-party signer and accept a callback containing the signed deploy object."))),(0,o.kt)("h3",{id:"querying-global-state"},"Querying Global State"),(0,o.kt)("p",null,"To execute a query of global state, such as retrieving smart contract data or getting current chain information, the preparation may be done on the front-end, but the query to a node must ultimately originate from your application's backend. This preparatory stage comes only in the form of defining a contract hash and the path which you'd like to query data. Alternately, for chain information, you must define the endpoint you'd like to query."),(0,o.kt)("h2",{id:"backend"},"Backend"),(0,o.kt)("p",null,"The backend of a dApp consists of the server-side code that connects the blockchain to the front-end interface and deals with data-parsing and application-layer communication. A backend server is necessary for building dApps on Casper as Casper's nodes expect ",(0,o.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"CORS headers")," from a specified origin on the HTTP requests they receive. Backend servers are helpful for other reasons too, such as queueing requests and analyzing the traffic moving between your dApp and the blockchain."),(0,o.kt)("p",null,"As the backend server of a dApp is the software communicating with Casper nodes (the blockchain), it needs to receive information such as which node and endpoint to connect to."),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'const client = new CasperClient("http://NODE_ADDRESS:7777/rpc");\n'))),(0,o.kt)(s.Z,{value:"py",label:"Python",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'client = NodeClient(NodeConnection((host = "NODE_ADDRESS"), (port_rpc = 7777)));\n')))),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"You can find online peers for Mainnet at ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live"},"cspr.live")," or testnet at ",(0,o.kt)("a",{parentName:"p",href:"https://testnet.cspr.live"},"testnet.cspr.live"))),(0,o.kt)("p",null,"There are two main types of blockchain interactions that will originate from the front-end: deploys and queries. In the case of a dApp, both of these will pass through the back-end."),(0,o.kt)("p",null,"Blockchain interaction for state queries is handled solely on the backend. On the front-end, a user simply chooses the path at which they want to query data. This path is sent to the backend where the server will perform the state query and send the result back to the front-end."),(0,o.kt)("p",null,"In the case of a user-signed transaction originating from the dApp's front-end, the backend will need to accept this transaction and forward it to a Casper network. This is often accomplished by opening a POST endpoint that accepts JSON formatted transactions and forwards them along."),(0,o.kt)("h2",{id:"blockchain"},"Blockchain"),(0,o.kt)("p",null,"The last stop for a deploy or query is the blockchain itself. Like the majority of smart contract blockchains, Casper networks maintain a forever-growing, immutable ledger that can be read and written to. When building a dApp for a Casper network, user interactions in the form of queries and deploys originate from the front-end, are forwarded to the backend, and are then sent to a Casper node for interaction with the blockchain. You can communicate with Casper nodes using JSON RPC calls, and have a variety of open ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/json-rpc-transactional"},"transactional"),", ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/json-rpc-informational"},"informational"),", and ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/json-rpc-pos"},"Proof-of-Stake")," endpoints. By utilizing an SDK on the backend, you won't need to construct these JSON RPC calls yourself, they'll be done for you within the available methods."),(0,o.kt)("p",null,"More than likely, you will want your dApp to perform personalized functions, store custom data, and perhaps even store or transact upon tokens with monetary value. All of these behaviors can be implemented by writing custom smart contracts for your application. Smart contracts on a Casper network can perform any function that a classical computer can. Casper's smart contracts are executed as ",(0,o.kt)("a",{parentName:"p",href:"https://webassembly.org/"},"WebAssembly")," binaries, and can be written in any language that compiles to WebAssembly. Currently, most developers choose to write their smart contracts in ",(0,o.kt)("a",{parentName:"p",href:"https://www.rust-lang.org/"},"Rust")," for its reliability and ease-of-use. Additionally, Casper's smart contract documentation is written for Rust."),(0,o.kt)("p",null,"To learn how to write smart contracts for your dApp, read the ",(0,o.kt)("a",{parentName:"p",href:"/writing-contracts"},"smart contract documentation"),"."))}b.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/35a30807.18a52ef5.js b/assets/js/35a30807.332ce4d9.js similarity index 72% rename from assets/js/35a30807.18a52ef5.js rename to assets/js/35a30807.332ce4d9.js index 62723830c1..fdb4a2ec09 100644 --- a/assets/js/35a30807.18a52ef5.js +++ b/assets/js/35a30807.332ce4d9.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8638],{3905:function(e,t,r){r.d(t,{Zo:function(){return l},kt:function(){return m}});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var a=n.createContext({}),s=function(e){var t=n.useContext(a),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(a.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(r),h=o,m=p["".concat(a,".").concat(h)]||p[h]||f[h]||i;return r?n.createElement(m,c(c({ref:t},l),{},{components:r})):n.createElement(m,c({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,c=new Array(i);c[0]=h;var u={};for(var a in t)hasOwnProperty.call(t,a)&&(u[a]=t[a]);u.originalType=e,u[p]="string"==typeof e?e:o,c[1]=u;for(var s=2;s=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var a=n.createContext({}),s=function(e){var t=n.useContext(a),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(a.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,a=e.parentName,l=u(e,["components","mdxType","originalType","parentName"]),p=s(r),h=o,m=p["".concat(a,".").concat(h)]||p[h]||f[h]||i;return r?n.createElement(m,c(c({ref:t},l),{},{components:r})):n.createElement(m,c({ref:t},l))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,c=new Array(i);c[0]=h;var u={};for(var a in t)hasOwnProperty.call(t,a)&&(u[a]=t[a]);u.originalType=e,u[p]="string"==typeof e?e:o,c[1]=u;for(var s=2;s=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var p=r.createContext({}),l=function(e){var t=r.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,s=e.originalType,p=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),c=l(a),h=n,m=c["".concat(p,".").concat(h)]||c[h]||u[h]||s;return a?r.createElement(m,o(o({ref:t},d),{},{components:a})):r.createElement(m,o({ref:t},d))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var s=a.length,o=new Array(s);o[0]=h;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i[c]="string"==typeof e?e:n,o[1]=i;for(var l=2;l=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var p=r.createContext({}),l=function(e){var t=r.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,s=e.originalType,p=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),c=l(a),h=n,m=c["".concat(p,".").concat(h)]||c[h]||u[h]||s;return a?r.createElement(m,o(o({ref:t},d),{},{components:a})):r.createElement(m,o({ref:t},d))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var s=a.length,o=new Array(s);o[0]=h;var i={};for(var p in t)hasOwnProperty.call(t,p)&&(i[p]=t[p]);i.originalType=e,i[c]="string"==typeof e?e:n,o[1]=i;for(var l=2;l=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=a.createContext({}),l=function(e){var t=a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,i=p(e,["components","mdxType","originalType","parentName"]),u=l(r),y=n,m=u["".concat(c,".").concat(y)]||u[y]||f[y]||o;return r?a.createElement(m,s(s({ref:t},i),{},{components:r})):a.createElement(m,s({ref:t},i))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=y;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[u]="string"==typeof e?e:n,s[1]=p;for(var l=2;l=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=a.createContext({}),l=function(e){var t=a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,i=p(e,["components","mdxType","originalType","parentName"]),u=l(r),y=n,m=u["".concat(c,".").concat(y)]||u[y]||f[y]||o;return r?a.createElement(m,s(s({ref:t},i),{},{components:r})):a.createElement(m,s({ref:t},i))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=y;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[u]="string"==typeof e?e:n,s[1]=p;for(var l=2;l=0||(s[a]=e[a]);return s}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(s[a]=e[a])}return s}var i=n.createContext({}),d=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},c=function(e){var t=d(e.components);return n.createElement(i.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,s=e.mdxType,r=e.originalType,i=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=d(a),m=s,h=p["".concat(i,".").concat(m)]||p[m]||u[m]||r;return a?n.createElement(h,l(l({ref:t},c),{},{components:a})):n.createElement(h,l({ref:t},c))}));function h(e,t){var a=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var r=a.length,l=new Array(r);l[0]=m;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[p]="string"==typeof e?e:s,l[1]=o;for(var d=2;d\n")),(0,r.kt)("p",null,"Update the weight of the primary key to 3 by calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"update_associated_keys.wasm"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/update_associated_keys.wasm \\\n--session-arg "associated_key:key=\'account-hash-\'" \\\n--session-arg "new_weight:u8=\'3\'"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The primary key in this account should now have weight 3."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("p",null,"The table below summarizes the updates."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")))),(0,r.kt)("h3",{id:"step-4-update-the-accounts-action-thresholds"},"Step 4: Update the account's action thresholds"),(0,r.kt)("p",null,"Set up a multi-signature scheme for the account by updating the ",(0,r.kt)("inlineCode",{parentName:"p"},"deployment")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"key_management")," thresholds. The ",(0,r.kt)("inlineCode",{parentName:"p"},"update_thresholds.wasm")," will take two arguments and set the ",(0,r.kt)("inlineCode",{parentName:"p"},"deployment")," threshold to 2 and the ",(0,r.kt)("inlineCode",{parentName:"p"},"key_management")," threshold to 3."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address https://rpc.testnet.casperlabs.io \\\n--chain-name casper-test \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/update_thresholds.wasm \\\n--session-arg \"deployment_threshold:u8='2'\" \\\n--session-arg \"key_management_threshold:u8='3'\"\n")),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The account's action thresholds should look like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"action_thresholds": {\n "deployment": 2,\n "key_management": 3\n},\n')),(0,r.kt)("p",null,"This account configuration requires a cumulative weight of 3 to manage keys and a cumulative weight of 2 to send deploys. For example, if two associated keys have weight 1, they must both sign and send the deploy as part of this account context. The cumulative weight of these two keys would not meet the threshold for key management."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("p",null,"The table below summarizes the updates."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")))),(0,r.kt)("h3",{id:"step-5-add-associated-keys-to-the-primary-account"},"Step 5: Add associated keys to the primary account"),(0,r.kt)("p",null,"To add an associated key to the primary account, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"add_account.wasm")," provided. This example adds two keys to the primary account (",(0,r.kt)("inlineCode",{parentName:"p"},"account-hash-d89c*"),"): ",(0,r.kt)("inlineCode",{parentName:"p"},"user_1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"account-hash-e2d0*"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"user_2")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"account-hash-04a9*"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/add_account.wasm \\\n--session-arg "new_key:key=\'account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7" \\\n--session-arg "weight:u8=\'1\'"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/add_account.wasm \\\n--session-arg "new_key:key=\'account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f" \\\n--session-arg "weight:u8=\'1\'"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"Now, the account should have one primary key with weight 3, and two associated accounts, each with weight 1."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n },\n {\n "account_hash": "account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7",\n "weight": 1\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("ol",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ol"},"All associated keys should be kept incredibly secure to ensure the security and integrity of the account."),(0,r.kt)("li",{parentName:"ol"},"After all associated keys and action thresholds have been set to the desired multi-signature scheme, the weight of the original primary key can be increased or lowered, depending on your use case. Be careful with this! If you lower the primary key's weight below the key management threshold, the account will require multiple signatures for key management. The account will be unusable if you do not have enough associated keys set up."))),(0,r.kt)("p",null,"The table below summarizes the updates."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"04a9..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"N/A"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"e2d0..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"N/A"),(0,r.kt)("td",{parentName:"tr",align:null},"1")))),(0,r.kt)("h3",{id:"step-6-send-a-deploy-from-the-primary-account"},"Step 6: Send a deploy from the primary account"),(0,r.kt)("p",null,"This step sends a deploy containing Wasm (",(0,r.kt)("inlineCode",{parentName:"p"},"contract.wasm"),"), which adds a named key to the account. The source code for the Wasm comes from the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/hello-world"},"hello-world")," repository. The deploy should succeed as the primary account has a weight of 3, which is greater than the deployment threshold."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy --chain-name casper-test \\\n--payment-amount 3000000000 \\\n--session-path tests/wasm/contract.wasm \\\n--secret-key $PATH/secret_key.pem \\\n--session-arg \"my-key-name:string='primary_account_key'\" \\\n--session-arg \"message:string='Hello, World'\"\n")),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"hello_world.wasm")," should have run and added a named key to the account."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"named_keys": [\n {\n "key": "uref-9b9ecaa9e5e235fc6955d4d528cb1b5b38f2d800f6cbbc55351131a3701b5a81-007",\n "name": "my-key-name"\n }\n]\n')),(0,r.kt)("h3",{id:"step-7-send-a-multi-signature-deploy-from-an-associated-key"},"Step 7: Send a multi-signature deploy from an associated key"),(0,r.kt)("p",null,"Given the multi-signature scheme set up in this example, two associated keys need to sign to send a deploy from one of the associated keys. This example uses the following commands to sign a deploy with multiple keys and send it to the network:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"make-deploy")," - creates and signs a deploy, saving the output to a file"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sign-deploy")," - adds additional signatures for a multi-signature deploy"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"send-deploy")," - sends the deploy to the network")),(0,r.kt)("p",null,"Similar to step 6, this example uses Wasm (",(0,r.kt)("inlineCode",{parentName:"p"},"contract.wasm"),"), which adds a named key to the account. The deploy originates from the primary account, specified with the ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-account")," argument. The deploy needs two signatures to meet the ",(0,r.kt)("inlineCode",{parentName:"p"},"deployment")," weight equal to 2. Once both associated keys sign the deploy, either can send it to the network."),(0,r.kt)("p",null,"When using the ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-account")," argument, specify the hex-encoded public key of the primary account context under which the session code will be executed."),(0,r.kt)("p",null,"One associated key creates and signs the deploy with the ",(0,r.kt)("inlineCode",{parentName:"p"},"make-deploy")," command, indicating the account context under which the session code will be executed."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client make-deploy --chain-name casper-test \\\n--payment-amount 300000000 \\\n--session-path tests/wasm/contract.wasm \\\n--secret-key $PATH/user_1_secret_key.pem \\\n--session-arg \"my-key-name:string='user_1_key'\" \\\n--session-arg \"message:string='Hello, World'\" \\\n--session-account 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986 \\\n--output hello_world_one_signature\n")),(0,r.kt)("p",null,"The second associated key signs the deploy with ",(0,r.kt)("inlineCode",{parentName:"p"},"sign-deploy")," to meet the deployment threshold for the account."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client sign-deploy -i hello_world_one_signature -k $PATH/user_2_secret_key.pem -o hello_world_two_signatures\n")),(0,r.kt)("p",null,"The deploy can be sent to the network using the ",(0,r.kt)("inlineCode",{parentName:"p"},"send-deploy")," command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client send-deploy --node-address https://rpc.testnet.casperlabs.io -i hello_world_two_signatures\n")),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"hello_world.wasm")," should have run and added a named key to the account."),(0,r.kt)("h2",{id:"removing-a-compromised-key"},"Removing a Compromised Key"),(0,r.kt)("p",null,"This example shows how to remove a compromised key from an account. The example adds an associated key only to remove it using the ",(0,r.kt)("inlineCode",{parentName:"p"},"remove_account.wasm")," session code."),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Remove keys with caution! Do not run this example on Mainnet."),(0,r.kt)("p",{parentName:"admonition"},"Before removing a key, ensure the remaining associated keys can combine their weight to meet the threshold for key management. Otherwise, the account could become unusable. Changing key weights or adding new associated keys would only be possible by meeting the key management threshold. Proceed with caution.")),(0,r.kt)("p",null,"Given the current setup, the primary account will add an associated key, and then remove it. In other use cases, associated keys may need to combine their signatures to send a multi-sig deploy that removes a key."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/add_account.wasm \\\n--session-arg "new_key:key=\'account-hash-1fed34baa6807a7868bb18f91b161d99ebf21763810fe4c92e39775d10bbf1f8" \\\n--session-arg "weight:u8=\'1\'"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1fed34baa6807a7868bb18f91b161d99ebf21763810fe4c92e39775d10bbf1f8",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n },\n {\n "account_hash": "account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7",\n "weight": 1\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("p",null,"The table below summarizes the updates after calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"add_account.wasm"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"04a9..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"e2d0..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"1fed..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"N/A"),(0,r.kt)("td",{parentName:"tr",align:null},"1")))),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"remove_account.wasm")," will remove the newly added account to demonstrate the possibility of removing associated keys that may have been compromised."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/remove_account.wasm \\\n--session-arg "remove_key:key=\'account-hash-1fed34baa6807a7868bb18f91b161d99ebf21763810fe4c92e39775d10bbf1f8"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The resulting account should not contain the associated key that was just removed."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n },\n {\n "account_hash": "account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7",\n "weight": 1\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("p",null,"The table below summarizes the updates after calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"remove_account.wasm"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"04a9..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"e2d0..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"1fed..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"N/A (Removed)")))),(0,r.kt)("h2",{id:"next-steps"},"Next Steps"),(0,r.kt)("p",null,"The next section contains ",(0,r.kt)("a",{parentName:"p",href:"/resources/advanced/multi-sig/other-scenarios"},"additional examples")," where Casper's multi-signature feature would be helpful."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/39b6f026.c0b2dde4.js b/assets/js/39b6f026.c0b2dde4.js deleted file mode 100644 index 0d6d78ccd4..0000000000 --- a/assets/js/39b6f026.c0b2dde4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2870],{3905:function(e,t,a){a.d(t,{Zo:function(){return c},kt:function(){return h}});var n=a(7294);function s(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t=0||(s[a]=e[a]);return s}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(s[a]=e[a])}return s}var i=n.createContext({}),d=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},c=function(e){var t=d(e.components);return n.createElement(i.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,s=e.mdxType,r=e.originalType,i=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=d(a),m=s,h=p["".concat(i,".").concat(m)]||p[m]||u[m]||r;return a?n.createElement(h,l(l({ref:t},c),{},{components:a})):n.createElement(h,l({ref:t},c))}));function h(e,t){var a=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var r=a.length,l=new Array(r);l[0]=m;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[p]="string"==typeof e?e:s,l[1]=o;for(var d=2;d\n")),(0,r.kt)("p",null,"Update the weight of the primary key to 3 by calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"update_associated_keys.wasm"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/update_associated_keys.wasm \\\n--session-arg "associated_key:key=\'account-hash-\'" \\\n--session-arg "new_weight:u8=\'3\'"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The primary key in this account should now have weight 3."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("p",null,"The table below summarizes the updates."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")))),(0,r.kt)("h3",{id:"step-4-update-the-accounts-action-thresholds"},"Step 4: Update the account's action thresholds"),(0,r.kt)("p",null,"Set up a multi-signature scheme for the account by updating the ",(0,r.kt)("inlineCode",{parentName:"p"},"deployment")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"key_management")," thresholds. The ",(0,r.kt)("inlineCode",{parentName:"p"},"update_thresholds.wasm")," will take two arguments and set the ",(0,r.kt)("inlineCode",{parentName:"p"},"deployment")," threshold to 2 and the ",(0,r.kt)("inlineCode",{parentName:"p"},"key_management")," threshold to 3."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address https://rpc.testnet.casperlabs.io \\\n--chain-name casper-test \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/update_thresholds.wasm \\\n--session-arg \"deployment_threshold:u8='2'\" \\\n--session-arg \"key_management_threshold:u8='3'\"\n")),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The account's action thresholds should look like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"action_thresholds": {\n "deployment": 2,\n "key_management": 3\n},\n')),(0,r.kt)("p",null,"This account configuration requires a cumulative weight of 3 to manage keys and a cumulative weight of 2 to send deploys. For example, if two associated keys have weight 1, they must both sign and send the deploy as part of this account context. The cumulative weight of these two keys would not meet the threshold for key management."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("p",null,"The table below summarizes the updates."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")))),(0,r.kt)("h3",{id:"step-5-add-associated-keys-to-the-primary-account"},"Step 5: Add associated keys to the primary account"),(0,r.kt)("p",null,"To add an associated key to the primary account, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"add_account.wasm")," provided. This example adds two keys to the primary account (",(0,r.kt)("inlineCode",{parentName:"p"},"account-hash-d89c*"),"): ",(0,r.kt)("inlineCode",{parentName:"p"},"user_1")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"account-hash-e2d0*"),", and ",(0,r.kt)("inlineCode",{parentName:"p"},"user_2")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"account-hash-04a9*"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/add_account.wasm \\\n--session-arg "new_key:key=\'account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7" \\\n--session-arg "weight:u8=\'1\'"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/add_account.wasm \\\n--session-arg "new_key:key=\'account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f" \\\n--session-arg "weight:u8=\'1\'"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"Now, the account should have one primary key with weight 3, and two associated accounts, each with weight 1."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n },\n {\n "account_hash": "account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7",\n "weight": 1\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("ol",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ol"},"All associated keys should be kept incredibly secure to ensure the security and integrity of the account."),(0,r.kt)("li",{parentName:"ol"},"After all associated keys and action thresholds have been set to the desired multi-signature scheme, the weight of the original primary key can be increased or lowered, depending on your use case. Be careful with this! If you lower the primary key's weight below the key management threshold, the account will require multiple signatures for key management. The account will be unusable if you do not have enough associated keys set up."))),(0,r.kt)("p",null,"The table below summarizes the updates."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"04a9..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"N/A"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"e2d0..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"N/A"),(0,r.kt)("td",{parentName:"tr",align:null},"1")))),(0,r.kt)("h3",{id:"step-6-send-a-deploy-from-the-primary-account"},"Step 6: Send a deploy from the primary account"),(0,r.kt)("p",null,"This step sends a deploy containing Wasm (",(0,r.kt)("inlineCode",{parentName:"p"},"contract.wasm"),"), which adds a named key to the account. The source code for the Wasm comes from the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/hello-world"},"hello-world")," repository. The deploy should succeed as the primary account has a weight of 3, which is greater than the deployment threshold."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy --chain-name casper-test \\\n--payment-amount 3000000000 \\\n--session-path tests/wasm/contract.wasm \\\n--secret-key $PATH/secret_key.pem \\\n--session-arg \"my-key-name:string='primary_account_key'\" \\\n--session-arg \"message:string='Hello, World'\"\n")),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"hello_world.wasm")," should have run and added a named key to the account."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"named_keys": [\n {\n "key": "uref-9b9ecaa9e5e235fc6955d4d528cb1b5b38f2d800f6cbbc55351131a3701b5a81-007",\n "name": "my-key-name"\n }\n]\n')),(0,r.kt)("h3",{id:"step-7-send-a-multi-signature-deploy-from-an-associated-key"},"Step 7: Send a multi-signature deploy from an associated key"),(0,r.kt)("p",null,"Given the multi-signature scheme set up in this example, two associated keys need to sign to send a deploy from one of the associated keys. This example uses the following commands to sign a deploy with multiple keys and send it to the network:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"make-deploy")," - creates and signs a deploy, saving the output to a file"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sign-deploy")," - adds additional signatures for a multi-signature deploy"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"send-deploy")," - sends the deploy to the network")),(0,r.kt)("p",null,"Similar to step 6, this example uses Wasm (",(0,r.kt)("inlineCode",{parentName:"p"},"contract.wasm"),"), which adds a named key to the account. The deploy originates from the primary account, specified with the ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-account")," argument. The deploy needs two signatures to meet the ",(0,r.kt)("inlineCode",{parentName:"p"},"deployment")," weight equal to 2. Once both associated keys sign the deploy, either can send it to the network."),(0,r.kt)("p",null,"When using the ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-account")," argument, specify the hex-encoded public key of the primary account context under which the session code will be executed."),(0,r.kt)("p",null,"One associated key creates and signs the deploy with the ",(0,r.kt)("inlineCode",{parentName:"p"},"make-deploy")," command, indicating the account context under which the session code will be executed."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client make-deploy --chain-name casper-test \\\n--payment-amount 300000000 \\\n--session-path tests/wasm/contract.wasm \\\n--secret-key $PATH/user_1_secret_key.pem \\\n--session-arg \"my-key-name:string='user_1_key'\" \\\n--session-arg \"message:string='Hello, World'\" \\\n--session-account 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986 \\\n--output hello_world_one_signature\n")),(0,r.kt)("p",null,"The second associated key signs the deploy with ",(0,r.kt)("inlineCode",{parentName:"p"},"sign-deploy")," to meet the deployment threshold for the account."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client sign-deploy -i hello_world_one_signature -k $PATH/user_2_secret_key.pem -o hello_world_two_signatures\n")),(0,r.kt)("p",null,"The deploy can be sent to the network using the ",(0,r.kt)("inlineCode",{parentName:"p"},"send-deploy")," command:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client send-deploy --node-address https://rpc.testnet.casperlabs.io -i hello_world_two_signatures\n")),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"hello_world.wasm")," should have run and added a named key to the account."),(0,r.kt)("h2",{id:"removing-a-compromised-key"},"Removing a Compromised Key"),(0,r.kt)("p",null,"This example shows how to remove a compromised key from an account. The example adds an associated key only to remove it using the ",(0,r.kt)("inlineCode",{parentName:"p"},"remove_account.wasm")," session code."),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"Remove keys with caution! Do not run this example on Mainnet."),(0,r.kt)("p",{parentName:"admonition"},"Before removing a key, ensure the remaining associated keys can combine their weight to meet the threshold for key management. Otherwise, the account could become unusable. Changing key weights or adding new associated keys would only be possible by meeting the key management threshold. Proceed with caution.")),(0,r.kt)("p",null,"Given the current setup, the primary account will add an associated key, and then remove it. In other use cases, associated keys may need to combine their signatures to send a multi-sig deploy that removes a key."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/add_account.wasm \\\n--session-arg "new_key:key=\'account-hash-1fed34baa6807a7868bb18f91b161d99ebf21763810fe4c92e39775d10bbf1f8" \\\n--session-arg "weight:u8=\'1\'"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1fed34baa6807a7868bb18f91b161d99ebf21763810fe4c92e39775d10bbf1f8",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n },\n {\n "account_hash": "account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7",\n "weight": 1\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("p",null,"The table below summarizes the updates after calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"add_account.wasm"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"04a9..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"e2d0..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"1fed..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"N/A"),(0,r.kt)("td",{parentName:"tr",align:null},"1")))),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"remove_account.wasm")," will remove the newly added account to demonstrate the possibility of removing associated keys that may have been compromised."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \\\n--chain-name "casper-test" \\\n--payment-amount 500000000 \\\n--secret-key $PATH/secret_key.pem \\\n--session-path target/wasm32-unknown-unknown/release/remove_account.wasm \\\n--session-arg "remove_key:key=\'account-hash-1fed34baa6807a7868bb18f91b161d99ebf21763810fe4c92e39775d10bbf1f8"\n')),(0,r.kt)("p",null,"Verify that the deploy ran successfully."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ \n")),(0,r.kt)("p",null,"Retrieve the latest state root hash and check the primary account details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/\n\ncasper-client query-global-state \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--state-root-hash \\\n--key account-hash-\n")),(0,r.kt)("p",null,"The resulting account should not contain the associated key that was just removed."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Account details"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'"Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n },\n {\n "account_hash": "account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7",\n "weight": 1\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "named_keys": []\n}\n'))),(0,r.kt)("p",null,"The table below summarizes the updates after calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"remove_account.wasm"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Threshold / Key"),(0,r.kt)("th",{parentName:"tr",align:null},"Previous weight"),(0,r.kt)("th",{parentName:"tr",align:null},"Current weight"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"deployment")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"key_management")),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Primary key (",(0,r.kt)("inlineCode",{parentName:"td"},"1ed5..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"3")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"04a9..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"e2d0..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Associated key (",(0,r.kt)("inlineCode",{parentName:"td"},"1fed..."),")"),(0,r.kt)("td",{parentName:"tr",align:null},"1"),(0,r.kt)("td",{parentName:"tr",align:null},"N/A (Removed)")))),(0,r.kt)("h2",{id:"next-steps"},"Next Steps"),(0,r.kt)("p",null,"The next section contains ",(0,r.kt)("a",{parentName:"p",href:"/resources/advanced/multi-sig/other-scenarios"},"additional examples")," where Casper's multi-signature feature would be helpful."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3b05c439.ca8c75d2.js b/assets/js/3b05c439.ca8c75d2.js new file mode 100644 index 0000000000..178940a8f2 --- /dev/null +++ b/assets/js/3b05c439.ca8c75d2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[299],{3905:function(e,t,o){o.d(t,{Zo:function(){return p},kt:function(){return u}});var a=o(7294);function n(e,t,o){return t in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}function r(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,a)}return o}function s(e){for(var t=1;t=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var c=a.createContext({}),i=function(e){var t=a.useContext(c),o=t;return e&&(o="function"==typeof e?e(t):s(s({},t),e)),o},p=function(e){var t=i(e.components);return a.createElement(c.Provider,{value:t},e.children)},k="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var o=e.components,n=e.mdxType,r=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),k=i(o),d=n,u=k["".concat(c,".").concat(d)]||k[d]||h[d]||r;return o?a.createElement(u,s(s({ref:t},p),{},{components:o})):a.createElement(u,s({ref:t},p))}));function u(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=o.length,s=new Array(r);s[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[k]="string"==typeof e?e:n,s[1]=l;for(var i=2;i=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var c=a.createContext({}),i=function(e){var t=a.useContext(c),o=t;return e&&(o="function"==typeof e?e(t):s(s({},t),e)),o},p=function(e){var t=i(e.components);return a.createElement(c.Provider,{value:t},e.children)},k="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var o=e.components,n=e.mdxType,r=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),k=i(o),d=n,u=k["".concat(c,".").concat(d)]||k[d]||h[d]||r;return o?a.createElement(u,s(s({ref:t},p),{},{components:o})):a.createElement(u,s({ref:t},p))}));function u(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=o.length,s=new Array(r);s[0]=d;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[k]="string"==typeof e?e:n,s[1]=l;for(var i=2;i=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),l=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},i=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(n),m=a,f=u["".concat(p,".").concat(m)]||u[m]||h[m]||o;return n?r.createElement(f,s(s({ref:t},i),{},{components:n})):r.createElement(f,s({ref:t},i))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=m;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),l=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},i=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(n),m=a,f=u["".concat(p,".").concat(m)]||u[m]||h[m]||o;return n?r.createElement(f,s(s({ref:t},i),{},{components:n})):r.createElement(f,s({ref:t},i))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=m;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var i=n.createContext({}),l=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),d=a,f=u["".concat(i,".").concat(d)]||u[d]||m[d]||o;return r?n.createElement(f,c(c({ref:t},p),{},{components:r})):n.createElement(f,c({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:a,c[1]=s;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var i=n.createContext({}),l=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),d=a,f=u["".concat(i,".").concat(d)]||u[d]||m[d]||o;return r?n.createElement(f,c(c({ref:t},p),{},{components:r})):n.createElement(f,c({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,c=new Array(o);c[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:a,c[1]=s;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),y=a,m=u["".concat(p,".").concat(y)]||u[y]||f[y]||o;return r?n.createElement(m,s(s({ref:t},i),{},{components:r})):n.createElement(m,s({ref:t},i))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),l=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=l(n),m=r,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},p),{},{components:n})):a.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:r,i[1]=c;for(var l=2;lcargo casper",id:"automatic-project-setup",level:3},{value:"Semi-automatically using plain cargo",id:"semi-automatic-project-setup",level:3},{value:"Manually",id:"manual-project-setup",level:3},{value:"Dependencies",id:"dependencies",level:3},{value:"Writing a Basic Smart Contract",id:"writing-a-basic-smart-contract",level:2},{value:"Updating the main.rs File",id:"updating-the-mainrs-file",level:3},{value:"Defining required dependencies",id:"defining-required-dependencies",level:4},{value:"Defining the global constants",id:"defining-the-global-constants",level:4},{value:"Defining the contract entry points",id:"defining-the-contract-entry-points",level:4},{value:"Defining the call function",id:"defining-the-call-function",level:4},{value:"Locked Contracts",id:"locked-contracts",level:2},{value:"Compiling Contract Code",id:"compiling-contract-code",level:2},{value:"Executing Contract Code",id:"executing-contract-code",level:2},{value:"Video Walkthrough",id:"video-walkthrough",level:2},{value:"What's Next?",id:"whats-next",level:2}],u={toc:d},m="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)(m,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"writing-a-basic-smart-contract-in-rust"},"Writing a Basic Smart Contract in Rust"),(0,o.kt)("h2",{id:"what-is-a-smart-contract"},"What is a Smart Contract?"),(0,o.kt)("p",null,"A smart contract is a self-contained program installed on a blockchain. In the context of a Casper network, a smart contract consists of contract code installed on-chain using a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#execution-semantics-deploys"},"Deploy"),". Casper smart contracts are programs that run on a Casper network. They interact with accounts and other contracts through entry points, allowing for various triggers, conditions, and logic."),(0,o.kt)("p",null,"Smart contracts exist as stored on-chain logic, allowing disparate users to call the included entry points. These contracts can, in turn, call one another to perform interconnected operations and create more complex programs. The decentralized nature of blockchain technology means that these smart contracts do not suffer from any single point of failure. Even if a Casper node leaves the network, other nodes will continue to allow the contract to operate as intended."),(0,o.kt)("h2",{id:"key-features-of-casper-contracts"},"Key Features of Casper Contracts"),(0,o.kt)("p",null,"On the Casper platform, developers may write smart contracts in any language that compiles to Wasm binaries. This tutorial focuses specifically on writing a smart contract in the Rust language. The Rust compiler compiles the contract code into Wasm. After that, the Wasm binary can be ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts"},"sent to a node")," on a Casper network using a Deploy. Nodes within the network then ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/p2p#communications-gossiping"},"gossip deploys"),", include them within a block, and finalize them. After finalizing, the network executes the deploys within the block."),(0,o.kt)("p",null,"Further, the Casper platform allows for ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/upgrading-contracts"},"upgradable contracts"),". A ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/struct.ContractPackage.html"},"ContractPackage")," is created through the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_contract.html"},"new_contract")," or ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_locked_contract.html"},"new_locked_contract")," methods. Through these methods, the Casper execution engine automatically creates the new contract package and assigns a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/hash-types#hash-and-key-explanations"},(0,o.kt)("inlineCode",{parentName:"a"},"ContractPackageHash")),". The new contract is added to this package with a ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/struct.ContractHash.html"},(0,o.kt)("inlineCode",{parentName:"a"},"ContractHash"))," key. The execution engine stores the new contract within the contract package alongside any previously installed contract versions, if applicable."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"new_contract")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"new_locked_contract")," methods are a convenience that automatically creates the package associated with a new contract. Developers choosing not to use these methods must first create a contract package to function as a container for their new contract."),(0,o.kt)("p",null,"The contract contains required metadata, and it is primarily identified by its ",(0,o.kt)("inlineCode",{parentName:"p"},"ContractHash"),". While the contract hash identifies a specific ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.ContractVersion.html"},"ContractVersion"),", the ",(0,o.kt)("inlineCode",{parentName:"p"},"ContractPackageHash")," serves as an identifier for the most recent contract version in the contract package."),(0,o.kt)("h2",{id:"directory-structure"},"Creating the Directory Structure"),(0,o.kt)("p",null,"To begin creating a smart contract, you need to set up the project structure, either manually or automatically, as shown below."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"project-directory/\n\n\u2514\u2500\u2500 contract/\n \u251c\u2500\u2500 src/\n \u2514\u2500\u2500 main.rs\n \u2514\u2500\u2500 Cargo.toml\n\n\u2514\u2500\u2500 Makefile\n\u2514\u2500\u2500 rust-toolchain\n\n\u2514\u2500\u2500 tests/\n \u251c\u2500\u2500 src/\n \u2514\u2500\u2500 integration-tests.rs\n \u2514\u2500\u2500 Cargo.toml\n")),(0,o.kt)("p",null,"The project structure would be different in a dApp with full-stack architecture. "),(0,o.kt)("h3",{id:"automatic-project-setup"},"Automatically using ",(0,o.kt)("inlineCode",{parentName:"h3"},"cargo casper")),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/getting-started#creating-a-project"},"cargo casper command")," can automatically set up the project structure. This is the recommended way of setting up a new Casper project."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cargo casper my-project\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper")," command will generate an example contract in the contract directory and an example ",(0,o.kt)("inlineCode",{parentName:"p"},"tests")," crate with logic defined in the ",(0,o.kt)("inlineCode",{parentName:"p"},"integration-tests.rs")," file. The ",(0,o.kt)("inlineCode",{parentName:"p"},"Makefile")," includes commands to prepare and build the contract, and the ",(0,o.kt)("inlineCode",{parentName:"p"},"rust-toolchain")," file specifies the target build version of Rust."),(0,o.kt)("h3",{id:"semi-automatic-project-setup"},"Semi-automatically using plain ",(0,o.kt)("inlineCode",{parentName:"h3"},"cargo")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"If you are a beginner, ",(0,o.kt)("a",{parentName:"p",href:"#creating-the-project-automatically"},"creating the structure automatically")," with ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper")," is recommended and the command creates everything you need to start coding.")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Create a top-level project directory for the contract code and its corresponding tests.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Inside the project directory, run the following command to create a new binary package called ",(0,o.kt)("inlineCode",{parentName:"p"},"contract"),". Use a different name instead of ",(0,o.kt)("inlineCode",{parentName:"p"},"contract")," if you wish."),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cargo new contract\n")),(0,o.kt)("p",{parentName:"li"},"The command creates a ",(0,o.kt)("inlineCode",{parentName:"p"},"contract")," folder with a ",(0,o.kt)("inlineCode",{parentName:"p"},"/src/main.rs")," file and a ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file:"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"main.rs")," - This file would contain the contract code."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"Cargo.toml")," - This file would contain crate dependencies and other configurations.")),(0,o.kt)("p",{parentName:"li"},"The following sections explain how to update these files using example code.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Inside the project directory, run the command to auto-generate the folder structure for the tests. Use a different name instead of ",(0,o.kt)("inlineCode",{parentName:"p"},"tests")," if you wish."),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cargo new tests\n")),(0,o.kt)("p",{parentName:"li"},"The command creates a ",(0,o.kt)("inlineCode",{parentName:"p"},"tests")," folder with a ",(0,o.kt)("inlineCode",{parentName:"p"},"/src/main.rs")," file and a ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file:"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"main.rs")," - This file would store the unit test code required to test the contract. You can rename the file to ",(0,o.kt)("inlineCode",{parentName:"li"},"integration-tests.rs")," as shown in the example structure."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"Cargo.toml")," - This is the file with test configurations.")),(0,o.kt)("p",{parentName:"li"},"The ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/testing-contracts"},"Testing Smart Contracts")," guide explains how to update the tests using example code.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Unlike ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo")," does not create a ",(0,o.kt)("inlineCode",{parentName:"p"},"Makefile")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"rust-toolchain")," configuration file. Therefore, you must manually add these files to the project's root folder."))),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example Makefile"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"prepare:\n rustup target add wasm32-unknown-unknown\n\nbuild-contract:\n cd contract && cargo build --release --target wasm32-unknown-unknown\n wasm-strip contract/target/wasm32-unknown-unknown/release/contract.wasm 2>/dev/null | true\n\ntest: build-contract\n mkdir -p tests/wasm\n cp contract/target/wasm32-unknown-unknown/release/contract.wasm tests/wasm\n cd tests && cargo test\n\nclippy:\n cd contract && cargo clippy --all-targets -- -D warnings\n cd tests && cargo clippy --all-targets -- -D warnings\n\ncheck-lint: clippy\n cd contract && cargo fmt -- --check\n cd tests && cargo fmt -- --check\n\nlint: clippy\n cd contract && cargo fmt\n cd tests && cargo fmt\n"))),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example rust-toolchain file"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"nightly-2022-08-03\n"))),(0,o.kt)("h3",{id:"manual-project-setup"},"Manually"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"If you are a beginner, ",(0,o.kt)("a",{parentName:"p",href:"#creating-the-project-automatically"},"creating the structure automatically")," with ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper")," is recommended, and the command creates everything you need to start coding.")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Create a top-level project directory to store the contract code and corresponding tests.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Create a folder for the contract code inside the project directory. This folder contains the logic that will be compiled into Wasm and executed on a Casper node. In this example, we named the folder ",(0,o.kt)("inlineCode",{parentName:"p"},"contract"),". You can use a different folder name if you wish."),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"In the ",(0,o.kt)("inlineCode",{parentName:"li"},"contract")," folder, add a source folder called ",(0,o.kt)("inlineCode",{parentName:"li"},"src")," and a ",(0,o.kt)("inlineCode",{parentName:"li"},"Cargo.toml")," file, which specifies the contract's dependencies."),(0,o.kt)("li",{parentName:"ul"},"Add a Rust file with the contract code in the ",(0,o.kt)("inlineCode",{parentName:"li"},"src")," folder. In this example, we have the ",(0,o.kt)("inlineCode",{parentName:"li"},"main.rs")," file."))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Navigating back to the project directory, create a folder for the tests, which help verify the contract's functionality. In this example, we named the folder ",(0,o.kt)("inlineCode",{parentName:"p"},"tests"),"."),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"In the ",(0,o.kt)("inlineCode",{parentName:"li"},"tests")," folder, add a source folder called ",(0,o.kt)("inlineCode",{parentName:"li"},"src")," and a ",(0,o.kt)("inlineCode",{parentName:"li"},"Cargo.toml")," file, which specifies the required dependencies to run the tests."),(0,o.kt)("li",{parentName:"ul"},"In the ",(0,o.kt)("inlineCode",{parentName:"li"},"src")," folder, add a Rust file with the tests that verify the contract's behavior. In this example, we have the ",(0,o.kt)("inlineCode",{parentName:"li"},"integration-tests.rs")," file."))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Manually create Makefile and rust-toolchain as per ",(0,o.kt)("a",{parentName:"p",href:"#semi-automatic-project-setup"},"Semi-automatic setup (4.)")))),(0,o.kt)("h3",{id:"dependencies"},"Dependencies"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file in the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract")," folder includes the dependencies and versions the contract requires. At a minimum, you need to import the latest versions of the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/"},"casper-contract")," and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/"},"casper-types")," crates. The following dependencies and version numbers are only examples and must be adjusted based on your requirements."),(0,o.kt)("p",null,"If you followed the ",(0,o.kt)("a",{parentName:"p",href:"#automatic-project-setup"},"automatic setup"),", the dependencies should be in the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file. For the ",(0,o.kt)("a",{parentName:"p",href:"#semi-automatic-project-setup"},"semi-automatic setup")," and ",(0,o.kt)("a",{parentName:"p",href:"#manual-project-setup"},"manual setup"),", however, you'll need to manually add the dependencies to the crate's ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-toml"},'[dependencies]\n# A library for developing Casper network smart contracts.\ncasper-contract = "1.4.4"\n# Types shared by many Casper crates for use on a Casper network.\ncasper-types = "1.5.0"\n')),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'casper-contract = "1.4.4"')," - Provides the SDK for the execution engine (EE). The latest version of the crate is published ",(0,o.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-contract"},"here"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'casper-types = "1.5.0"')," - Includes types shared by many Casper crates for use on a Casper network. This crate is necessary for the EE to understand and interpret the session code. The latest version of the crate is published ",(0,o.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-types"},"here"),".")),(0,o.kt)("h2",{id:"writing-a-basic-smart-contract"},"Writing a Basic Smart Contract"),(0,o.kt)("p",null,"At this point, you either have the default example contract defined in ",(0,o.kt)("inlineCode",{parentName:"p"},"contract/src/main.rs")," (",(0,o.kt)("a",{parentName:"p",href:"#automatic-project-setup"},"automatic")," setup using cargo-casper), an empty ",(0,o.kt)("inlineCode",{parentName:"p"},"contract/src/main.rs")," file (",(0,o.kt)("a",{parentName:"p",href:"#manual-project-setup"},"manual"),' project setup), or a Rust "hello world" program defined in the ',(0,o.kt)("inlineCode",{parentName:"p"},"contract/src/main.rs")," (",(0,o.kt)("a",{parentName:"p",href:"#semi-automatic-project-setup"},"semi-automatic")," setup)."),(0,o.kt)("p",null,"This section covers the process of writing a smart contract in Rust, step by step. Therefore, you should clear the contents of the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract/main.rs")," file if there are any."),(0,o.kt)("p",null,"The example code comes from the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/"},"counter contract"),". This simple contract allows callers to increment and retrieve an integer. Casper provides a ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/index.html"},"contract API")," within the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/index.html"},(0,o.kt)("inlineCode",{parentName:"a"},"casper_contract"))," crate."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Important syntax elements used frequently in Rust:"),(0,o.kt)("ul",{parentName:"admonition"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/flow_control/match.html"},"Match"),(0,o.kt)("br",null)),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/primitives/array.html"},"Array"),(0,o.kt)("br",null)),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/flow_control/loop.html"},"Loop"),(0,o.kt)("br",null)),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/std/vec.html"},"Vectors"),(0,o.kt)("br",null)),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/fn.html"},"Functions"),(0,o.kt)("br",null))),(0,o.kt)("p",{parentName:"admonition"},"To be able to comfortably write code in Rust it is crucial to understand these topics before going further into the examples.")),(0,o.kt)("h3",{id:"updating-the-mainrs-file"},"Updating the ",(0,o.kt)("inlineCode",{parentName:"h3"},"main.rs")," File"),(0,o.kt)("p",null,"To begin writing contract code, add the following file attributes to support the Wasm execution environment. If you still have an auto-generated ",(0,o.kt)("inlineCode",{parentName:"p"},"main.rs")," file, remove the auto-generated main function."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"#![no_std]\n#![no_main]\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"#![no_main]")," - This attribute tells the program not to use the standard main function as its entry point."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"#![no_std]")," - This attribute tells the program not to import the standard libraries.")),(0,o.kt)("h4",{id:"defining-required-dependencies"},"Defining required dependencies"),(0,o.kt)("p",null,"Add the required imports and dependencies. The example code for the counter contract declares the following dependencies."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"// This code imports necessary aspects of external crates that we will use in our contract code.\nextern crate alloc;\n\n// Importing Rust types.\nuse alloc::{\n string::{String, ToString},\n vec::Vec,\n};\n// Importing aspects of the Casper platform.\nuse casper_contract::{\n contract_api::{runtime, storage},\n unwrap_or_revert::UnwrapOrRevert,\n};\n// Importing specific Casper types.\nuse casper_types::{\n api_error::ApiError,\n contracts::{EntryPoint, EntryPointAccess, EntryPointType, EntryPoints, NamedKeys},\n CLType, CLValue, URef,\n};\n")),(0,o.kt)("h4",{id:"defining-the-global-constants"},"Defining the global constants"),(0,o.kt)("p",null,"After importing the necessary dependencies, you should define the constants used within the contract, including entry points and values. The following example outlines the necessary constants for the counter contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'// Creating constants for values within the contract package.\nconst CONTRACT_PACKAGE_NAME: &str = "counter_package_name";\nconst CONTRACT_ACCESS_UREF: &str = "counter_access_uref";\n\n// Creating constants for the various contract entry points.\nconst ENTRY_POINT_COUNTER_INC: &str = "counter_inc";\nconst ENTRY_POINT_COUNTER_GET: &str = "counter_get";\n\n// Creating constants for values within the contract.\nconst CONTRACT_VERSION_KEY: &str = "version";\nconst CONTRACT_KEY: &str = "counter";\nconst COUNT_KEY: &str = "count";\n')),(0,o.kt)("h4",{id:"defining-the-contract-entry-points"},"Defining the contract entry points"),(0,o.kt)("p",null,"Entry points provide access to contract code installed in global state. Either ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session code")," or another smart contract may call these entry points. A contract must have at least one entry point and may have more than one entry point. Entry points are defined by their name, and those names should be clear and self-describing. Each entry point is equivalent to a static main entry point in a traditional program."),(0,o.kt)("p",null,"Entry points are not functions or methods, and they have no arguments. They are static entry points into the contract's logic. Yet, the contract logic can access parameters by name, passed along with the Deploy. Note that another smart contract may access any of these entry points."),(0,o.kt)("p",null,"If an entry point has one or more mandatory parameters that will cause the logic to revert if they are not included, declare them within that entry point. Optional and non-critical parameters should be excluded."),(0,o.kt)("p",null,"When defining entry points, begin with a ",(0,o.kt)("inlineCode",{parentName:"p"},"#[no_mangle]")," line to ensure the system does not change critical syntax within the method names. Each entry point should contain the contract code that drives the action you wish it to accomplish. Finally, include any storage or return values needed, as applicable."),(0,o.kt)("p",null,"The following entry point is an example from the counter contract. To see all the available entry points, review the contract in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/contract-v1/src/main.rs"},"GitHub"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn counter_inc() {\n let uref: URef = runtime::get_key(COUNT_KEY)\n .unwrap_or_revert_with(ApiError::MissingKey)\n .into_uref()\n .unwrap_or_revert_with(ApiError::UnexpectedKeyVariant);\n storage::add(uref, 1); // Increment the count by 1.\n}\n')),(0,o.kt)("h4",{id:"defining-the-call-function"},"Defining the ",(0,o.kt)("inlineCode",{parentName:"h4"},"call")," function"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function starts the code execution and installs the contract on-chain. In some cases, it also initializes some constructs, such as a Dictionary for record-keeping or a purse. The following steps describe how to structure the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function. Review the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/8a622cd92d768893b9ef9fc2b150c674415be87e/contract-v1/src/main.rs#L55"},"call function")," in the counter contract."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Define the runtime arguments.")),(0,o.kt)("p",null,"At the time of contract installation, pass in parameters as runtime arguments. Use this pattern of variable definition to collect any sentinel values that dictate the behavior of the contract. If the entry point takes in arguments, you must declare those as part of the entry point's definition."),(0,o.kt)("p",null,"Look at the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep-78-enhanced-nft/blob/dev/contract/src/main.rs"},"CEP-78 contract")," to see examples of entry points taking in arguments. The counter contract does not use variable parameters since it is too simple."),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},"Add the entry points into the ",(0,o.kt)("inlineCode",{parentName:"li"},"call")," function.")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function replaces a traditional ",(0,o.kt)("inlineCode",{parentName:"p"},"main")," function and executes automatically when a caller interacts with the contract. Within the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function, we define entry points the caller can access using session code or another contract. When writing code that calls an entry point, there must be a one-to-one mapping of the entry point name. Otherwise, the execution engine will return an error that the entry point does not exist."),(0,o.kt)("p",null,"Each entry point should have these arguments:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"name")," - The entry point's name, which should be the same as the initial definition."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"arguments")," - A list of runtime arguments declared as part of the definition of the entry point."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"return type")," - The CLType returned by the entry point. Use the type ",(0,o.kt)("em",{parentName:"li"},"Unit")," for empty return types."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"access level")," - Access permissions of the entry point."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"entry point type")," - This can be ",(0,o.kt)("inlineCode",{parentName:"li"},"contract")," or ",(0,o.kt)("inlineCode",{parentName:"li"},"session")," code.")),(0,o.kt)("p",null,"This step adds the individual entry points to a ",(0,o.kt)("inlineCode",{parentName:"p"},"counter_entry_points")," object using the ",(0,o.kt)("inlineCode",{parentName:"p"},"add_entry_point")," method. This object will later be passed to the ",(0,o.kt)("inlineCode",{parentName:"p"},"new_contract")," method."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n // Initialize the count to 0 locally\n let count_start = storage::new_uref(0_i32);\n // Create the entry points for this contract\n let mut counter_entry_points = EntryPoints::new();\n\n counter_entry_points.add_entry_point(EntryPoint::new(\n ENTRY_POINT_COUNTER_GET,\n Vec::new(),\n CLType::I32,\n EntryPointAccess::Public,\n EntryPointType::Contract,\n ));\n\n counter_entry_points.add_entry_point(EntryPoint::new(\n ENTRY_POINT_COUNTER_INC,\n Vec::new(),\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract,\n ));\n}\n')),(0,o.kt)("p",null,"In the following, we will add more content to this call function."),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},"Create the contract's named keys.")),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.NamedKeys.html"},"NamedKeys")," are a collection of String-Key pairs used to identify some network data quickly."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/nightly/alloc/string/struct.String.html"},"String")," is the name given to identify the data"),(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-types/latest/casper_types/enum.Key.html"},"Key")," is the data to be referenced")),(0,o.kt)("p",null,"You can create named keys to store any record or value as needed, such as other accounts, smart contracts, URefs, transfers, deploy information, purse balances, etc. The list of possible Key variants can be found ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/enum.Key.html"},"here"),"."),(0,o.kt)("p",null,"For the counter, we store the integer that we increment into a named key."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"}," // In the named keys of the counter contract, add a key for the count.\n let mut counter_named_keys = NamedKeys::new();\n let key_name = String::from(COUNT_KEY);\n counter_named_keys.insert(key_name, count_start.into());\n")),(0,o.kt)("ol",{start:4},(0,o.kt)("li",{parentName:"ol"},"Create the contract.")),(0,o.kt)("p",null,"Use the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_contract.html"},"new_contract")," method to create the contract with its named keys and entry points. This method creates the contract object and saves the access URef and the contract package hash in the caller's context. The execution engine automatically creates a contract package and assigns it a ",(0,o.kt)("inlineCode",{parentName:"p"},"contractPackageHash"),". Then, it adds the contract to the package with a ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/struct.ContractHash.html"},(0,o.kt)("inlineCode",{parentName:"a"},"contractHash")),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"}," // Create a new contract package that can be upgraded.\n let (stored_contract_hash, contract_version) = storage::new_contract(\n counter_entry_points,\n Some(counter_named_keys),\n Some(CONTRACT_PACKAGE_NAME.to_string()),\n Some(CONTRACT_ACCESS_UREF.to_string()),\n );\n")),(0,o.kt)("p",null,"Usually, these contracts are upgradeable with the ability to add new ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.ContractVersion.html"},"versions"),". You ",(0,o.kt)("strong",{parentName:"p"},"must have the access URef")," to the contract package to add a new contract version. This can be accomplished by passing the ",(0,o.kt)("inlineCode",{parentName:"p"},"Some(CONTRACT_ACCESS_UREF.to_string())")," argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"new_contract")," method. To prevent any upgrades to a contract, use the ",(0,o.kt)("inlineCode",{parentName:"p"},"new_locked_contract")," method described ",(0,o.kt)("a",{parentName:"p",href:"#locked-contracts"},"below"),"."),(0,o.kt)("ol",{start:5},(0,o.kt)("li",{parentName:"ol"},"Create additional named keys.")),(0,o.kt)("p",null,"Generally, the ",(0,o.kt)("inlineCode",{parentName:"p"},"Contract_Hash")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"Contract_Version")," are saved as ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys")," in the account's context for later use."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"}," // Store the contract version in the context's named keys.\n let version_uref = storage::new_uref(contract_version);\n runtime::put_key(CONTRACT_VERSION_KEY, version_uref.into());\n\n // Create a named key for the contract hash.\n runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());\n")),(0,o.kt)("p",null,"The complete call function should look like this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n // Initialize the count to 0 locally\n let count_start = storage::new_uref(0_i32);\n // Create the entry points for this contract\n let mut counter_entry_points = EntryPoints::new();\n\n counter_entry_points.add_entry_point(EntryPoint::new(\n ENTRY_POINT_COUNTER_GET,\n Vec::new(),\n CLType::I32,\n EntryPointAccess::Public,\n EntryPointType::Contract,\n ));\n\n counter_entry_points.add_entry_point(EntryPoint::new(\n ENTRY_POINT_COUNTER_INC,\n Vec::new(),\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract,\n ));\n\n // In the named keys of the counter contract, add a key for the count.\n let mut counter_named_keys = NamedKeys::new();\n let key_name = String::from(COUNT_KEY);\n counter_named_keys.insert(key_name, count_start.into());\n\n // Create a new contract package that can be upgraded.\n let (stored_contract_hash, contract_version) = storage::new_contract(\n counter_entry_points,\n Some(counter_named_keys),\n Some(CONTRACT_PACKAGE_NAME.to_string()),\n Some(CONTRACT_ACCESS_UREF.to_string()),\n );\n\n /* To create a locked contract instead, use new_locked_contract and throw away the contract version returned\n let (stored_contract_hash, _) =\n storage::new_locked_contract(counter_entry_points, Some(counter_named_keys), None, None); */\n\n // Store the contract version in the context\'s named keys.\n let version_uref = storage::new_uref(contract_version);\n runtime::put_key(CONTRACT_VERSION_KEY, version_uref.into());\n\n // Create a named key for the contract hash.\n runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());\n}\n')),(0,o.kt)("h2",{id:"locked-contracts"},"Locked Contracts"),(0,o.kt)("p",null,"Locked contracts cannot contain other contract ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.ContractVersion.html"},"versions")," in the same contract package; thus, they cannot be upgraded. In this scenario, the Casper execution engine will create a contract package, add a contract to that package and prevent any further upgrades to the contract. Use locked contracts when you need to ensure high security and will not require updates to the contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn new_locked_contract(\n entry_points: EntryPoints,\n named_keys: Option,\n hash_name: Option,\n uref_name: Option,\n) -> (ContractHash, ContractVersion) {\n create_contract(entry_points, named_keys, hash_name, uref_name, true)\n}\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"entry_points")," - The set of entry points defined inside the smart contract."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"named_keys")," - Any ",(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.NamedKeys.html"},"named-key")," pairs for the contract."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"hash_name")," - Contract hash value. Puts ",(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-types/latest/casper_types/contracts/struct.ContractHash.html"},"contractHash")," in the current context's named keys under ",(0,o.kt)("inlineCode",{parentName:"li"},"hash_name"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"uref_name")," - Access URef value. Puts access_uref in the current context's named keys under ",(0,o.kt)("inlineCode",{parentName:"li"},"uref_name"),".")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Note"),": The current context is the context of the person who initiated the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function, usually an account."),(0,o.kt)("p",null,"The counter contract in our example would be locked if we created it this way:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let (stored_contract_hash, _) =\n storage::new_locked_contract(counter_entry_points, Some(counter_named_keys), None, None);\n")),(0,o.kt)("h2",{id:"compiling-contract-code"},"Compiling Contract Code"),(0,o.kt)("p",null,"To compile the smart contract, run the following commands in the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract")," folder in your project's directory, where the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file and ",(0,o.kt)("inlineCode",{parentName:"p"},"src")," folder are hosted."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"rustup target add wasm32-unknown-unknown\ncargo build --release --target wasm32-unknown-unknown\n")),(0,o.kt)("p",null,"For the counter example, in the project directory where the ",(0,o.kt)("inlineCode",{parentName:"p"},"Makefile")," is, run the following commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"make prepare\nmake build-contract\n")),(0,o.kt)("h2",{id:"executing-contract-code"},"Executing Contract Code"),(0,o.kt)("p",null,"Contract execution must be initiated through an outside call, usually via ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session code")," or another smart contract. Developers should also be familiar with the difference between contract code and session code, explained in the next section."),(0,o.kt)("h2",{id:"video-walkthrough"},"Video Walkthrough"),(0,o.kt)("p",null,"The following brief video accompanies this guide."),(0,o.kt)("p",{align:"center"},(0,o.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed/yHJwkhO5EQg",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,o.kt)("h2",{id:"whats-next"},"What's Next?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Learn to ",(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/testing-contracts"},"test your contract"),"."),(0,o.kt)("li",{parentName:"ul"},"Understand ",(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session code")," and how it triggers a smart contract."),(0,o.kt)("li",{parentName:"ul"},"Learn to ",(0,o.kt)("a",{parentName:"li",href:"/developers/cli/installing-contracts"},"install a contract and query global state")," with the Casper command-line client.")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3fe59759.e776ea84.js b/assets/js/3fe59759.e776ea84.js deleted file mode 100644 index 7b614e8ca4..0000000000 --- a/assets/js/3fe59759.e776ea84.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4452],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),l=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),d=l(n),m=r,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},p),{},{components:n})):a.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:r,i[1]=c;for(var l=2;lcargo casper",id:"automatic-project-setup",level:3},{value:"Semi-automatically using plain cargo",id:"semi-automatic-project-setup",level:3},{value:"Manually",id:"manual-project-setup",level:3},{value:"Dependencies",id:"dependencies",level:3},{value:"Writing a Basic Smart Contract",id:"writing-a-basic-smart-contract",level:2},{value:"Updating the main.rs File",id:"updating-the-mainrs-file",level:3},{value:"Defining required dependencies",id:"defining-required-dependencies",level:4},{value:"Defining the global constants",id:"defining-the-global-constants",level:4},{value:"Defining the contract entry points",id:"defining-the-contract-entry-points",level:4},{value:"Defining the call function",id:"defining-the-call-function",level:4},{value:"Locked Contracts",id:"locked-contracts",level:2},{value:"Compiling Contract Code",id:"compiling-contract-code",level:2},{value:"Executing Contract Code",id:"executing-contract-code",level:2},{value:"Video Walkthrough",id:"video-walkthrough",level:2},{value:"What's Next?",id:"whats-next",level:2}],u={toc:d},m="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)(m,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"writing-a-basic-smart-contract-in-rust"},"Writing a Basic Smart Contract in Rust"),(0,o.kt)("h2",{id:"what-is-a-smart-contract"},"What is a Smart Contract?"),(0,o.kt)("p",null,"A smart contract is a self-contained program installed on a blockchain. In the context of a Casper network, a smart contract consists of contract code installed on-chain using a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#execution-semantics-deploys"},"Deploy"),". Casper smart contracts are programs that run on a Casper network. They interact with accounts and other contracts through entry points, allowing for various triggers, conditions, and logic."),(0,o.kt)("p",null,"Smart contracts exist as stored on-chain logic, allowing disparate users to call the included entry points. These contracts can, in turn, call one another to perform interconnected operations and create more complex programs. The decentralized nature of blockchain technology means that these smart contracts do not suffer from any single point of failure. Even if a Casper node leaves the network, other nodes will continue to allow the contract to operate as intended."),(0,o.kt)("h2",{id:"key-features-of-casper-contracts"},"Key Features of Casper Contracts"),(0,o.kt)("p",null,"On the Casper platform, developers may write smart contracts in any language that compiles to Wasm binaries. This tutorial focuses specifically on writing a smart contract in the Rust language. The Rust compiler compiles the contract code into Wasm. After that, the Wasm binary can be ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts"},"sent to a node")," on a Casper network using a Deploy. Nodes within the network then ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/p2p#communications-gossiping"},"gossip deploys"),", include them within a block, and finalize them. After finalizing, the network executes the deploys within the block."),(0,o.kt)("p",null,"Further, the Casper platform allows for ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/upgrading-contracts"},"upgradable contracts"),". A ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/struct.ContractPackage.html"},"ContractPackage")," is created through the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_contract.html"},"new_contract")," or ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_locked_contract.html"},"new_locked_contract")," methods. Through these methods, the Casper execution engine automatically creates the new contract package and assigns a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/hash-types#hash-and-key-explanations"},(0,o.kt)("inlineCode",{parentName:"a"},"ContractPackageHash")),". The new contract is added to this package with a ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/struct.ContractHash.html"},(0,o.kt)("inlineCode",{parentName:"a"},"ContractHash"))," key. The execution engine stores the new contract within the contract package alongside any previously installed contract versions, if applicable."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"new_contract")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"new_locked_contract")," methods are a convenience that automatically creates the package associated with a new contract. Developers choosing not to use these methods must first create a contract package to function as a container for their new contract."),(0,o.kt)("p",null,"The contract contains required metadata, and it is primarily identified by its ",(0,o.kt)("inlineCode",{parentName:"p"},"ContractHash"),". While the contract hash identifies a specific ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.ContractVersion.html"},"ContractVersion"),", the ",(0,o.kt)("inlineCode",{parentName:"p"},"ContractPackageHash")," serves as an identifier for the most recent contract version in the contract package."),(0,o.kt)("h2",{id:"directory-structure"},"Creating the Directory Structure"),(0,o.kt)("p",null,"To begin creating a smart contract, you need to set up the project structure, either manually or automatically, as shown below."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"project-directory/\n\n\u2514\u2500\u2500 contract/\n \u251c\u2500\u2500 src/\n \u2514\u2500\u2500 main.rs\n \u2514\u2500\u2500 Cargo.toml\n\n\u2514\u2500\u2500 Makefile\n\u2514\u2500\u2500 rust-toolchain\n\n\u2514\u2500\u2500 tests/\n \u251c\u2500\u2500 src/\n \u2514\u2500\u2500 integration-tests.rs\n \u2514\u2500\u2500 Cargo.toml\n")),(0,o.kt)("p",null,"The project structure would be different in a dApp with full-stack architecture. "),(0,o.kt)("h3",{id:"automatic-project-setup"},"Automatically using ",(0,o.kt)("inlineCode",{parentName:"h3"},"cargo casper")),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/getting-started#creating-a-project"},"cargo casper command")," can automatically set up the project structure. This is the recommended way of setting up a new Casper project."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cargo casper my-project\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper")," command will generate an example contract in the contract directory and an example ",(0,o.kt)("inlineCode",{parentName:"p"},"tests")," crate with logic defined in the ",(0,o.kt)("inlineCode",{parentName:"p"},"integration-tests.rs")," file. The ",(0,o.kt)("inlineCode",{parentName:"p"},"Makefile")," includes commands to prepare and build the contract, and the ",(0,o.kt)("inlineCode",{parentName:"p"},"rust-toolchain")," file specifies the target build version of Rust."),(0,o.kt)("h3",{id:"semi-automatic-project-setup"},"Semi-automatically using plain ",(0,o.kt)("inlineCode",{parentName:"h3"},"cargo")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"If you are a beginner, ",(0,o.kt)("a",{parentName:"p",href:"#creating-the-project-automatically"},"creating the structure automatically")," with ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper")," is recommended and the command creates everything you need to start coding.")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Create a top-level project directory for the contract code and its corresponding tests.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Inside the project directory, run the following command to create a new binary package called ",(0,o.kt)("inlineCode",{parentName:"p"},"contract"),". Use a different name instead of ",(0,o.kt)("inlineCode",{parentName:"p"},"contract")," if you wish."),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cargo new contract\n")),(0,o.kt)("p",{parentName:"li"},"The command creates a ",(0,o.kt)("inlineCode",{parentName:"p"},"contract")," folder with a ",(0,o.kt)("inlineCode",{parentName:"p"},"/src/main.rs")," file and a ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file:"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"main.rs")," - This file would contain the contract code."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"Cargo.toml")," - This file would contain crate dependencies and other configurations.")),(0,o.kt)("p",{parentName:"li"},"The following sections explain how to update these files using example code.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Inside the project directory, run the command to auto-generate the folder structure for the tests. Use a different name instead of ",(0,o.kt)("inlineCode",{parentName:"p"},"tests")," if you wish."),(0,o.kt)("pre",{parentName:"li"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cargo new tests\n")),(0,o.kt)("p",{parentName:"li"},"The command creates a ",(0,o.kt)("inlineCode",{parentName:"p"},"tests")," folder with a ",(0,o.kt)("inlineCode",{parentName:"p"},"/src/main.rs")," file and a ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file:"),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"main.rs")," - This file would store the unit test code required to test the contract. You can rename the file to ",(0,o.kt)("inlineCode",{parentName:"li"},"integration-tests.rs")," as shown in the example structure."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"Cargo.toml")," - This is the file with test configurations.")),(0,o.kt)("p",{parentName:"li"},"The ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/testing-contracts"},"Testing Smart Contracts")," guide explains how to update the tests using example code.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Unlike ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo")," does not create a ",(0,o.kt)("inlineCode",{parentName:"p"},"Makefile")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"rust-toolchain")," configuration file. Therefore, you must manually add these files to the project's root folder."))),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example Makefile"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"prepare:\n rustup target add wasm32-unknown-unknown\n\nbuild-contract:\n cd contract && cargo build --release --target wasm32-unknown-unknown\n wasm-strip contract/target/wasm32-unknown-unknown/release/contract.wasm 2>/dev/null | true\n\ntest: build-contract\n mkdir -p tests/wasm\n cp contract/target/wasm32-unknown-unknown/release/contract.wasm tests/wasm\n cd tests && cargo test\n\nclippy:\n cd contract && cargo clippy --all-targets -- -D warnings\n cd tests && cargo clippy --all-targets -- -D warnings\n\ncheck-lint: clippy\n cd contract && cargo fmt -- --check\n cd tests && cargo fmt -- --check\n\nlint: clippy\n cd contract && cargo fmt\n cd tests && cargo fmt\n"))),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example rust-toolchain file"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"nightly-2022-08-03\n"))),(0,o.kt)("h3",{id:"manual-project-setup"},"Manually"),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"If you are a beginner, ",(0,o.kt)("a",{parentName:"p",href:"#creating-the-project-automatically"},"creating the structure automatically")," with ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper")," is recommended, and the command creates everything you need to start coding.")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Create a top-level project directory to store the contract code and corresponding tests.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Create a folder for the contract code inside the project directory. This folder contains the logic that will be compiled into Wasm and executed on a Casper node. In this example, we named the folder ",(0,o.kt)("inlineCode",{parentName:"p"},"contract"),". You can use a different folder name if you wish."),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"In the ",(0,o.kt)("inlineCode",{parentName:"li"},"contract")," folder, add a source folder called ",(0,o.kt)("inlineCode",{parentName:"li"},"src")," and a ",(0,o.kt)("inlineCode",{parentName:"li"},"Cargo.toml")," file, which specifies the contract's dependencies."),(0,o.kt)("li",{parentName:"ul"},"Add a Rust file with the contract code in the ",(0,o.kt)("inlineCode",{parentName:"li"},"src")," folder. In this example, we have the ",(0,o.kt)("inlineCode",{parentName:"li"},"main.rs")," file."))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Navigating back to the project directory, create a folder for the tests, which help verify the contract's functionality. In this example, we named the folder ",(0,o.kt)("inlineCode",{parentName:"p"},"tests"),"."),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"In the ",(0,o.kt)("inlineCode",{parentName:"li"},"tests")," folder, add a source folder called ",(0,o.kt)("inlineCode",{parentName:"li"},"src")," and a ",(0,o.kt)("inlineCode",{parentName:"li"},"Cargo.toml")," file, which specifies the required dependencies to run the tests."),(0,o.kt)("li",{parentName:"ul"},"In the ",(0,o.kt)("inlineCode",{parentName:"li"},"src")," folder, add a Rust file with the tests that verify the contract's behavior. In this example, we have the ",(0,o.kt)("inlineCode",{parentName:"li"},"integration-tests.rs")," file."))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},"Manually create Makefile and rust-toolchain as per ",(0,o.kt)("a",{parentName:"p",href:"#semi-automatic-project-setup"},"Semi-automatic setup (4.)")))),(0,o.kt)("h3",{id:"dependencies"},"Dependencies"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file in the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract")," folder includes the dependencies and versions the contract requires. At a minimum, you need to import the latest versions of the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/"},"casper-contract")," and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/"},"casper-types")," crates. The following dependencies and version numbers are only examples and must be adjusted based on your requirements."),(0,o.kt)("p",null,"If you followed the ",(0,o.kt)("a",{parentName:"p",href:"#automatic-project-setup"},"automatic setup"),", the dependencies should be in the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file. For the ",(0,o.kt)("a",{parentName:"p",href:"#semi-automatic-project-setup"},"semi-automatic setup")," and ",(0,o.kt)("a",{parentName:"p",href:"#manual-project-setup"},"manual setup"),", however, you'll need to manually add the dependencies to the crate's ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-toml"},'[dependencies]\n# A library for developing Casper network smart contracts.\ncasper-contract = "1.4.4"\n# Types shared by many Casper crates for use on a Casper network.\ncasper-types = "1.5.0"\n')),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'casper-contract = "1.4.4"')," - Provides the SDK for the execution engine (EE). The latest version of the crate is published ",(0,o.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-contract"},"here"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'casper-types = "1.5.0"')," - Includes types shared by many Casper crates for use on a Casper network. This crate is necessary for the EE to understand and interpret the session code. The latest version of the crate is published ",(0,o.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-types"},"here"),".")),(0,o.kt)("h2",{id:"writing-a-basic-smart-contract"},"Writing a Basic Smart Contract"),(0,o.kt)("p",null,"At this point, you either have the default example contract defined in ",(0,o.kt)("inlineCode",{parentName:"p"},"contract/src/main.rs")," (",(0,o.kt)("a",{parentName:"p",href:"#automatic-project-setup"},"automatic")," setup using cargo-casper), an empty ",(0,o.kt)("inlineCode",{parentName:"p"},"contract/src/main.rs")," file (",(0,o.kt)("a",{parentName:"p",href:"#manual-project-setup"},"manual"),' project setup), or a Rust "hello world" program defined in the ',(0,o.kt)("inlineCode",{parentName:"p"},"contract/src/main.rs")," (",(0,o.kt)("a",{parentName:"p",href:"#semi-automatic-project-setup"},"semi-automatic")," setup)."),(0,o.kt)("p",null,"This section covers the process of writing a smart contract in Rust, step by step. Therefore, you should clear the contents of the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract/main.rs")," file if there are any."),(0,o.kt)("p",null,"The example code comes from the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/"},"counter contract"),". This simple contract allows callers to increment and retrieve an integer. Casper provides a ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/index.html"},"contract API")," within the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/index.html"},(0,o.kt)("inlineCode",{parentName:"a"},"casper_contract"))," crate."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Important syntax elements used frequently in Rust:"),(0,o.kt)("ul",{parentName:"admonition"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/flow_control/match.html"},"Match"),(0,o.kt)("br",null)),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/primitives/array.html"},"Array"),(0,o.kt)("br",null)),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/flow_control/loop.html"},"Loop"),(0,o.kt)("br",null)),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/std/vec.html"},"Vectors"),(0,o.kt)("br",null)),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/rust-by-example/fn.html"},"Functions"),(0,o.kt)("br",null))),(0,o.kt)("p",{parentName:"admonition"},"To be able to comfortably write code in Rust it is crucial to understand these topics before going further into the examples.")),(0,o.kt)("h3",{id:"updating-the-mainrs-file"},"Updating the ",(0,o.kt)("inlineCode",{parentName:"h3"},"main.rs")," File"),(0,o.kt)("p",null,"To begin writing contract code, add the following file attributes to support the Wasm execution environment. If you still have an auto-generated ",(0,o.kt)("inlineCode",{parentName:"p"},"main.rs")," file, remove the auto-generated main function."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"#![no_std]\n#![no_main]\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"#![no_main]")," - This attribute tells the program not to use the standard main function as its entry point."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"#![no_std]")," - This attribute tells the program not to import the standard libraries.")),(0,o.kt)("h4",{id:"defining-required-dependencies"},"Defining required dependencies"),(0,o.kt)("p",null,"Add the required imports and dependencies. The example code for the counter contract declares the following dependencies."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"// This code imports necessary aspects of external crates that we will use in our contract code.\nextern crate alloc;\n\n// Importing Rust types.\nuse alloc::{\n string::{String, ToString},\n vec::Vec,\n};\n// Importing aspects of the Casper platform.\nuse casper_contract::{\n contract_api::{runtime, storage},\n unwrap_or_revert::UnwrapOrRevert,\n};\n// Importing specific Casper types.\nuse casper_types::{\n api_error::ApiError,\n contracts::{EntryPoint, EntryPointAccess, EntryPointType, EntryPoints, NamedKeys},\n CLType, CLValue, URef,\n};\n")),(0,o.kt)("h4",{id:"defining-the-global-constants"},"Defining the global constants"),(0,o.kt)("p",null,"After importing the necessary dependencies, you should define the constants used within the contract, including entry points and values. The following example outlines the necessary constants for the counter contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'// Creating constants for values within the contract package.\nconst CONTRACT_PACKAGE_NAME: &str = "counter_package_name";\nconst CONTRACT_ACCESS_UREF: &str = "counter_access_uref";\n\n// Creating constants for the various contract entry points.\nconst ENTRY_POINT_COUNTER_INC: &str = "counter_inc";\nconst ENTRY_POINT_COUNTER_GET: &str = "counter_get";\n\n// Creating constants for values within the contract.\nconst CONTRACT_VERSION_KEY: &str = "version";\nconst CONTRACT_KEY: &str = "counter";\nconst COUNT_KEY: &str = "count";\n')),(0,o.kt)("h4",{id:"defining-the-contract-entry-points"},"Defining the contract entry points"),(0,o.kt)("p",null,"Entry points provide access to contract code installed in global state. Either ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session code")," or another smart contract may call these entry points. A contract must have at least one entry point and may have more than one entry point. Entry points are defined by their name, and those names should be clear and self-describing. Each entry point is equivalent to a static main entry point in a traditional program."),(0,o.kt)("p",null,"Entry points are not functions or methods, and they have no arguments. They are static entry points into the contract's logic. Yet, the contract logic can access parameters by name, passed along with the Deploy. Note that another smart contract may access any of these entry points."),(0,o.kt)("p",null,"If an entry point has one or more mandatory parameters that will cause the logic to revert if they are not included, declare them within that entry point. Optional and non-critical parameters should be excluded."),(0,o.kt)("p",null,"When defining entry points, begin with a ",(0,o.kt)("inlineCode",{parentName:"p"},"#[no_mangle]")," line to ensure the system does not change critical syntax within the method names. Each entry point should contain the contract code that drives the action you wish it to accomplish. Finally, include any storage or return values needed, as applicable."),(0,o.kt)("p",null,"The following entry point is an example from the counter contract. To see all the available entry points, review the contract in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/contract-v1/src/main.rs"},"GitHub"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn counter_inc() {\n let uref: URef = runtime::get_key(COUNT_KEY)\n .unwrap_or_revert_with(ApiError::MissingKey)\n .into_uref()\n .unwrap_or_revert_with(ApiError::UnexpectedKeyVariant);\n storage::add(uref, 1); // Increment the count by 1.\n}\n')),(0,o.kt)("h4",{id:"defining-the-call-function"},"Defining the ",(0,o.kt)("inlineCode",{parentName:"h4"},"call")," function"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function starts the code execution and installs the contract on-chain. In some cases, it also initializes some constructs, such as a Dictionary for record-keeping or a purse. The following steps describe how to structure the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function. Review the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/8a622cd92d768893b9ef9fc2b150c674415be87e/contract-v1/src/main.rs#L55"},"call function")," in the counter contract."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Define the runtime arguments.")),(0,o.kt)("p",null,"At the time of contract installation, pass in parameters as runtime arguments. Use this pattern of variable definition to collect any sentinel values that dictate the behavior of the contract. If the entry point takes in arguments, you must declare those as part of the entry point's definition."),(0,o.kt)("p",null,"Look at the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep-78-enhanced-nft/blob/dev/contract/src/main.rs"},"CEP-78 contract")," to see examples of entry points taking in arguments. The counter contract does not use variable parameters since it is too simple."),(0,o.kt)("ol",{start:2},(0,o.kt)("li",{parentName:"ol"},"Add the entry points into the ",(0,o.kt)("inlineCode",{parentName:"li"},"call")," function.")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function replaces a traditional ",(0,o.kt)("inlineCode",{parentName:"p"},"main")," function and executes automatically when a caller interacts with the contract. Within the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function, we define entry points the caller can access using session code or another contract. When writing code that calls an entry point, there must be a one-to-one mapping of the entry point name. Otherwise, the execution engine will return an error that the entry point does not exist."),(0,o.kt)("p",null,"Each entry point should have these arguments:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"name")," - The entry point's name, which should be the same as the initial definition."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"arguments")," - A list of runtime arguments declared as part of the definition of the entry point."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"return type")," - The CLType returned by the entry point. Use the type ",(0,o.kt)("em",{parentName:"li"},"Unit")," for empty return types."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"access level")," - Access permissions of the entry point."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"entry point type")," - This can be ",(0,o.kt)("inlineCode",{parentName:"li"},"contract")," or ",(0,o.kt)("inlineCode",{parentName:"li"},"session")," code.")),(0,o.kt)("p",null,"This step adds the individual entry points to a ",(0,o.kt)("inlineCode",{parentName:"p"},"counter_entry_points")," object using the ",(0,o.kt)("inlineCode",{parentName:"p"},"add_entry_point")," method. This object will later be passed to the ",(0,o.kt)("inlineCode",{parentName:"p"},"new_contract")," method."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n // Initialize the count to 0 locally\n let count_start = storage::new_uref(0_i32);\n // Create the entry points for this contract\n let mut counter_entry_points = EntryPoints::new();\n\n counter_entry_points.add_entry_point(EntryPoint::new(\n ENTRY_POINT_COUNTER_GET,\n Vec::new(),\n CLType::I32,\n EntryPointAccess::Public,\n EntryPointType::Contract,\n ));\n\n counter_entry_points.add_entry_point(EntryPoint::new(\n ENTRY_POINT_COUNTER_INC,\n Vec::new(),\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract,\n ));\n}\n')),(0,o.kt)("p",null,"In the following, we will add more content to this call function."),(0,o.kt)("ol",{start:3},(0,o.kt)("li",{parentName:"ol"},"Create the contract's named keys.")),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.NamedKeys.html"},"NamedKeys")," are a collection of String-Key pairs used to identify some network data quickly."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("a",{parentName:"li",href:"https://doc.rust-lang.org/nightly/alloc/string/struct.String.html"},"String")," is the name given to identify the data"),(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-types/latest/casper_types/enum.Key.html"},"Key")," is the data to be referenced")),(0,o.kt)("p",null,"You can create named keys to store any record or value as needed, such as other accounts, smart contracts, URefs, transfers, deploy information, purse balances, etc. The list of possible Key variants can be found ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/enum.Key.html"},"here"),"."),(0,o.kt)("p",null,"For the counter, we store the integer that we increment into a named key."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"}," // In the named keys of the counter contract, add a key for the count.\n let mut counter_named_keys = NamedKeys::new();\n let key_name = String::from(COUNT_KEY);\n counter_named_keys.insert(key_name, count_start.into());\n")),(0,o.kt)("ol",{start:4},(0,o.kt)("li",{parentName:"ol"},"Create the contract.")),(0,o.kt)("p",null,"Use the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_contract.html"},"new_contract")," method to create the contract with its named keys and entry points. This method creates the contract object and saves the access URef and the contract package hash in the caller's context. The execution engine automatically creates a contract package and assigns it a ",(0,o.kt)("inlineCode",{parentName:"p"},"contractPackageHash"),". Then, it adds the contract to the package with a ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/struct.ContractHash.html"},(0,o.kt)("inlineCode",{parentName:"a"},"contractHash")),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"}," // Create a new contract package that can be upgraded.\n let (stored_contract_hash, contract_version) = storage::new_contract(\n counter_entry_points,\n Some(counter_named_keys),\n Some(CONTRACT_PACKAGE_NAME.to_string()),\n Some(CONTRACT_ACCESS_UREF.to_string()),\n );\n")),(0,o.kt)("p",null,"Usually, these contracts are upgradeable with the ability to add new ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.ContractVersion.html"},"versions"),". You ",(0,o.kt)("strong",{parentName:"p"},"must have the access URef")," to the contract package to add a new contract version. This can be accomplished by passing the ",(0,o.kt)("inlineCode",{parentName:"p"},"Some(CONTRACT_ACCESS_UREF.to_string())")," argument to the ",(0,o.kt)("inlineCode",{parentName:"p"},"new_contract")," method. To prevent any upgrades to a contract, use the ",(0,o.kt)("inlineCode",{parentName:"p"},"new_locked_contract")," method described ",(0,o.kt)("a",{parentName:"p",href:"#locked-contracts"},"below"),"."),(0,o.kt)("ol",{start:5},(0,o.kt)("li",{parentName:"ol"},"Create additional named keys.")),(0,o.kt)("p",null,"Generally, the ",(0,o.kt)("inlineCode",{parentName:"p"},"Contract_Hash")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"Contract_Version")," are saved as ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys")," in the account's context for later use."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"}," // Store the contract version in the context's named keys.\n let version_uref = storage::new_uref(contract_version);\n runtime::put_key(CONTRACT_VERSION_KEY, version_uref.into());\n\n // Create a named key for the contract hash.\n runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());\n")),(0,o.kt)("p",null,"The complete call function should look like this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n // Initialize the count to 0 locally\n let count_start = storage::new_uref(0_i32);\n // Create the entry points for this contract\n let mut counter_entry_points = EntryPoints::new();\n\n counter_entry_points.add_entry_point(EntryPoint::new(\n ENTRY_POINT_COUNTER_GET,\n Vec::new(),\n CLType::I32,\n EntryPointAccess::Public,\n EntryPointType::Contract,\n ));\n\n counter_entry_points.add_entry_point(EntryPoint::new(\n ENTRY_POINT_COUNTER_INC,\n Vec::new(),\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract,\n ));\n\n // In the named keys of the counter contract, add a key for the count.\n let mut counter_named_keys = NamedKeys::new();\n let key_name = String::from(COUNT_KEY);\n counter_named_keys.insert(key_name, count_start.into());\n\n // Create a new contract package that can be upgraded.\n let (stored_contract_hash, contract_version) = storage::new_contract(\n counter_entry_points,\n Some(counter_named_keys),\n Some(CONTRACT_PACKAGE_NAME.to_string()),\n Some(CONTRACT_ACCESS_UREF.to_string()),\n );\n\n /* To create a locked contract instead, use new_locked_contract and throw away the contract version returned\n let (stored_contract_hash, _) =\n storage::new_locked_contract(counter_entry_points, Some(counter_named_keys), None, None); */\n\n // Store the contract version in the context\'s named keys.\n let version_uref = storage::new_uref(contract_version);\n runtime::put_key(CONTRACT_VERSION_KEY, version_uref.into());\n\n // Create a named key for the contract hash.\n runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());\n}\n')),(0,o.kt)("h2",{id:"locked-contracts"},"Locked Contracts"),(0,o.kt)("p",null,"Locked contracts cannot contain other contract ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.ContractVersion.html"},"versions")," in the same contract package; thus, they cannot be upgraded. In this scenario, the Casper execution engine will create a contract package, add a contract to that package and prevent any further upgrades to the contract. Use locked contracts when you need to ensure high security and will not require updates to the contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn new_locked_contract(\n entry_points: EntryPoints,\n named_keys: Option,\n hash_name: Option,\n uref_name: Option,\n) -> (ContractHash, ContractVersion) {\n create_contract(entry_points, named_keys, hash_name, uref_name, true)\n}\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"entry_points")," - The set of entry points defined inside the smart contract."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"named_keys")," - Any ",(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-types/latest/casper_types/contracts/type.NamedKeys.html"},"named-key")," pairs for the contract."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"hash_name")," - Contract hash value. Puts ",(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-types/latest/casper_types/contracts/struct.ContractHash.html"},"contractHash")," in the current context's named keys under ",(0,o.kt)("inlineCode",{parentName:"li"},"hash_name"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"uref_name")," - Access URef value. Puts access_uref in the current context's named keys under ",(0,o.kt)("inlineCode",{parentName:"li"},"uref_name"),".")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Note"),": The current context is the context of the person who initiated the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function, usually an account."),(0,o.kt)("p",null,"The counter contract in our example would be locked if we created it this way:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"let (stored_contract_hash, _) =\n storage::new_locked_contract(counter_entry_points, Some(counter_named_keys), None, None);\n")),(0,o.kt)("h2",{id:"compiling-contract-code"},"Compiling Contract Code"),(0,o.kt)("p",null,"To compile the smart contract, run the following commands in the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract")," folder in your project's directory, where the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file and ",(0,o.kt)("inlineCode",{parentName:"p"},"src")," folder are hosted."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"rustup target add wasm32-unknown-unknown\ncargo build --release --target wasm32-unknown-unknown\n")),(0,o.kt)("p",null,"For the counter example, in the project directory where the ",(0,o.kt)("inlineCode",{parentName:"p"},"Makefile")," is, run the following commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"make prepare\nmake build-contract\n")),(0,o.kt)("h2",{id:"executing-contract-code"},"Executing Contract Code"),(0,o.kt)("p",null,"Contract execution must be initiated through an outside call, usually via ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session code")," or another smart contract. Developers should also be familiar with the difference between contract code and session code, explained in the next section."),(0,o.kt)("h2",{id:"video-walkthrough"},"Video Walkthrough"),(0,o.kt)("p",null,"The following brief video accompanies this guide."),(0,o.kt)("p",{align:"center"},(0,o.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed/yHJwkhO5EQg",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,o.kt)("h2",{id:"whats-next"},"What's Next?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Learn to ",(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/testing-contracts"},"test your contract"),"."),(0,o.kt)("li",{parentName:"ul"},"Understand ",(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session code")," and how it triggers a smart contract."),(0,o.kt)("li",{parentName:"ul"},"Learn to ",(0,o.kt)("a",{parentName:"li",href:"/developers/cli/installing-contracts"},"install a contract and query global state")," with the Casper command-line client.")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/401abd7a.f21f56e0.js b/assets/js/401abd7a.f21f56e0.js new file mode 100644 index 0000000000..e2290f5c40 --- /dev/null +++ b/assets/js/401abd7a.f21f56e0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6661],{3905:function(e,t,r){r.d(t,{Zo:function(){return u},kt:function(){return k}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var d=n.createContext({}),p=function(e){var t=n.useContext(d),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(d.Provider,{value:t},e.children)},s="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,l=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),s=p(r),m=a,k=s["".concat(d,".").concat(m)]||s[m]||c[m]||l;return r?n.createElement(k,o(o({ref:t},u),{},{components:r})):n.createElement(k,o({ref:t},u))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=r.length,o=new Array(l);o[0]=m;var i={};for(var d in t)hasOwnProperty.call(t,d)&&(i[d]=t[d]);i.originalType=e,i[s]="string"==typeof e?e:a,o[1]=i;for(var p=2;pParams",id:"invalid-params",level:2}],c={toc:s},m="wrapper";function k(e){var t=e.components,r=(0,a.Z)(e,o);return(0,l.kt)(m,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"casper-json-rpc-error-codes"},"Casper JSON-RPC Error Codes"),(0,l.kt)("p",null,"The following document expands on custom error codes provided by ",(0,l.kt)("inlineCode",{parentName:"p"},"casper-json-rpc")," crate."),(0,l.kt)("h2",{id:"codes"},"Error Codes"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Code"),(0,l.kt)("th",{parentName:"tr",align:null},"Error"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-1"),(0,l.kt)("td",{parentName:"tr",align:null},"NoSuchDeploy"),(0,l.kt)("td",{parentName:"tr",align:null},"The requested Deploy was not found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-2"),(0,l.kt)("td",{parentName:"tr",align:null},"NoSuchBlock"),(0,l.kt)("td",{parentName:"tr",align:null},"The requested Block was not found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-3"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToParseQueryKey"),(0,l.kt)("td",{parentName:"tr",align:null},"Parsing the Key from a query failed.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-4"),(0,l.kt)("td",{parentName:"tr",align:null},"QueryFailed"),(0,l.kt)("td",{parentName:"tr",align:null},"The query failed to find a result.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-5"),(0,l.kt)("td",{parentName:"tr",align:null},"QueryFailedToExecute"),(0,l.kt)("td",{parentName:"tr",align:null},"Executing the query failed.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-6"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToParseGetBalanceURef"),(0,l.kt)("td",{parentName:"tr",align:null},"Parsing the URef while getting a balance failed.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-7"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToGetBalance"),(0,l.kt)("td",{parentName:"tr",align:null},"Failed to get the requested balance.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-8"),(0,l.kt)("td",{parentName:"tr",align:null},"GetBalanceFailedToExecute"),(0,l.kt)("td",{parentName:"tr",align:null},"Executing the query to retrieve the balance failed.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-9"),(0,l.kt)("td",{parentName:"tr",align:null},"InvalidDeploy"),(0,l.kt)("td",{parentName:"tr",align:null},"The given Deploy cannot be executed as it is invalid.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-10"),(0,l.kt)("td",{parentName:"tr",align:null},"NoSuchAccount"),(0,l.kt)("td",{parentName:"tr",align:null},"The given account was not found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-11"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToGetDictionaryURef"),(0,l.kt)("td",{parentName:"tr",align:null},"Failed to get the requested dictionary URef.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-12"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToGetTrie"),(0,l.kt)("td",{parentName:"tr",align:null},"Failed to get the requested dictionary trie.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-13"),(0,l.kt)("td",{parentName:"tr",align:null},"NoSuchStateRoot"),(0,l.kt)("td",{parentName:"tr",align:null},"The requested state root hash was not found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32600"),(0,l.kt)("td",{parentName:"tr",align:null},"InvalidRequest"),(0,l.kt)("td",{parentName:"tr",align:null},"The JSON sent is not a valid Request object.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32601"),(0,l.kt)("td",{parentName:"tr",align:null},"MethodNotFound"),(0,l.kt)("td",{parentName:"tr",align:null},"The method does not exist or is not available.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32602"),(0,l.kt)("td",{parentName:"tr",align:null},"InvalidParams"),(0,l.kt)("td",{parentName:"tr",align:null},"Invalid method parameter(s)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32603"),(0,l.kt)("td",{parentName:"tr",align:null},"InternalError"),(0,l.kt)("td",{parentName:"tr",align:null},"Internal JSON-RPC error.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32700"),(0,l.kt)("td",{parentName:"tr",align:null},"ParseError"),(0,l.kt)("td",{parentName:"tr",align:null},"Invalid JSON was received by the server.")))),(0,l.kt)("h2",{id:"invalid-params"},"Invalid ",(0,l.kt)("inlineCode",{parentName:"h2"},"Params")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"casper-json-rpc")," no longer ignores invalid ",(0,l.kt)("inlineCode",{parentName:"p"},"params")," fields. ",(0,l.kt)("inlineCode",{parentName:"p"},"Params")," fields to be omitted should be an empty Array '[]', an empty Object '{}' or absent."),(0,l.kt)("p",null,"Failing to adhere to this will result in an ",(0,l.kt)("inlineCode",{parentName:"p"},"InvalidParams")," error."))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/401abd7a.f39345fb.js b/assets/js/401abd7a.f39345fb.js deleted file mode 100644 index 3f95406e4c..0000000000 --- a/assets/js/401abd7a.f39345fb.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6661],{3905:function(e,t,r){r.d(t,{Zo:function(){return u},kt:function(){return k}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var d=n.createContext({}),p=function(e){var t=n.useContext(d),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(d.Provider,{value:t},e.children)},s="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,l=e.originalType,d=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),s=p(r),m=a,k=s["".concat(d,".").concat(m)]||s[m]||c[m]||l;return r?n.createElement(k,o(o({ref:t},u),{},{components:r})):n.createElement(k,o({ref:t},u))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=r.length,o=new Array(l);o[0]=m;var i={};for(var d in t)hasOwnProperty.call(t,d)&&(i[d]=t[d]);i.originalType=e,i[s]="string"==typeof e?e:a,o[1]=i;for(var p=2;pParams",id:"invalid-params",level:2}],c={toc:s},m="wrapper";function k(e){var t=e.components,r=(0,a.Z)(e,o);return(0,l.kt)(m,(0,n.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"casper-json-rpc-error-codes"},"Casper JSON-RPC Error Codes"),(0,l.kt)("p",null,"The following document expands on custom error codes provided by ",(0,l.kt)("inlineCode",{parentName:"p"},"casper-json-rpc")," crate."),(0,l.kt)("h2",{id:"codes"},"Error Codes"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Code"),(0,l.kt)("th",{parentName:"tr",align:null},"Error"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-1"),(0,l.kt)("td",{parentName:"tr",align:null},"NoSuchDeploy"),(0,l.kt)("td",{parentName:"tr",align:null},"The requested Deploy was not found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-2"),(0,l.kt)("td",{parentName:"tr",align:null},"NoSuchBlock"),(0,l.kt)("td",{parentName:"tr",align:null},"The requested Block was not found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-3"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToParseQueryKey"),(0,l.kt)("td",{parentName:"tr",align:null},"Parsing the Key from a query failed.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-4"),(0,l.kt)("td",{parentName:"tr",align:null},"QueryFailed"),(0,l.kt)("td",{parentName:"tr",align:null},"The query failed to find a result.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-5"),(0,l.kt)("td",{parentName:"tr",align:null},"QueryFailedToExecute"),(0,l.kt)("td",{parentName:"tr",align:null},"Executing the query failed.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-6"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToParseGetBalanceURef"),(0,l.kt)("td",{parentName:"tr",align:null},"Parsing the URef while getting a balance failed.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-7"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToGetBalance"),(0,l.kt)("td",{parentName:"tr",align:null},"Failed to get the requested balance.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-8"),(0,l.kt)("td",{parentName:"tr",align:null},"GetBalanceFailedToExecute"),(0,l.kt)("td",{parentName:"tr",align:null},"Executing the query to retrieve the balance failed.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-9"),(0,l.kt)("td",{parentName:"tr",align:null},"InvalidDeploy"),(0,l.kt)("td",{parentName:"tr",align:null},"The given Deploy cannot be executed as it is invalid.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-10"),(0,l.kt)("td",{parentName:"tr",align:null},"NoSuchAccount"),(0,l.kt)("td",{parentName:"tr",align:null},"The given account was not found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-11"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToGetDictionaryURef"),(0,l.kt)("td",{parentName:"tr",align:null},"Failed to get the requested dictionary URef.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-12"),(0,l.kt)("td",{parentName:"tr",align:null},"FailedToGetTrie"),(0,l.kt)("td",{parentName:"tr",align:null},"Failed to get the requested dictionary trie.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-13"),(0,l.kt)("td",{parentName:"tr",align:null},"NoSuchStateRoot"),(0,l.kt)("td",{parentName:"tr",align:null},"The requested state root hash was not found.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32600"),(0,l.kt)("td",{parentName:"tr",align:null},"InvalidRequest"),(0,l.kt)("td",{parentName:"tr",align:null},"The JSON sent is not a valid Request object.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32601"),(0,l.kt)("td",{parentName:"tr",align:null},"MethodNotFound"),(0,l.kt)("td",{parentName:"tr",align:null},"The method does not exist or is not available.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32602"),(0,l.kt)("td",{parentName:"tr",align:null},"InvalidParams"),(0,l.kt)("td",{parentName:"tr",align:null},"Invalid method parameter(s)")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32603"),(0,l.kt)("td",{parentName:"tr",align:null},"InternalError"),(0,l.kt)("td",{parentName:"tr",align:null},"Internal JSON-RPC error.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"-32700"),(0,l.kt)("td",{parentName:"tr",align:null},"ParseError"),(0,l.kt)("td",{parentName:"tr",align:null},"Invalid JSON was received by the server.")))),(0,l.kt)("h2",{id:"invalid-params"},"Invalid ",(0,l.kt)("inlineCode",{parentName:"h2"},"Params")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"casper-json-rpc")," no longer ignores invalid ",(0,l.kt)("inlineCode",{parentName:"p"},"params")," fields. ",(0,l.kt)("inlineCode",{parentName:"p"},"Params")," fields to be omitted should be an empty Array '[]', an empty Object '{}' or absent."),(0,l.kt)("p",null,"Failing to adhere to this will result in an ",(0,l.kt)("inlineCode",{parentName:"p"},"InvalidParams")," error."))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/41afe816.5118bf09.js b/assets/js/41afe816.5118bf09.js deleted file mode 100644 index 4f9f074ed7..0000000000 --- a/assets/js/41afe816.5118bf09.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3457],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return y}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function p(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var p=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var o=r.createContext({}),s=function(e){var t=r.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(o.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,p=e.originalType,o=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,y=u["".concat(o,".").concat(m)]||u[m]||d[m]||p;return n?r.createElement(y,i(i({ref:t},c),{},{components:n})):r.createElement(y,i({ref:t},c))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var p=n.length,i=new Array(p);i[0]=m;var l={};for(var o in t)hasOwnProperty.call(t,o)&&(l[o]=t[o]);l.originalType=e,l[u]="string"==typeof e?e:a,i[1]=l;for(var s=2;s")," and also holds the CLType of the underlying data as a separate member. The ",(0,p.kt)("inlineCode",{parentName:"p"},"parsed")," field, representing the original value, is a convenience only available when a CLValue is encoded to JSON, and can always be set to null if preferred."),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},(0,p.kt)("inlineCode",{parentName:"p"},"bytes")," A Casper serialized representation of the underlying value. For more information, reference the ",(0,p.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"Serialization Standard"),".")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},(0,p.kt)("a",{parentName:"p",href:"#cltype"},(0,p.kt)("inlineCode",{parentName:"a"},"cl_type"))))))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/41afe816.519480b3.js b/assets/js/41afe816.519480b3.js new file mode 100644 index 0000000000..6d7db25298 --- /dev/null +++ b/assets/js/41afe816.519480b3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3457],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return y}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function p(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var p=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var o=r.createContext({}),s=function(e){var t=r.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(o.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,p=e.originalType,o=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,y=u["".concat(o,".").concat(m)]||u[m]||d[m]||p;return n?r.createElement(y,i(i({ref:t},c),{},{components:n})):r.createElement(y,i({ref:t},c))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var p=n.length,i=new Array(p);i[0]=m;var l={};for(var o in t)hasOwnProperty.call(t,o)&&(l[o]=t[o]);l.originalType=e,l[u]="string"==typeof e?e:a,i[1]=l;for(var s=2;s")," and also holds the CLType of the underlying data as a separate member. The ",(0,p.kt)("inlineCode",{parentName:"p"},"parsed")," field, representing the original value, is a convenience only available when a CLValue is encoded to JSON, and can always be set to null if preferred."),(0,p.kt)("ul",null,(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},(0,p.kt)("inlineCode",{parentName:"p"},"bytes")," A Casper serialized representation of the underlying value. For more information, reference the ",(0,p.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"Serialization Standard"),".")),(0,p.kt)("li",{parentName:"ul"},(0,p.kt)("p",{parentName:"li"},(0,p.kt)("a",{parentName:"p",href:"#cltype"},(0,p.kt)("inlineCode",{parentName:"a"},"cl_type"))))))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4636fedf.b2a570c8.js b/assets/js/4636fedf.b2a570c8.js new file mode 100644 index 0000000000..58a328720e --- /dev/null +++ b/assets/js/4636fedf.b2a570c8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8032],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return h}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),m=l(n),d=a,h=m["".concat(c,".").concat(d)]||m[d]||u[d]||o;return n?r.createElement(h,s(s({ref:t},p),{},{components:n})):r.createElement(h,s({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=d;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[m]="string"==typeof e?e:a,s[1]=i;for(var l=2;l new WebAssembly.Instance(compiled, imports).exports,\n});\n')),(0,o.kt)("p",null,"Next, create a directory called ",(0,o.kt)("inlineCode",{parentName:"p"},"assembly"),", and in that directory, create a file called ",(0,o.kt)("inlineCode",{parentName:"p"},"tsconfig.json")," in the following way:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "extends": "../node_modules/assemblyscript/std/assembly.json",\n "include": ["./**/*.ts"]\n}\n')),(0,o.kt)("h3",{id:"sample-smart-contract"},"Sample Smart Contract"),(0,o.kt)("p",null,"In the ",(0,o.kt)("inlineCode",{parentName:"p"},"assembly")," directory, also create an ",(0,o.kt)("inlineCode",{parentName:"p"},"index.ts")," file, where the code for the contract needs to go."),(0,o.kt)("p",null,"You can use the following sample snippet, which demonstrates a simple smart contract that immediately returns an error and writes a message to a block when executed on a Casper network."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},'//@ts-nocheck\nimport { Error, ErrorCode } from "casper-contract/error";\n\n// simplest possible feedback loop\nexport function call(): void {\n Error.fromErrorCode(ErrorCode.None).revert(); // ErrorCode: 1\n}\n')),(0,o.kt)("p",null,"If you prefer a more complicated first contract, you can look at example contracts on the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem"},"Casper Ecosystem GitHub")," repository for inspiration."),(0,o.kt)("h3",{id:"compile-to-wasm"},"Compile to Wasm"),(0,o.kt)("p",null,"To compile the contract to Wasm, use ",(0,o.kt)("em",{parentName:"p"},"npm")," to run the ",(0,o.kt)("em",{parentName:"p"},"asbuild")," script from the project root:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"npm run asbuild\n")),(0,o.kt)("p",null,"If the build is successful, there will be a ",(0,o.kt)("inlineCode",{parentName:"p"},"dist")," folder in the ",(0,o.kt)("inlineCode",{parentName:"p"},"root")," folder and in it should be ",(0,o.kt)("inlineCode",{parentName:"p"},"your-contract-name.wasm"),"."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4636fedf.f9d193a0.js b/assets/js/4636fedf.f9d193a0.js deleted file mode 100644 index 6a538f3886..0000000000 --- a/assets/js/4636fedf.f9d193a0.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8032],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return h}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),m=l(n),d=a,h=m["".concat(c,".").concat(d)]||m[d]||u[d]||o;return n?r.createElement(h,s(s({ref:t},p),{},{components:n})):r.createElement(h,s({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=d;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[m]="string"==typeof e?e:a,s[1]=i;for(var l=2;l new WebAssembly.Instance(compiled, imports).exports,\n});\n')),(0,o.kt)("p",null,"Next, create a directory called ",(0,o.kt)("inlineCode",{parentName:"p"},"assembly"),", and in that directory, create a file called ",(0,o.kt)("inlineCode",{parentName:"p"},"tsconfig.json")," in the following way:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "extends": "../node_modules/assemblyscript/std/assembly.json",\n "include": ["./**/*.ts"]\n}\n')),(0,o.kt)("h3",{id:"sample-smart-contract"},"Sample Smart Contract"),(0,o.kt)("p",null,"In the ",(0,o.kt)("inlineCode",{parentName:"p"},"assembly")," directory, also create an ",(0,o.kt)("inlineCode",{parentName:"p"},"index.ts")," file, where the code for the contract needs to go."),(0,o.kt)("p",null,"You can use the following sample snippet, which demonstrates a simple smart contract that immediately returns an error and writes a message to a block when executed on a Casper network."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-typescript"},'//@ts-nocheck\nimport { Error, ErrorCode } from "casper-contract/error";\n\n// simplest possible feedback loop\nexport function call(): void {\n Error.fromErrorCode(ErrorCode.None).revert(); // ErrorCode: 1\n}\n')),(0,o.kt)("p",null,"If you prefer a more complicated first contract, you can look at example contracts on the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem"},"Casper Ecosystem GitHub")," repository for inspiration."),(0,o.kt)("h3",{id:"compile-to-wasm"},"Compile to Wasm"),(0,o.kt)("p",null,"To compile the contract to Wasm, use ",(0,o.kt)("em",{parentName:"p"},"npm")," to run the ",(0,o.kt)("em",{parentName:"p"},"asbuild")," script from the project root:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"npm run asbuild\n")),(0,o.kt)("p",null,"If the build is successful, there will be a ",(0,o.kt)("inlineCode",{parentName:"p"},"dist")," folder in the ",(0,o.kt)("inlineCode",{parentName:"p"},"root")," folder and in it should be ",(0,o.kt)("inlineCode",{parentName:"p"},"your-contract-name.wasm"),"."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/463fc8b8.1fe31a4c.js b/assets/js/463fc8b8.1fe31a4c.js new file mode 100644 index 0000000000..4c9caa1955 --- /dev/null +++ b/assets/js/463fc8b8.1fe31a4c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2807],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return f}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),i=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=i(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=i(n),h=r,f=d["".concat(l,".").concat(h)]||d[h]||p[h]||c;return n?a.createElement(f,o(o({ref:t},u),{},{components:n})):a.createElement(f,o({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,o=new Array(c);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var i=2;i: \\\n// This is the contract package hash, which can be found within the `NamedKeys` of the account that sent the installing deploy.\n--key hash-82bd86d2675b2dc44c19027fb7717a99db6fda5e0cad8d597f2495a9dbc9df7f \\\n// This is the most up to date state root hash, which can found by using the `get-state-root-hash` command in the Casper client.\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n")),(0,c.kt)("details",null,(0,c.kt)("summary",null,(0,c.kt)("b",null,"Casper client command without comments")),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -n http://: \\\n--key hash-82bd86d2675b2dc44c19027fb7717a99db6fda5e0cad8d597f2495a9dbc9df7f \\\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n"))),(0,c.kt)("p",null,"This will return the ",(0,c.kt)("inlineCode",{parentName:"p"},"Contract Package")," object:"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -1489823435760214673,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[2048 hex chars]",\n "stored_value": {\n "ContractPackage": {\n "access_key": "uref-8dac847ce0ae20f0156cf37dd233cc1d166fde8269fc9a393b0ea04174be1167-007",\n "disabled_versions": [],\n "groups": [],\n "versions": [\n {\n "contract_hash": "contract-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e",\n "contract_version": 1,\n "protocol_version_major": 1\n }\n ]\n }\n }\n }\n}\n')),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},"Note - In the ",(0,c.kt)("inlineCode",{parentName:"li"},"contract_hash")," field, the hash value represents the stored contract which we will invoke later.")),(0,c.kt)("h2",{id:"querying-the-utility-contract"},"Querying the Utility Contract"),(0,c.kt)("p",null,"In addition, there is a utility contract that invokes the various balance and allowance entry points of the main fungible token contract. Upon receiving the returned value, the utility contract will write the value to a URef called ",(0,c.kt)("inlineCode",{parentName:"p"},"result"),". You can find this URef in the ",(0,c.kt)("inlineCode",{parentName:"p"},"NamedKeys")," of the utility contract."),(0,c.kt)("p",null,"First, you will need to query the ",(0,c.kt)("inlineCode",{parentName:"p"},"cep18_test_contract")," hash found within the installing account's ",(0,c.kt)("inlineCode",{parentName:"p"},"NamedKeys"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},"casper-client query-global-state -n http://: \\\n// This is the contract hash for the `cep18_test_contract` as found from the installing account's `NamedKeys`\n--key hash-015b99020edb40e7e1e2b31a8e104bc226242f960a2d10dc1d91ae3eb6fa41b6 \\\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n")),(0,c.kt)("details",null,(0,c.kt)("summary",null,(0,c.kt)("b",null,"Casper client command without comments")),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},"casper-client query-global-state -n http://: \\\n--key hash-015b99020edb40e7e1e2b31a8e104bc226242f960a2d10dc1d91ae3eb6fa41b6 \\\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n"))),(0,c.kt)("p",null,"Which should return information similar to the following:"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 5359405942597097786,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[2048 hex chars]",\n "stored_value": {\n "ContractPackage": {\n "access_key": "uref-1b867a3751f505762c69c8d92ba7462818cd0c2a705bb5d4270bce479410ee55-007",\n "disabled_versions": [],\n "groups": [],\n "versions": [\n {\n "contract_hash": "contract-a8fe057675930f0951d45816c55615228ac8af2b7b231788278dffcf1dd8c0ca",\n "contract_version": 1,\n "protocol_version_major": 1\n }\n ]\n }\n }\n }\n}\n\n')),(0,c.kt)("p",null,"You will need to take the ",(0,c.kt)("inlineCode",{parentName:"p"},"contract_hash")," value and replace ",(0,c.kt)("inlineCode",{parentName:"p"},"contract")," with ",(0,c.kt)("inlineCode",{parentName:"p"},"hash")," to run another `query-global-state:"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -n http://: \\\n--key hash-a8fe057675930f0951d45816c55615228ac8af2b7b231788278dffcf1dd8c0ca \\\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n")),(0,c.kt)("p",null,"Which will return the full ",(0,c.kt)("inlineCode",{parentName:"p"},"cep18_test_contract")," information. The following snippet is condensed to show only the ",(0,c.kt)("inlineCode",{parentName:"p"},"NamedKeys"),", but you should also see the ",(0,c.kt)("inlineCode",{parentName:"p"},"entry_points")," when you run the command. You should see the URef ",(0,c.kt)("inlineCode",{parentName:"p"},"result"),", which will be used to view the results of any checks run through the utility contract."),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -1426549275795832481,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[3370 hex chars]",\n "stored_value": {\n "Contract": {\n "contract_package_hash": "contract-package-015b99020edb40e7e1e2b31a8e104bc226242f960a2d10dc1d91ae3eb6fa41b6",\n "contract_wasm_hash": "contract-wasm-7959083a4df983ddcd3a9ae46af092dbf126031181ab2619ddc64db09bde8c27",\n "named_keys": [\n {\n "key": "uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007",\n "name": "result"\n }\n ],\n "protocol_version": "1.0.0"\n }\n }\n }\n}\n\n')),(0,c.kt)("h2",{id:"next-steps"},"Next Steps"),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/transfer"},"CEP-18 Token Transfers and Allowances"))))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/463fc8b8.f7eb6dea.js b/assets/js/463fc8b8.f7eb6dea.js deleted file mode 100644 index 2a04079133..0000000000 --- a/assets/js/463fc8b8.f7eb6dea.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2807],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return f}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),i=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=i(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,c=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=i(n),h=r,f=d["".concat(l,".").concat(h)]||d[h]||p[h]||c;return n?a.createElement(f,o(o({ref:t},u),{},{components:n})):a.createElement(f,o({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var c=n.length,o=new Array(c);o[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var i=2;i: \\\n// This is the contract package hash, which can be found within the `NamedKeys` of the account that sent the installing deploy.\n--key hash-82bd86d2675b2dc44c19027fb7717a99db6fda5e0cad8d597f2495a9dbc9df7f \\\n// This is the most up to date state root hash, which can found by using the `get-state-root-hash` command in the Casper client.\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n")),(0,c.kt)("details",null,(0,c.kt)("summary",null,(0,c.kt)("b",null,"Casper client command without comments")),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -n http://: \\\n--key hash-82bd86d2675b2dc44c19027fb7717a99db6fda5e0cad8d597f2495a9dbc9df7f \\\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n"))),(0,c.kt)("p",null,"This will return the ",(0,c.kt)("inlineCode",{parentName:"p"},"Contract Package")," object:"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -1489823435760214673,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[2048 hex chars]",\n "stored_value": {\n "ContractPackage": {\n "access_key": "uref-8dac847ce0ae20f0156cf37dd233cc1d166fde8269fc9a393b0ea04174be1167-007",\n "disabled_versions": [],\n "groups": [],\n "versions": [\n {\n "contract_hash": "contract-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e",\n "contract_version": 1,\n "protocol_version_major": 1\n }\n ]\n }\n }\n }\n}\n')),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},"Note - In the ",(0,c.kt)("inlineCode",{parentName:"li"},"contract_hash")," field, the hash value represents the stored contract which we will invoke later.")),(0,c.kt)("h2",{id:"querying-the-utility-contract"},"Querying the Utility Contract"),(0,c.kt)("p",null,"In addition, there is a utility contract that invokes the various balance and allowance entry points of the main fungible token contract. Upon receiving the returned value, the utility contract will write the value to a URef called ",(0,c.kt)("inlineCode",{parentName:"p"},"result"),". You can find this URef in the ",(0,c.kt)("inlineCode",{parentName:"p"},"NamedKeys")," of the utility contract."),(0,c.kt)("p",null,"First, you will need to query the ",(0,c.kt)("inlineCode",{parentName:"p"},"cep18_test_contract")," hash found within the installing account's ",(0,c.kt)("inlineCode",{parentName:"p"},"NamedKeys"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},"casper-client query-global-state -n http://: \\\n// This is the contract hash for the `cep18_test_contract` as found from the installing account's `NamedKeys`\n--key hash-015b99020edb40e7e1e2b31a8e104bc226242f960a2d10dc1d91ae3eb6fa41b6 \\\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n")),(0,c.kt)("details",null,(0,c.kt)("summary",null,(0,c.kt)("b",null,"Casper client command without comments")),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},"casper-client query-global-state -n http://: \\\n--key hash-015b99020edb40e7e1e2b31a8e104bc226242f960a2d10dc1d91ae3eb6fa41b6 \\\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n"))),(0,c.kt)("p",null,"Which should return information similar to the following:"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 5359405942597097786,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[2048 hex chars]",\n "stored_value": {\n "ContractPackage": {\n "access_key": "uref-1b867a3751f505762c69c8d92ba7462818cd0c2a705bb5d4270bce479410ee55-007",\n "disabled_versions": [],\n "groups": [],\n "versions": [\n {\n "contract_hash": "contract-a8fe057675930f0951d45816c55615228ac8af2b7b231788278dffcf1dd8c0ca",\n "contract_version": 1,\n "protocol_version_major": 1\n }\n ]\n }\n }\n }\n}\n\n')),(0,c.kt)("p",null,"You will need to take the ",(0,c.kt)("inlineCode",{parentName:"p"},"contract_hash")," value and replace ",(0,c.kt)("inlineCode",{parentName:"p"},"contract")," with ",(0,c.kt)("inlineCode",{parentName:"p"},"hash")," to run another `query-global-state:"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -n http://: \\\n--key hash-a8fe057675930f0951d45816c55615228ac8af2b7b231788278dffcf1dd8c0ca \\\n--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933\n")),(0,c.kt)("p",null,"Which will return the full ",(0,c.kt)("inlineCode",{parentName:"p"},"cep18_test_contract")," information. The following snippet is condensed to show only the ",(0,c.kt)("inlineCode",{parentName:"p"},"NamedKeys"),", but you should also see the ",(0,c.kt)("inlineCode",{parentName:"p"},"entry_points")," when you run the command. You should see the URef ",(0,c.kt)("inlineCode",{parentName:"p"},"result"),", which will be used to view the results of any checks run through the utility contract."),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -1426549275795832481,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[3370 hex chars]",\n "stored_value": {\n "Contract": {\n "contract_package_hash": "contract-package-015b99020edb40e7e1e2b31a8e104bc226242f960a2d10dc1d91ae3eb6fa41b6",\n "contract_wasm_hash": "contract-wasm-7959083a4df983ddcd3a9ae46af092dbf126031181ab2619ddc64db09bde8c27",\n "named_keys": [\n {\n "key": "uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007",\n "name": "result"\n }\n ],\n "protocol_version": "1.0.0"\n }\n }\n }\n}\n\n')),(0,c.kt)("h2",{id:"next-steps"},"Next Steps"),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/transfer"},"CEP-18 Token Transfers and Allowances"))))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/46ca92b5.4dcf13f1.js b/assets/js/46ca92b5.4dcf13f1.js new file mode 100644 index 0000000000..d77cceccd3 --- /dev/null +++ b/assets/js/46ca92b5.4dcf13f1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5814],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return f}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=s(n),d=a,f=c["".concat(p,".").concat(d)]||c[d]||m[d]||i;return n?r.createElement(f,o(o({ref:t},u),{},{components:n})):r.createElement(f,o({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var s=2;slimits.conf File",id:"updating-limits-conf",level:2}],m={toc:c},d="wrapper";function f(e){var t=e.components,n=(0,a.Z)(e,o);return(0,i.kt)(d,(0,r.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"setting-the-open-files-limit"},"Setting the Open Files Limit"),(0,i.kt)("p",null,"When the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," launches, it tries to set the maximum open files limit (",(0,i.kt)("inlineCode",{parentName:"p"},"nofile"),") for the process to ",(0,i.kt)("inlineCode",{parentName:"p"},"64000"),". With some systems, this limit will be larger than the default hard limit of ",(0,i.kt)("inlineCode",{parentName:"p"},"4096"),"."),(0,i.kt)("p",null,"The node software uses file handles for both files and network connections. Since network connections are unpredictable, running out of file handles can stop critical file writes from occurring. Therefore, the default ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," limit needs to be increased."),(0,i.kt)("p",null,"With the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," running, you can see what the system allocated by finding the process ID (PID) for the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," with the following command."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'pgrep "casper-node$"\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Sample output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'$ pgrep "casper-node$"\n275928\n')),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"This PID will change, so you need to run the above command to get the current version with your system. Also, it will not be ",(0,i.kt)("inlineCode",{parentName:"p"},"275928")," each time."))),(0,i.kt)("p",null,"If you do not get a value in return, you do not have the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," running correctly."),(0,i.kt)("p",null,"To find the current ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," (number of open files) hard limit, run ",(0,i.kt)("inlineCode",{parentName:"p"},"prlimit")," with the PID from the previous command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo prlimit -n -p \n")),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Sample output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"$ sudo prlimit -n -p 275928\nRESOURCE DESCRIPTION SOFT HARD UNITS\nNOFILE max number of open files 1024 4096 files\n"))),(0,i.kt)("p",null,"You can also embed both commands as shown here:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'sudo prlimit -n -p $(pgrep "casper-node$")\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Sample output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'$ sudo prlimit -n -p $(pgrep "casper-node$")\nRESOURCE DESCRIPTION SOFT HARD UNITS\nNOFILE max number of open files 1024 4096 files\n'))),(0,i.kt)("p",null,"If you receive ",(0,i.kt)("inlineCode",{parentName:"p"},"prlimit: option requires an argument -- 'p'"),", then ",(0,i.kt)("inlineCode",{parentName:"p"},'pgrep "casper-node$"')," is not returning anything because the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," is no longer running."),(0,i.kt)("h2",{id:"updating-manually"},"Setting the Limit Manually"),(0,i.kt)("p",null,"Run the command below to set the ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," limit for an active process without restarting the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," processes. Note that this setting is active only while the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," process runs. To make this setting permanent, ",(0,i.kt)("a",{parentName:"p",href:"#updating-limits-conf"},"update the ",(0,i.kt)("inlineCode",{parentName:"a"},"limits.conf"))," file instead."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'sudo prlimit --nofile=64000 --pid=$(pgrep "casper-node$")`\n')),(0,i.kt)("p",null,"Next, check that the ",(0,i.kt)("inlineCode",{parentName:"p"},"prlimit")," has changed:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'sudo prlimit -n -p $(pgrep "casper-node$")\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Sample output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'$ sudo prlimit -n -p $(pgrep "casper-node$")\nRESOURCE DESCRIPTION SOFT HARD UNITS\nNOFILE max number of open files 64000 64000 files\n'))),(0,i.kt)("h2",{id:"updating-limits-conf"},"Updating the ",(0,i.kt)("inlineCode",{parentName:"h2"},"limits.conf")," File"),(0,i.kt)("p",null,"It is possible to persist the ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," limit across server reboots, ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," restarts, and protocol upgrades, by adding the ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," setting for the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper")," user in ",(0,i.kt)("inlineCode",{parentName:"p"},"/etc/security/limits.conf"),"."),(0,i.kt)("p",null,"Add the following row to the bottom of the ",(0,i.kt)("inlineCode",{parentName:"p"},"/etc/security/limits.conf")," file:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"casper hard nofile 64000\n")),(0,i.kt)("p",null,"Afterward, log out of any shells to enable this change. Restarting the node should maintain the correct ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," setting."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/46ca92b5.8ec9abc4.js b/assets/js/46ca92b5.8ec9abc4.js deleted file mode 100644 index 26741ff8c5..0000000000 --- a/assets/js/46ca92b5.8ec9abc4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5814],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return f}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),s=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=s(n),d=a,f=c["".concat(p,".").concat(d)]||c[d]||m[d]||i;return n?r.createElement(f,o(o({ref:t},u),{},{components:n})):r.createElement(f,o({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var s=2;slimits.conf File",id:"updating-limits-conf",level:2}],m={toc:c},d="wrapper";function f(e){var t=e.components,n=(0,a.Z)(e,o);return(0,i.kt)(d,(0,r.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"setting-the-open-files-limit"},"Setting the Open Files Limit"),(0,i.kt)("p",null,"When the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," launches, it tries to set the maximum open files limit (",(0,i.kt)("inlineCode",{parentName:"p"},"nofile"),") for the process to ",(0,i.kt)("inlineCode",{parentName:"p"},"64000"),". With some systems, this limit will be larger than the default hard limit of ",(0,i.kt)("inlineCode",{parentName:"p"},"4096"),"."),(0,i.kt)("p",null,"The node software uses file handles for both files and network connections. Since network connections are unpredictable, running out of file handles can stop critical file writes from occurring. Therefore, the default ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," limit needs to be increased."),(0,i.kt)("p",null,"With the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," running, you can see what the system allocated by finding the process ID (PID) for the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," with the following command."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'pgrep "casper-node$"\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Sample output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'$ pgrep "casper-node$"\n275928\n')),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"This PID will change, so you need to run the above command to get the current version with your system. Also, it will not be ",(0,i.kt)("inlineCode",{parentName:"p"},"275928")," each time."))),(0,i.kt)("p",null,"If you do not get a value in return, you do not have the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," running correctly."),(0,i.kt)("p",null,"To find the current ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," (number of open files) hard limit, run ",(0,i.kt)("inlineCode",{parentName:"p"},"prlimit")," with the PID from the previous command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo prlimit -n -p \n")),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Sample output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"$ sudo prlimit -n -p 275928\nRESOURCE DESCRIPTION SOFT HARD UNITS\nNOFILE max number of open files 1024 4096 files\n"))),(0,i.kt)("p",null,"You can also embed both commands as shown here:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'sudo prlimit -n -p $(pgrep "casper-node$")\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Sample output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'$ sudo prlimit -n -p $(pgrep "casper-node$")\nRESOURCE DESCRIPTION SOFT HARD UNITS\nNOFILE max number of open files 1024 4096 files\n'))),(0,i.kt)("p",null,"If you receive ",(0,i.kt)("inlineCode",{parentName:"p"},"prlimit: option requires an argument -- 'p'"),", then ",(0,i.kt)("inlineCode",{parentName:"p"},'pgrep "casper-node$"')," is not returning anything because the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," is no longer running."),(0,i.kt)("h2",{id:"updating-manually"},"Setting the Limit Manually"),(0,i.kt)("p",null,"Run the command below to set the ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," limit for an active process without restarting the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," processes. Note that this setting is active only while the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node")," process runs. To make this setting permanent, ",(0,i.kt)("a",{parentName:"p",href:"#updating-limits-conf"},"update the ",(0,i.kt)("inlineCode",{parentName:"a"},"limits.conf"))," file instead."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'sudo prlimit --nofile=64000 --pid=$(pgrep "casper-node$")`\n')),(0,i.kt)("p",null,"Next, check that the ",(0,i.kt)("inlineCode",{parentName:"p"},"prlimit")," has changed:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'sudo prlimit -n -p $(pgrep "casper-node$")\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Sample output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'$ sudo prlimit -n -p $(pgrep "casper-node$")\nRESOURCE DESCRIPTION SOFT HARD UNITS\nNOFILE max number of open files 64000 64000 files\n'))),(0,i.kt)("h2",{id:"updating-limits-conf"},"Updating the ",(0,i.kt)("inlineCode",{parentName:"h2"},"limits.conf")," File"),(0,i.kt)("p",null,"It is possible to persist the ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," limit across server reboots, ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," restarts, and protocol upgrades, by adding the ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," setting for the ",(0,i.kt)("inlineCode",{parentName:"p"},"casper")," user in ",(0,i.kt)("inlineCode",{parentName:"p"},"/etc/security/limits.conf"),"."),(0,i.kt)("p",null,"Add the following row to the bottom of the ",(0,i.kt)("inlineCode",{parentName:"p"},"/etc/security/limits.conf")," file:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"casper hard nofile 64000\n")),(0,i.kt)("p",null,"Afterward, log out of any shells to enable this change. Restarting the node should maintain the correct ",(0,i.kt)("inlineCode",{parentName:"p"},"nofile")," setting."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/474a98da.3c5b93aa.js b/assets/js/474a98da.d53e36e3.js similarity index 55% rename from assets/js/474a98da.3c5b93aa.js rename to assets/js/474a98da.d53e36e3.js index fc552afe02..c7b6f2d6ae 100644 --- a/assets/js/474a98da.3c5b93aa.js +++ b/assets/js/474a98da.d53e36e3.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1918],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return h}});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),l=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(i.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,s=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=l(n),f=o,h=p["".concat(i,".").concat(f)]||p[f]||d[f]||s;return n?r.createElement(h,a(a({ref:t},u),{},{components:n})):r.createElement(h,a({ref:t},u))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var s=n.length,a=new Array(s);a[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var l=2;l=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),l=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(i.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,s=e.originalType,i=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=l(n),f=o,h=p["".concat(i,".").concat(f)]||p[f]||d[f]||s;return n?r.createElement(h,a(a({ref:t},u),{},{components:n})):r.createElement(h,a({ref:t},u))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var s=n.length,a=new Array(s);a[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=c(n),d=a,h=u["".concat(l,".").concat(d)]||u[d]||m[d]||o;return n?r.createElement(h,s(s({ref:t},p),{},{components:n})):r.createElement(h,s({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:a,s[1]=i;for(var c=2;c=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=c(n),d=a,h=u["".concat(l,".").concat(d)]||u[d]||m[d]||o;return n?r.createElement(h,s(s({ref:t},p),{},{components:n})):r.createElement(h,s({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:a,s[1]=i;for(var c=2;c=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=a.createContext({}),i=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=i(e.components);return a.createElement(c.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),h=i(n),d=o,m=h["".concat(c,".").concat(d)]||h[d]||p[d]||r;return n?a.createElement(m,l(l({ref:t},u),{},{components:n})):a.createElement(m,l({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,l=new Array(r);l[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[h]="string"==typeof e?e:o,l[1]=s;for(var i=2;i=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=a.createContext({}),i=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=i(e.components);return a.createElement(c.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),h=i(n),d=o,m=h["".concat(c,".").concat(d)]||h[d]||p[d]||r;return n?a.createElement(m,l(l({ref:t},u),{},{components:n})):a.createElement(m,l({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,l=new Array(r);l[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[h]="string"==typeof e?e:o,l[1]=s;for(var i=2;i=0||(a[r]=t[r]);return a}(t,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,r)&&(a[r]=t[r])}return a}var u=n.createContext({}),l=function(t){var e=n.useContext(u),r=e;return t&&(r="function"==typeof t?t(e):i(i({},e),t)),r},c=function(t){var e=l(t.components);return n.createElement(u.Provider,{value:e},t.children)},d="mdxType",p={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},m=n.forwardRef((function(t,e){var r=t.components,a=t.mdxType,o=t.originalType,u=t.parentName,c=s(t,["components","mdxType","originalType","parentName"]),d=l(r),m=a,f=d["".concat(u,".").concat(m)]||d[m]||p[m]||o;return r?n.createElement(f,i(i({ref:e},c),{},{components:r})):n.createElement(f,i({ref:e},c))}));function f(t,e){var r=arguments,a=e&&e.mdxType;if("string"==typeof t||a){var o=r.length,i=new Array(o);i[0]=m;var s={};for(var u in e)hasOwnProperty.call(e,u)&&(s[u]=e[u]);s.originalType=t,s[d]="string"==typeof t?t:a,i[1]=s;for(var l=2;l=0||(a[r]=t[r]);return a}(t,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,r)&&(a[r]=t[r])}return a}var u=n.createContext({}),l=function(t){var e=n.useContext(u),r=e;return t&&(r="function"==typeof t?t(e):i(i({},e),t)),r},c=function(t){var e=l(t.components);return n.createElement(u.Provider,{value:e},t.children)},d="mdxType",p={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},m=n.forwardRef((function(t,e){var r=t.components,a=t.mdxType,o=t.originalType,u=t.parentName,c=s(t,["components","mdxType","originalType","parentName"]),d=l(r),m=a,f=d["".concat(u,".").concat(m)]||d[m]||p[m]||o;return r?n.createElement(f,i(i({ref:e},c),{},{components:r})):n.createElement(f,i({ref:e},c))}));function f(t,e){var r=arguments,a=e&&e.mdxType;if("string"==typeof t||a){var o=r.length,i=new Array(o);i[0]=m;var s={};for(var u in e)hasOwnProperty.call(e,u)&&(s[u]=e[u]);s.originalType=t,s[d]="string"==typeof t?t:a,i[1]=s;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,h=p["".concat(c,".").concat(d)]||p[d]||m[d]||o;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,h=p["".concat(c,".").concat(d)]||p[d]||m[d]||o;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},g="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),g=u(n),d=r,m=g["".concat(s,".").concat(d)]||g[d]||p[d]||o;return n?a.createElement(m,i(i({ref:t},c),{},{components:n})):a.createElement(m,i({ref:t},c))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[g]="string"==typeof e?e:r,i[1]=l;for(var u=2;u=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},g="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),g=u(n),d=r,m=g["".concat(s,".").concat(d)]||g[d]||p[d]||o;return n?a.createElement(m,i(i({ref:t},c),{},{components:n})):a.createElement(m,i({ref:t},c))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[g]="string"==typeof e?e:r,i[1]=l;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),f=l(r),m=a,y=f["".concat(c,".").concat(m)]||f[m]||i[m]||o;return r?n.createElement(y,s(s({ref:t},u),{},{components:r})):n.createElement(y,s({ref:t},u))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=m;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[f]="string"==typeof e?e:a,s[1]=p;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),f=l(r),m=a,y=f["".concat(c,".").concat(m)]||f[m]||i[m]||o;return r?n.createElement(y,s(s({ref:t},u),{},{components:r})):n.createElement(y,s({ref:t},u))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=m;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[f]="string"==typeof e?e:a,s[1]=p;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(r),f=a,m=d["".concat(p,".").concat(f)]||d[f]||c[f]||o;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(r),f=a,m=d["".concat(p,".").concat(f)]||d[f]||c[f]||o;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var l=2;l=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=c(n),g=o,f=u["".concat(p,".").concat(g)]||u[g]||d[g]||a;return n?r.createElement(f,i(i({ref:t},l),{},{components:n})):r.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=g;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:o,i[1]=s;for(var c=2;c=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),c=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=c(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=c(n),g=o,f=u["".concat(p,".").concat(g)]||u[g]||d[g]||a;return n?r.createElement(f,i(i({ref:t},l),{},{components:n})):r.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=g;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:o,i[1]=s;for(var c=2;c=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),i=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},l=function(e){var t=i(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},k=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=p(e,["components","mdxType","originalType","parentName"]),u=i(n),k=a,m=u["".concat(c,".").concat(k)]||u[k]||d[k]||o;return n?r.createElement(m,s(s({ref:t},l),{},{components:n})):r.createElement(m,s({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=k;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[u]="string"==typeof e?e:a,s[1]=p;for(var i=2;i=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),i=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},l=function(e){var t=i(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},k=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,l=p(e,["components","mdxType","originalType","parentName"]),u=i(n),k=a,m=u["".concat(c,".").concat(k)]||u[k]||d[k]||o;return n?r.createElement(m,s(s({ref:t},l),{},{components:n})):r.createElement(m,s({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=k;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[u]="string"==typeof e?e:a,s[1]=p;for(var i=2;i=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var i=n.createContext({}),p=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(a),d=r,h=u["".concat(i,".").concat(d)]||u[d]||m[d]||o;return a?n.createElement(h,l(l({ref:t},c),{},{components:a})):n.createElement(h,l({ref:t},c))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,l=new Array(o);l[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:r,l[1]=s;for(var p=2;p=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var i=n.createContext({}),p=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=p(a),d=r,h=u["".concat(i,".").concat(d)]||u[d]||m[d]||o;return a?n.createElement(h,l(l({ref:t},c),{},{components:a})):n.createElement(h,l({ref:t},c))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,l=new Array(o);l[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:r,l[1]=s;for(var p=2;p=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),c=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=c(r),f=n,m=d["".concat(s,".").concat(f)]||d[f]||p[f]||o;return r?a.createElement(m,i(i({ref:t},u),{},{components:r})):a.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:n,i[1]=l;for(var c=2;c=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),c=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=c(r),f=n,m=d["".concat(s,".").concat(f)]||d[f]||p[f]||o;return r?a.createElement(m,i(i({ref:t},u),{},{components:r})):a.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:n,i[1]=l;for(var c=2;c=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var p=n.createContext({}),d=function(t){var e=n.useContext(p),a=e;return t&&(a="function"==typeof t?t(e):i(i({},e),t)),a},m=function(t){var e=d(t.components);return n.createElement(p.Provider,{value:e},t.children)},k="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},N=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,l=t.originalType,p=t.parentName,m=o(t,["components","mdxType","originalType","parentName"]),k=d(a),N=r,s=k["".concat(p,".").concat(N)]||k[N]||u[N]||l;return a?n.createElement(s,i(i({ref:e},m),{},{components:a})):n.createElement(s,i({ref:e},m))}));function s(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=a.length,i=new Array(l);i[0]=N;var o={};for(var p in e)hasOwnProperty.call(e,p)&&(o[p]=e[p]);o.originalType=t,o[k]="string"==typeof t?t:r,i[1]=o;for(var d=2;dBr_Table OpCode Costs",id:"br_table-opcode-costs",level:2},{value:"External Function Costs",id:"external-function-costs",level:2},{value:"Protocol Operating Costs",id:"protocol-operating-costs",level:2},{value:"Auction System Contract Costs",id:"auction-system-contract-costs",level:3},{value:"Mint System Contract Costs",id:"mint-system-contract-costs",level:3},{value:"Handle_Payment System Contract Costs",id:"handle_payment-system-contract-costs",level:3},{value:"Standard_Payment System Contract Costs",id:"standard_payment-system-contract-costs",level:3}],u={toc:k},N="wrapper";function s(t){var e=t.components,a=(0,r.Z)(t,i);return(0,l.kt)(N,(0,n.Z)({},u,a,{components:e,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"opcode-costs-tables"},"OpCode Costs Tables"),(0,l.kt)("p",null,"The following tables outline the cost, in motes, for a given operation on Casper's Mainnet. If you are building for a private network or other instance of Casper, you will need to verify these costs in the associated ",(0,l.kt)("inlineCode",{parentName:"p"},"chainspec.toml"),"."),(0,l.kt)("p",null,"More information on ",(0,l.kt)("inlineCode",{parentName:"p"},"chainspec"),"s for private networks can be found ",(0,l.kt)("a",{parentName:"p",href:"/operators/setup-network/chain-spec"},"here")),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("p",{parentName:"admonition"},"All costs in this table are in ",(0,l.kt)("a",{parentName:"p",href:"/concepts/glossary/M/#motes"},"motes"),", not CSPR, and the corresponding chainspec is ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/53dd33865c2707c29284ccc0e8485f22ddd6fbe3/resources/production/chainspec.toml#L129"},"here"),".")),(0,l.kt)("h2",{id:"storage-costs"},"Storage Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"gas_per_byte"),(0,l.kt)("td",{parentName:"tr",align:null},"Gas charged per byte stored in global state."),(0,l.kt)("td",{parentName:"tr",align:null},"630,000")))),(0,l.kt)("h2",{id:"opcode-costs"},"OpCode Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"bit"),(0,l.kt)("td",{parentName:"tr",align:null},"Bit operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"300")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add"),(0,l.kt)("td",{parentName:"tr",align:null},"Arithmetic add operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"210")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mul"),(0,l.kt)("td",{parentName:"tr",align:null},"Mul operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"240")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"div"),(0,l.kt)("td",{parentName:"tr",align:null},"Div operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"320")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"load"),(0,l.kt)("td",{parentName:"tr",align:null},"Memory load operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"store"),(0,l.kt)("td",{parentName:"tr",align:null},"Memory store operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"4,700")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"const"),(0,l.kt)("td",{parentName:"tr",align:null},"Const store operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"110")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"local"),(0,l.kt)("td",{parentName:"tr",align:null},"Local operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"390")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"global"),(0,l.kt)("td",{parentName:"tr",align:null},"Global operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"390")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"integer_comparison"),(0,l.kt)("td",{parentName:"tr",align:null},"Integer operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"250")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"conversion"),(0,l.kt)("td",{parentName:"tr",align:null},"Conversion operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"420")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"unreachable"),(0,l.kt)("td",{parentName:"tr",align:null},"Unreachable operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"270")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"nop"),(0,l.kt)("td",{parentName:"tr",align:null},"Nop operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"200")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"current_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Get the current memory operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"290")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"grow_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Grow memory cost per page (64 kB)."),(0,l.kt)("td",{parentName:"tr",align:null},"240,000")))),(0,l.kt)("h2",{id:"control-flow-operation-costs"},"Control Flow Operation Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"block")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"loop"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"loop")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"if"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"if")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"else"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"else")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"end"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"end")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"br"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"br")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"br_if"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"br_if")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"return"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"return")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"select"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"select")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"call")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"68_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call_indirect"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"call_indirect")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"68,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"drop"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"drop")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")))),(0,l.kt)("h2",{id:"br_table-opcode-costs"},(0,l.kt)("inlineCode",{parentName:"h2"},"Br_Table")," OpCode Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"cost"),(0,l.kt)("td",{parentName:"tr",align:null},"Fixed cost per ",(0,l.kt)("inlineCode",{parentName:"td"},"br_table")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"size_multiplier"),(0,l.kt)("td",{parentName:"tr",align:null},"Size of target labels in the ",(0,l.kt)("inlineCode",{parentName:"td"},"br_table")," opcode will be multiplied by ",(0,l.kt)("inlineCode",{parentName:"td"},"size_multiplier"),"."),(0,l.kt)("td",{parentName:"tr",align:null},"100")))),(0,l.kt)("h2",{id:"external-function-costs"},"External Function Costs"),(0,l.kt)("p",null,'The following costs are for low-level bindings for host-side ("external") functions. More information on the Casper external FFI can be found ',(0,l.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/ext_ffi/index.html"},"here"),"."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Host-Side Function"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"),(0,l.kt)("th",{parentName:"tr",align:null},"Arguments"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add"),(0,l.kt)("td",{parentName:"tr",align:null},"5,800"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add_associated_key"),(0,l.kt)("td",{parentName:"tr",align:null},"9,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add_contract_version"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"blake2b"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call_contract"),(0,l.kt)("td",{parentName:"tr",align:null},"4,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 420, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call_versioned_contract"),(0,l.kt)("td",{parentName:"tr",align:null},"4,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 420, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create_contract_package_at_hash"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create_contract_user_group"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"disable_contract_version"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_balance"),(0,l.kt)("td",{parentName:"tr",align:null},"3,800"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_blocktime"),(0,l.kt)("td",{parentName:"tr",align:null},"330"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_caller"),(0,l.kt)("td",{parentName:"tr",align:null},"380"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_key"),(0,l.kt)("td",{parentName:"tr",align:null},"2,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 440, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_main_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"1,300"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_named_arg"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_named_arg_size"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_phase"),(0,l.kt)("td",{parentName:"tr",align:null},"710"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_system_contract"),(0,l.kt)("td",{parentName:"tr",align:null},"1,100"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"has_key"),(0,l.kt)("td",{parentName:"tr",align:null},"1,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 840]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"is_valid_uref"),(0,l.kt)("td",{parentName:"tr",align:null},"760"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"load_named_keys"),(0,l.kt)("td",{parentName:"tr",align:null},"42,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"new_uref"),(0,l.kt)("td",{parentName:"tr",align:null},"17,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 590]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"random_bytes"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"print"),(0,l.kt)("td",{parentName:"tr",align:null},"20,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 4,600]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"provision_contract_user_group_uref"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"put_key"),(0,l.kt)("td",{parentName:"tr",align:null},"38,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 1,100, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_host_buffer"),(0,l.kt)("td",{parentName:"tr",align:null},"3,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 310, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_value"),(0,l.kt)("td",{parentName:"tr",align:null},"6,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_value_local"),(0,l.kt)("td",{parentName:"tr",align:null},"5,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 590, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"remove_associated_key"),(0,l.kt)("td",{parentName:"tr",align:null},"4,200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"remove_contract_user_group"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"remove_contract_user_group_urefs"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"remove_key"),(0,l.kt)("td",{parentName:"tr",align:null},"61,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 3,200]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"ret"),(0,l.kt)("td",{parentName:"tr",align:null},"23,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 420,000]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"revert"),(0,l.kt)("td",{parentName:"tr",align:null},"500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"set_action_threshold"),(0,l.kt)("td",{parentName:"tr",align:null},"74,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer_from_purse_to_account"),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer_from_purse_to_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"82,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer_to_account"),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"update_associated_key"),(0,l.kt)("td",{parentName:"tr",align:null},"4,200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"write"),(0,l.kt)("td",{parentName:"tr",align:null},"14,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 980]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"write_local"),(0,l.kt)("td",{parentName:"tr",align:null},"9,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 1,800, 0, 520]")))),(0,l.kt)("h2",{id:"protocol-operating-costs"},"Protocol Operating Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"wasmless_transfer_cost"),(0,l.kt)("td",{parentName:"tr",align:null},"Default gas cost for a wasmless transfer."),(0,l.kt)("td",{parentName:"tr",align:null},"100,000,000")))),(0,l.kt)("h3",{id:"auction-system-contract-costs"},(0,l.kt)("inlineCode",{parentName:"h3"},"Auction")," System Contract Costs"),(0,l.kt)("p",null,"These are the costs of calling ",(0,l.kt)("inlineCode",{parentName:"p"},"auction")," system contract entrypoints."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Entrypoint"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_era_validators"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_era_validators")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_seigniorage_recipients"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_seigniorage_recipients")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"add_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"delegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"delegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"undelegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"undelegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"run_auction"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"run_auction")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"slash"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"slash")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"distribute"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"distribute")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_delegator_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_delegator_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_validator_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_validator_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_era_id"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_era_id")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"activate_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"activate_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"redelegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"redelegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")))),(0,l.kt)("h3",{id:"mint-system-contract-costs"},(0,l.kt)("inlineCode",{parentName:"h3"},"Mint")," System Contract Costs"),(0,l.kt)("p",null,"These are the costs of calling ",(0,l.kt)("inlineCode",{parentName:"p"},"mint")," system contract entrypoints."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Entrypoint"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mint"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"mint")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"reduce_total_supply"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"reduce_total_supply")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"create")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"balance"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"balance")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"transfer")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_base_round_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_base_round_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mint_into_existing_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"mint_into_existing_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")))),(0,l.kt)("h3",{id:"handle_payment-system-contract-costs"},(0,l.kt)("inlineCode",{parentName:"h3"},"Handle_Payment")," System Contract Costs"),(0,l.kt)("p",null,"These are the costs of calling entrypoints on the ",(0,l.kt)("inlineCode",{parentName:"p"},"handle_payment")," system contract."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Entrypoint"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_payment_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_payment_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"set_refund_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"set_refund_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_refund_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_refund_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"finalize_payment"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"finalize_payment")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")))),(0,l.kt)("h3",{id:"standard_payment-system-contract-costs"},(0,l.kt)("inlineCode",{parentName:"h3"},"Standard_Payment")," System Contract Costs"),(0,l.kt)("p",null,"These settings manage the costs of calling entrypoints on the ",(0,l.kt)("inlineCode",{parentName:"p"},"standard_payment")," system contract."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Entrypoint"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"pay"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"pay")," entrypoint and sending an amount to a payment purse."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")))))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5c6c4a57.8779d977.js b/assets/js/5c6c4a57.8779d977.js deleted file mode 100644 index ddbad8c229..0000000000 --- a/assets/js/5c6c4a57.8779d977.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2570],{3905:function(t,e,a){a.d(e,{Zo:function(){return m},kt:function(){return s}});var n=a(7294);function r(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function l(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function i(t){for(var e=1;e=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var p=n.createContext({}),d=function(t){var e=n.useContext(p),a=e;return t&&(a="function"==typeof t?t(e):i(i({},e),t)),a},m=function(t){var e=d(t.components);return n.createElement(p.Provider,{value:e},t.children)},k="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},N=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,l=t.originalType,p=t.parentName,m=o(t,["components","mdxType","originalType","parentName"]),k=d(a),N=r,s=k["".concat(p,".").concat(N)]||k[N]||u[N]||l;return a?n.createElement(s,i(i({ref:e},m),{},{components:a})):n.createElement(s,i({ref:e},m))}));function s(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=a.length,i=new Array(l);i[0]=N;var o={};for(var p in e)hasOwnProperty.call(e,p)&&(o[p]=e[p]);o.originalType=t,o[k]="string"==typeof t?t:r,i[1]=o;for(var d=2;dBr_Table OpCode Costs",id:"br_table-opcode-costs",level:2},{value:"External Function Costs",id:"external-function-costs",level:2},{value:"Protocol Operating Costs",id:"protocol-operating-costs",level:2},{value:"Auction System Contract Costs",id:"auction-system-contract-costs",level:3},{value:"Mint System Contract Costs",id:"mint-system-contract-costs",level:3},{value:"Handle_Payment System Contract Costs",id:"handle_payment-system-contract-costs",level:3},{value:"Standard_Payment System Contract Costs",id:"standard_payment-system-contract-costs",level:3}],u={toc:k},N="wrapper";function s(t){var e=t.components,a=(0,r.Z)(t,i);return(0,l.kt)(N,(0,n.Z)({},u,a,{components:e,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"opcode-costs-tables"},"OpCode Costs Tables"),(0,l.kt)("p",null,"The following tables outline the cost, in motes, for a given operation on Casper's Mainnet. If you are building for a private network or other instance of Casper, you will need to verify these costs in the associated ",(0,l.kt)("inlineCode",{parentName:"p"},"chainspec.toml"),"."),(0,l.kt)("p",null,"More information on ",(0,l.kt)("inlineCode",{parentName:"p"},"chainspec"),"s for private networks can be found ",(0,l.kt)("a",{parentName:"p",href:"/operators/setup-network/chain-spec"},"here")),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("p",{parentName:"admonition"},"All costs in this table are in ",(0,l.kt)("a",{parentName:"p",href:"/concepts/glossary/M/#motes"},"motes"),", not CSPR, and the corresponding chainspec is ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/53dd33865c2707c29284ccc0e8485f22ddd6fbe3/resources/production/chainspec.toml#L129"},"here"),".")),(0,l.kt)("h2",{id:"storage-costs"},"Storage Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"gas_per_byte"),(0,l.kt)("td",{parentName:"tr",align:null},"Gas charged per byte stored in global state."),(0,l.kt)("td",{parentName:"tr",align:null},"630,000")))),(0,l.kt)("h2",{id:"opcode-costs"},"OpCode Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"bit"),(0,l.kt)("td",{parentName:"tr",align:null},"Bit operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"300")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add"),(0,l.kt)("td",{parentName:"tr",align:null},"Arithmetic add operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"210")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mul"),(0,l.kt)("td",{parentName:"tr",align:null},"Mul operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"240")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"div"),(0,l.kt)("td",{parentName:"tr",align:null},"Div operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"320")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"load"),(0,l.kt)("td",{parentName:"tr",align:null},"Memory load operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"store"),(0,l.kt)("td",{parentName:"tr",align:null},"Memory store operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"4,700")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"const"),(0,l.kt)("td",{parentName:"tr",align:null},"Const store operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"110")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"local"),(0,l.kt)("td",{parentName:"tr",align:null},"Local operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"390")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"global"),(0,l.kt)("td",{parentName:"tr",align:null},"Global operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"390")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"integer_comparison"),(0,l.kt)("td",{parentName:"tr",align:null},"Integer operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"250")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"conversion"),(0,l.kt)("td",{parentName:"tr",align:null},"Conversion operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"420")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"unreachable"),(0,l.kt)("td",{parentName:"tr",align:null},"Unreachable operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"270")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"nop"),(0,l.kt)("td",{parentName:"tr",align:null},"Nop operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"200")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"current_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Get the current memory operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"290")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"grow_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Grow memory cost per page (64 kB)."),(0,l.kt)("td",{parentName:"tr",align:null},"240,000")))),(0,l.kt)("h2",{id:"control-flow-operation-costs"},"Control Flow Operation Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"block")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"loop"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"loop")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"if"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"if")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"else"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"else")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"end"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"end")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"br"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"br")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"br_if"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"br_if")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"return"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"return")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"select"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"select")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"call")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"68_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call_indirect"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"call_indirect")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"68,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"drop"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"drop")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")))),(0,l.kt)("h2",{id:"br_table-opcode-costs"},(0,l.kt)("inlineCode",{parentName:"h2"},"Br_Table")," OpCode Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"cost"),(0,l.kt)("td",{parentName:"tr",align:null},"Fixed cost per ",(0,l.kt)("inlineCode",{parentName:"td"},"br_table")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"size_multiplier"),(0,l.kt)("td",{parentName:"tr",align:null},"Size of target labels in the ",(0,l.kt)("inlineCode",{parentName:"td"},"br_table")," opcode will be multiplied by ",(0,l.kt)("inlineCode",{parentName:"td"},"size_multiplier"),"."),(0,l.kt)("td",{parentName:"tr",align:null},"100")))),(0,l.kt)("h2",{id:"external-function-costs"},"External Function Costs"),(0,l.kt)("p",null,'The following costs are for low-level bindings for host-side ("external") functions. More information on the Casper external FFI can be found ',(0,l.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/ext_ffi/index.html"},"here"),"."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Host-Side Function"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"),(0,l.kt)("th",{parentName:"tr",align:null},"Arguments"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add"),(0,l.kt)("td",{parentName:"tr",align:null},"5,800"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add_associated_key"),(0,l.kt)("td",{parentName:"tr",align:null},"9,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add_contract_version"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"blake2b"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call_contract"),(0,l.kt)("td",{parentName:"tr",align:null},"4,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 420, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call_versioned_contract"),(0,l.kt)("td",{parentName:"tr",align:null},"4,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 420, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create_contract_package_at_hash"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create_contract_user_group"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"disable_contract_version"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_balance"),(0,l.kt)("td",{parentName:"tr",align:null},"3,800"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_blocktime"),(0,l.kt)("td",{parentName:"tr",align:null},"330"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_caller"),(0,l.kt)("td",{parentName:"tr",align:null},"380"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_key"),(0,l.kt)("td",{parentName:"tr",align:null},"2,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 440, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_main_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"1,300"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_named_arg"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_named_arg_size"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_phase"),(0,l.kt)("td",{parentName:"tr",align:null},"710"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_system_contract"),(0,l.kt)("td",{parentName:"tr",align:null},"1,100"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"has_key"),(0,l.kt)("td",{parentName:"tr",align:null},"1,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 840]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"is_valid_uref"),(0,l.kt)("td",{parentName:"tr",align:null},"760"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"load_named_keys"),(0,l.kt)("td",{parentName:"tr",align:null},"42,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"new_uref"),(0,l.kt)("td",{parentName:"tr",align:null},"17,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 590]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"random_bytes"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"print"),(0,l.kt)("td",{parentName:"tr",align:null},"20,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 4,600]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"provision_contract_user_group_uref"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"put_key"),(0,l.kt)("td",{parentName:"tr",align:null},"38,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 1,100, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_host_buffer"),(0,l.kt)("td",{parentName:"tr",align:null},"3,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 310, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_value"),(0,l.kt)("td",{parentName:"tr",align:null},"6,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_value_local"),(0,l.kt)("td",{parentName:"tr",align:null},"5,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 590, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"remove_associated_key"),(0,l.kt)("td",{parentName:"tr",align:null},"4,200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"remove_contract_user_group"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"remove_contract_user_group_urefs"),(0,l.kt)("td",{parentName:"tr",align:null},"200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"remove_key"),(0,l.kt)("td",{parentName:"tr",align:null},"61,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 3,200]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"ret"),(0,l.kt)("td",{parentName:"tr",align:null},"23,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 420,000]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"revert"),(0,l.kt)("td",{parentName:"tr",align:null},"500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"set_action_threshold"),(0,l.kt)("td",{parentName:"tr",align:null},"74,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer_from_purse_to_account"),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer_from_purse_to_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"82,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer_to_account"),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 0, 0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"update_associated_key"),(0,l.kt)("td",{parentName:"tr",align:null},"4,200"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"write"),(0,l.kt)("td",{parentName:"tr",align:null},"14,000"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 0, 0, 980]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"write_local"),(0,l.kt)("td",{parentName:"tr",align:null},"9,500"),(0,l.kt)("td",{parentName:"tr",align:null},"[0, 1,800, 0, 520]")))),(0,l.kt)("h2",{id:"protocol-operating-costs"},"Protocol Operating Costs"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"wasmless_transfer_cost"),(0,l.kt)("td",{parentName:"tr",align:null},"Default gas cost for a wasmless transfer."),(0,l.kt)("td",{parentName:"tr",align:null},"100,000,000")))),(0,l.kt)("h3",{id:"auction-system-contract-costs"},(0,l.kt)("inlineCode",{parentName:"h3"},"Auction")," System Contract Costs"),(0,l.kt)("p",null,"These are the costs of calling ",(0,l.kt)("inlineCode",{parentName:"p"},"auction")," system contract entrypoints."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Entrypoint"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_era_validators"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_era_validators")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_seigniorage_recipients"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_seigniorage_recipients")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"add_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"delegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"delegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"undelegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"undelegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"run_auction"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"run_auction")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"slash"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"slash")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"distribute"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"distribute")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_delegator_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_delegator_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_validator_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_validator_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_era_id"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_era_id")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"activate_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"activate_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"redelegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"redelegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")))),(0,l.kt)("h3",{id:"mint-system-contract-costs"},(0,l.kt)("inlineCode",{parentName:"h3"},"Mint")," System Contract Costs"),(0,l.kt)("p",null,"These are the costs of calling ",(0,l.kt)("inlineCode",{parentName:"p"},"mint")," system contract entrypoints."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Entrypoint"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mint"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"mint")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"reduce_total_supply"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"reduce_total_supply")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"create")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"balance"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"balance")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"transfer")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_base_round_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_base_round_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mint_into_existing_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"mint_into_existing_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2,500,000,000")))),(0,l.kt)("h3",{id:"handle_payment-system-contract-costs"},(0,l.kt)("inlineCode",{parentName:"h3"},"Handle_Payment")," System Contract Costs"),(0,l.kt)("p",null,"These are the costs of calling entrypoints on the ",(0,l.kt)("inlineCode",{parentName:"p"},"handle_payment")," system contract."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Entrypoint"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_payment_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_payment_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"set_refund_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"set_refund_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_refund_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_refund_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"finalize_payment"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"finalize_payment")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")))),(0,l.kt)("h3",{id:"standard_payment-system-contract-costs"},(0,l.kt)("inlineCode",{parentName:"h3"},"Standard_Payment")," System Contract Costs"),(0,l.kt)("p",null,"These settings manage the costs of calling entrypoints on the ",(0,l.kt)("inlineCode",{parentName:"p"},"standard_payment")," system contract."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Entrypoint"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Cost"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"pay"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"pay")," entrypoint and sending an amount to a payment purse."),(0,l.kt)("td",{parentName:"tr",align:null},"10,000")))))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5e4971e3.a84bc526.js b/assets/js/5e4971e3.a84bc526.js deleted file mode 100644 index e97387e56f..0000000000 --- a/assets/js/5e4971e3.a84bc526.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3550],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},g=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),g=r,m=d["".concat(c,".").concat(g)]||d[g]||u[g]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=g;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},g=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),g=r,m=d["".concat(c,".").concat(g)]||d[g]||u[g]||i;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=g;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:r,o[1]=s;for(var l=2;l=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=a.createContext({}),l=function(e){var t=a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,i=p(e,["components","mdxType","originalType","parentName"]),d=l(r),f=n,y=d["".concat(c,".").concat(f)]||d[f]||u[f]||o;return r?a.createElement(y,s(s({ref:t},i),{},{components:r})):a.createElement(y,s({ref:t},i))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=f;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[d]="string"==typeof e?e:n,s[1]=p;for(var l=2;l=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=a.createContext({}),l=function(e){var t=a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,i=p(e,["components","mdxType","originalType","parentName"]),d=l(r),f=n,y=d["".concat(c,".").concat(f)]||d[f]||u[f]||o;return r?a.createElement(y,s(s({ref:t},i),{},{components:r})):a.createElement(y,s({ref:t},i))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=f;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[d]="string"==typeof e?e:n,s[1]=p;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),s=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[d]="string"==typeof e?e:r,i[1]=p;for(var s=2;s=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),s=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=s(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[d]="string"==typeof e?e:r,i[1]=p;for(var s=2;s=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,f=p["".concat(c,".").concat(d)]||p[d]||m[d]||i;return n?o.createElement(f,a(a({ref:t},u),{},{components:n})):o.createElement(f,a({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:r,a[1]=s;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},d=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),d=r,f=p["".concat(c,".").concat(d)]||p[d]||m[d]||i;return n?o.createElement(f,a(a({ref:t},u),{},{components:n})):o.createElement(f,a({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:r,a[1]=s;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,s=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(r),d=a,k=p["".concat(l,".").concat(d)]||p[d]||f[d]||s;return r?n.createElement(k,o(o({ref:t},c),{},{components:r})):n.createElement(k,o({ref:t},c))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var s=r.length,o=new Array(s);o[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[p]="string"==typeof e?e:a,o[1]=i;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,s=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(r),d=a,k=p["".concat(l,".").concat(d)]||p[d]||f[d]||s;return r?n.createElement(k,o(o({ref:t},c),{},{components:r})):n.createElement(k,o({ref:t},c))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var s=r.length,o=new Array(s);o[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[p]="string"==typeof e?e:a,o[1]=i;for(var u=2;u=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=i.createContext({}),c=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=c(e.components);return i.createElement(l.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},h=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=c(n),h=a,m=u["".concat(l,".").concat(h)]||u[h]||p[h]||o;return n?i.createElement(m,r(r({ref:t},d),{},{components:n})):i.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,r=new Array(o);r[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,r[1]=s;for(var c=2;c=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=i.createContext({}),c=function(e){var t=i.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=c(e.components);return i.createElement(l.Provider,{value:t},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},h=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=c(n),h=a,m=u["".concat(l,".").concat(h)]||u[h]||p[h]||o;return n?i.createElement(m,r(r({ref:t},d),{},{components:n})):i.createElement(m,r({ref:t},d))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,r=new Array(o);r[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,r[1]=s;for(var c=2;c=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var p=a.createContext({}),l=function(e){var t=a.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return a.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),y=n,g=u["".concat(p,".").concat(y)]||u[y]||f[y]||o;return r?a.createElement(g,s(s({ref:t},i),{},{components:r})):a.createElement(g,s({ref:t},i))}));function g(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:n,s[1]=c;for(var l=2;l=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var p=a.createContext({}),l=function(e){var t=a.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return a.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},y=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),y=n,g=u["".concat(p,".").concat(y)]||u[y]||f[y]||o;return r?a.createElement(g,s(s({ref:t},i),{},{components:r})):a.createElement(g,s({ref:t},i))}));function g(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:n,s[1]=c;for(var l=2;l=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var p=r.createContext({}),c=function(e){var n=r.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},d=function(e){var n=c(e.components);return r.createElement(p.Provider,{value:n},e.children)},i="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),i=c(t),m=a,f=i["".concat(p,".").concat(m)]||i[m]||u[m]||o;return t?r.createElement(f,s(s({ref:n},d),{},{components:t})):r.createElement(f,s({ref:n},d))}));function f(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,s=new Array(o);s[0]=m;var l={};for(var p in n)hasOwnProperty.call(n,p)&&(l[p]=n[p]);l.originalType=e,l[i]="string"==typeof e?e:a,s[1]=l;for(var c=2;c/rpc", http.DefaultClient)\n client := casper.NewRPCClient(handler)\n deployHash := "62972eddc6fdc03b7ec53e52f7da7e24f01add9a74d68e3e21d924051c43f126"\n deploy, err := client.GetDeploy(context.Background(), deployHash)\n if err != nil {\n return\n }\n fmt.Println(deploy.Deploy.Hash)\n}\n')),(0,o.kt)("h3",{id:"handle-the-deploy-processed-event"},"Handle the Deploy Processed Event"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-go"},'package main\n\nimport (\n "context"\n "log"\n\n "github.com/make-software/casper-go-sdk/sse"\n)\n\nfunc main() {\n client := sse.NewClient("https:///events/main")\n defer client.Stop()\n client.RegisterHandler(\n sse.DeployProcessedEventType,\n func(ctx context.Context, rawEvent sse.RawEvent) error {\n deploy, err := rawEvent.ParseAsDeployProcessedEvent()\n if err != nil {\n return err\n }\n log.Printf("Deploy hash: %s", deploy.DeployProcessed.DeployHash)\n return nil\n })\n lastEventID := 1234\n client.Start(context.TODO(), lastEventID)\n}\n')),(0,o.kt)("h3",{id:"sending-a-transfer"},"Sending a Transfer"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-go"},'package main\n\nimport (\n "context"\n "encoding/hex"\n "log"\n "math/big"\n "net/http"\n\n "github.com/make-software/casper-go-sdk/casper"\n "github.com/make-software/casper-go-sdk/types/clvalue"\n)\n\nfunc main() {\n accountPublicKey, err := casper.NewPublicKey("012488699f9a31e36ecf002675cd7186b48e6a735d10ec1b308587ca719937752c")\n if err != nil { return }\n amount := big.NewInt(100000000)\n session := casper.ExecutableDeployItem{\n ModuleBytes: &casper.ModuleBytes{\n ModuleBytes: hex.EncodeToString([]byte("")),\n Args: (&casper.Args{}).\n AddArgument("target", clvalue.NewCLByteArray(accountPublicKey.AccountHash().Bytes())).\n AddArgument("amount", *clvalue.NewCLUInt512(amount)),\n },\n }\n\n payment := casper.StandardPayment(amount)\n\n deployHeader := casper.DefaultHeader()\n deployHeader.Account = accountPublicKey\n deployHeader.ChainName = "casper-test"\n\n newDeploy, err := casper.MakeDeploy(deployHeader, payment, session)\n\n handler := casper.NewRPCHandler("https://:7777/rpc", http.DefaultClient)\n client := casper.NewRPCClient(handler)\n result, err := client.PutDeploy(context.Background(), *newDeploy)\n\n log.Println(result.DeployHash)\n}\n')))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6eee94da.a6e1f425.js b/assets/js/6eee94da.a6e1f425.js deleted file mode 100644 index 2c6fee752d..0000000000 --- a/assets/js/6eee94da.a6e1f425.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2388],{3905:function(e,n,t){t.d(n,{Zo:function(){return d},kt:function(){return f}});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function s(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var p=r.createContext({}),c=function(e){var n=r.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},d=function(e){var n=c(e.components);return r.createElement(p.Provider,{value:n},e.children)},i="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),i=c(t),m=a,f=i["".concat(p,".").concat(m)]||i[m]||u[m]||o;return t?r.createElement(f,s(s({ref:n},d),{},{components:t})):r.createElement(f,s({ref:n},d))}));function f(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,s=new Array(o);s[0]=m;var l={};for(var p in n)hasOwnProperty.call(n,p)&&(l[p]=n[p]);l.originalType=e,l[i]="string"==typeof e?e:a,s[1]=l;for(var c=2;c/rpc", http.DefaultClient)\n client := casper.NewRPCClient(handler)\n deployHash := "62972eddc6fdc03b7ec53e52f7da7e24f01add9a74d68e3e21d924051c43f126"\n deploy, err := client.GetDeploy(context.Background(), deployHash)\n if err != nil {\n return\n }\n fmt.Println(deploy.Deploy.Hash)\n}\n')),(0,o.kt)("h3",{id:"handle-the-deploy-processed-event"},"Handle the Deploy Processed Event"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-go"},'package main\n\nimport (\n "context"\n "log"\n\n "github.com/make-software/casper-go-sdk/sse"\n)\n\nfunc main() {\n client := sse.NewClient("https:///events/main")\n defer client.Stop()\n client.RegisterHandler(\n sse.DeployProcessedEventType,\n func(ctx context.Context, rawEvent sse.RawEvent) error {\n deploy, err := rawEvent.ParseAsDeployProcessedEvent()\n if err != nil {\n return err\n }\n log.Printf("Deploy hash: %s", deploy.DeployProcessed.DeployHash)\n return nil\n })\n lastEventID := 1234\n client.Start(context.TODO(), lastEventID)\n}\n')),(0,o.kt)("h3",{id:"sending-a-transfer"},"Sending a Transfer"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-go"},'package main\n\nimport (\n "context"\n "encoding/hex"\n "log"\n "math/big"\n "net/http"\n\n "github.com/make-software/casper-go-sdk/casper"\n "github.com/make-software/casper-go-sdk/types/clvalue"\n)\n\nfunc main() {\n accountPublicKey, err := casper.NewPublicKey("012488699f9a31e36ecf002675cd7186b48e6a735d10ec1b308587ca719937752c")\n if err != nil { return }\n amount := big.NewInt(100000000)\n session := casper.ExecutableDeployItem{\n ModuleBytes: &casper.ModuleBytes{\n ModuleBytes: hex.EncodeToString([]byte("")),\n Args: (&casper.Args{}).\n AddArgument("target", clvalue.NewCLByteArray(accountPublicKey.AccountHash().Bytes())).\n AddArgument("amount", *clvalue.NewCLUInt512(amount)),\n },\n }\n\n payment := casper.StandardPayment(amount)\n\n deployHeader := casper.DefaultHeader()\n deployHeader.Account = accountPublicKey\n deployHeader.ChainName = "casper-test"\n\n newDeploy, err := casper.MakeDeploy(deployHeader, payment, session)\n\n handler := casper.NewRPCHandler("https://:7777/rpc", http.DefaultClient)\n client := casper.NewRPCClient(handler)\n result, err := client.PutDeploy(context.Background(), *newDeploy)\n\n log.Println(result.DeployHash)\n}\n')))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6faae04c.3f306220.js b/assets/js/6faae04c.3f306220.js new file mode 100644 index 0000000000..e498163044 --- /dev/null +++ b/assets/js/6faae04c.3f306220.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6986],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,s(s({ref:t},c),{},{components:n})):a.createElement(h,s({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[d]="string"==typeof e?e:r,s[1]=i;for(var p=2;p:7777 \\\n--amount 10000000000 \\\n--secret-key .pem \\\n--chain-name casper \\\n--target-account \\\n--payment-amount \n")),(0,o.kt)("p",null,"The payment amount varies based on the deploy and network ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". For node version ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1"),", wasmless transfers cost 10^8 motes."),(0,o.kt)("h3",{id:"bulk-or-batched-wasm-transfer"},"Bulk or batched Wasm transfer"),(0,o.kt)("p",null,"Bulk or batched Wasm transfers allow you to apply some logic before or after the transfer. They also allow for conditional transfers. You may also use them if you are doing a series of transfers between multiple purses. Listed below are five methods for the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/index.html"},"Rust contract API"),", which can be used in session code to achieve batched Wasm transfer:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_to_account"),": Transfers amount of motes from the main purse of the account to the purse of a target account. If the target purse does not exist, the transfer process will create one. Can be called from session code only and not a contract as a contract doesn't have a main purse."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_to_public_key"),": Transfers amount of motes from the main purse of the caller\u2019s account to the main purse of the target. If the account referenced by the target does not exist, the transfer will create a new account. Can be called from session code only and not from a contract as a contract doesn't have a main purse."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_from_purse_to_purse"),": Transfers amount of motes from source purse to target purse. If the target does not exist, the transfer fails."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_from_purse_to_public_key"),": Transfers amount of motes from source to the main purse of target. If the account referenced by the target does not exist, the transfer will create it."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_from_purse_to_account"),": Transfers amount of motes from source purse to target account's purse. If the target account does not exist, the transfer creates a new account.")),(0,o.kt)("p",null,"For more information on how to write session code, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/writing-session-code"},"Writing Session Code"),". There are equivalent ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/e01b528db64f96fc1d3eac8b3b8e58e1337b398d/smart_contracts/contract_as/assembly/purse.ts#L135-L305"},"assembly script")," methods available. Alternatively, you can program directly against the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/e01b528db64f96fc1d3eac8b3b8e58e1337b398d/smart_contracts/contract/src/ext_ffi.rs#L283-L370"},"ext-FFI")," methods."),(0,o.kt)("h2",{id:"integrating-cspr"},"Integrating CSPR"),(0,o.kt)("p",null,"You can integrate with the ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/"},"JSON-RPC API")," of a node on the Casper Mainnet. You can program directly against the RPC or if you prefer you can choose from the variety of SDK libraries that are available to use on a Casper network see ",(0,o.kt)("a",{parentName:"p",href:"/sdk"},"SDK Libraries"),". Casper also provides a stream server that gives you real-time information about a variety of events occurring on a node. Use of the stream is optional. You might want to use this feature as it notifies you of events instead of requiring you to ask periodically. For more information about various events, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/dapps/monitor-and-consume-events"},"Monitoring and Consuming Events"),"."),(0,o.kt)("h2",{id:"testing-the-integration"},"Testing the Integration"),(0,o.kt)("p",null,"Our recommended testing mechanism is to have a test environment that points at the official Casper ",(0,o.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"Testnet"),". Through this, you may run production like operations of your test exchange against the test environment. However, if you are not doing this and you just want to integrate with the ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"Mainnet"),", then you can do so with your own test accounts."),(0,o.kt)("p",null,"If you are not going to do a Testnet integration, then we suggest you create some additional test accounts and test the transactions on the Mainnet through your software prior to moving to the general public."),(0,o.kt)("h2",{id:"the-casper-protocol"},"The Casper Protocol"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Casper is integrated with BitGo for enterprise grade custody. If your exchange uses BitGo, support for Casper is available already."),(0,o.kt)("li",{parentName:"ul"},"Casper has an execution after consensus model, which means that transactions are executed after they are finalized. Transactions are not orphaned or uncle\u2019d on Casper and neither does chain reorganization happen on it. For more information on the execution process, see ",(0,o.kt)("a",{parentName:"li",href:"/concepts/design/casper-design#execution-semantics-head"},"Execution Semantics"),"."),(0,o.kt)("li",{parentName:"ul"},"Exchanges can check finality signatures. Validators send finality signatures after the finalized block is executed and global state is updated. The Casper node streams execution effects and finality signatures through an SSE architecture. For more information about various events, see ",(0,o.kt)("a",{parentName:"li",href:"/developers/dapps/monitor-and-consume-events"},"Monitoring and Consuming Events"),".")),(0,o.kt)("h2",{id:"staking-integration-for-exchanges"},"Staking Integration for Exchanges"),(0,o.kt)("p",null,"Exchanges seeking to integrate CSPR staking mechanisms will need to understand the processes of delegation, undelegation and redelegation through deploys on a Casper network. The following outlines the use of the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/casper-js-sdk/"},"JavaScript SDK")," to perform these actions, as well as parameters relating to staking. Further information about staking on a Casper network can be found ",(0,o.kt)("a",{parentName:"p",href:"/staking/"},"here"),"."),(0,o.kt)("h3",{id:"deploy-structures-and-parameters"},"Deploy Structures and Parameters"),(0,o.kt)("p",null,"Staking operations consists of two parts:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"/developers/cli/sending-deploys"},"Creating a deploy object")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"/developers/dapps/signing-a-deploy"},"Signing the deploy"))),(0,o.kt)("p",null,"The staking deploy requires the following information:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"The delegator's public key"),(0,o.kt)("li",{parentName:"ul"},"The validator's public key"),(0,o.kt)("li",{parentName:"ul"},"The new validator's public key (For redelegation only)"),(0,o.kt)("li",{parentName:"ul"},"The amount to be delegated"),(0,o.kt)("li",{parentName:"ul"},"The gas cost"),(0,o.kt)("li",{parentName:"ul"},"The auction manager contract's hash"),(0,o.kt)("li",{parentName:"ul"},"The appropriate entry point")),(0,o.kt)("p",null,"Casper provides a series of prebuilt Wasm files for use in these operations. They are provided for convenience, and you are free to create your own custom deploys. You can find them in our ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository, in the following locations:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/client/delegate"},"Delegate")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/client/undelegate"},"Undelegate")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/client/redelegate"},"Redelegate"))),(0,o.kt)("h4",{id:"1-creating-a-deploy-object"},"1. Creating a deploy object"),(0,o.kt)("p",null,"To create a deploy using the JavaScript SDK, we will need ",(0,o.kt)("inlineCode",{parentName:"p"},"deployParams"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"session")," and a ",(0,o.kt)("inlineCode",{parentName:"p"},"payment"),"."),(0,o.kt)("p",null,"Deploy params is a ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployUtil.DeployParams")," object created from the delegator's ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," and the network name as shown in the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { DeployUtil, CLPublicKey } from 'casper-js-sdk';\n\nconst deployParams = new DeployUtil.DeployParams(\n CLPublicKey.fromHex(publicKeyHex),\n network_name // 'testnet' | 'mainnet'\n);\n")),(0,o.kt)("p",null,"For creating a ",(0,o.kt)("inlineCode",{parentName:"p"},"session")," object, which is ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployUtil.ExecutableDeployItem"),", we need"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("strong",{parentName:"li"},"delegator")," and ",(0,o.kt)("strong",{parentName:"li"},"validator's public keys")),(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("strong",{parentName:"li"},"amount")," of tokens to delegate/undelegate/redelgate"),(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("strong",{parentName:"li"},"auction manager contract's hash")),(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("strong",{parentName:"li"},"entry point"))),(0,o.kt)("p",null,"First, create a variable ",(0,o.kt)("inlineCode",{parentName:"p"},"RuntimeArgs")," from the public keys and the amount. We will need to use it below in ",(0,o.kt)("inlineCode",{parentName:"p"},"session"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { RuntimeArgs, CLValueBuilder, CLPublicKey } from 'casper-js-sdk';\n\nconst args = RuntimeArgs.fromMap({\n delegator: CLPublicKey.fromHex(delegatorPublicKeyHex),\n validator: CLPublicKey.fromHex(validatorPublicKeyHex),\n amount: CLValueBuilder.u512(amountMotes) // in motes\n});\n")),(0,o.kt)("p",null,"Second, create a ",(0,o.kt)("inlineCode",{parentName:"p"},"session")," parameter. It is a ",(0,o.kt)("inlineCode",{parentName:"p"},"Uint8Array")," consisting of the ",(0,o.kt)("inlineCode",{parentName:"p"},"auction manager contract's hash"),", the ",(0,o.kt)("inlineCode",{parentName:"p"},"entry points")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime arguments"),", which we previously created."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"auction manager contract's hash")," will depend on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Mainnet"),(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Testnet"),(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")))),(0,o.kt)("p",null,"Your ",(0,o.kt)("inlineCode",{parentName:"p"},"entry point")," will depend on which action you are performing, with the following three available:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"delegate")," - Initial delegation to a validator"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"undelegate")," - Undelegating tokens from a validator back to the delegator"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"redelegate")," - Redelegating tokens to a new validator")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { decodeBase16, DeployUtil } from 'casper-js-sdk';\n\nconst session = DeployUtil.ExecutableDeployItem.newStoredContractByHash(\n decodeBase16(auction_manager_contract_hash), // auction manager contract hash\n contractEntryPoint, // auction manager entry point\n args\n);\n")),(0,o.kt)("p",null,"To create the ",(0,o.kt)("inlineCode",{parentName:"p"},"payment")," parameter for the deploy, we need a deploy cost. The actual costs can be pulled from the network chainspec. Here is the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.4.8/resources/production/chainspec.toml"},(0,o.kt)("inlineCode",{parentName:"a"},"chainspec for version 1.4.8")),". You will need the chainspec for the network version you are using."),(0,o.kt)("p",null,"Use the ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployUtil.standardPayment")," method for creating ",(0,o.kt)("inlineCode",{parentName:"p"},"payment"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { DeployUtil } from 'casper-js-sdk';\n\nconst payment = DeployUtil.standardPayment(deployCost);\n")),(0,o.kt)("p",null,"The last operation is creating the deploy:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { DeployUtil } from 'casper-js-sdk';\n\nDeployUtil.makeDeploy(deployParams, session, payment);\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Redelegation"),", occurs the same way as delegation, but with the introduction of a third public_key."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { RuntimeArgs, CLPublicKey, CLValueBuilder } from 'casper-js-sdk';\n\nconst args = RuntimeArgs.fromMap({\n delegator: CLPublicKey.fromHex(delegatorPublicKeyHex),\n validator: CLPublicKey.fromHex(validatorPublicKeyHex),\n new_validator: CLPublicKey.fromHex(redelegateValidatorPublicKeyHex),\n amount: CLValueBuilder.u512(amountMotes)\n})\n")),(0,o.kt)("h4",{id:"2a-sign-the-deploy-casper-signer"},"2a. Sign the deploy (Casper Signer)"),(0,o.kt)("p",null,"To get the signature, you will need to use ",(0,o.kt)("inlineCode",{parentName:"p"},"Signer.sign")," from the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/casper-js-sdk/"},"JavaScript SDK"),". It will return ",(0,o.kt)("inlineCode",{parentName:"p"},"Promise<{ deploy }>"),", which is the signed object."),(0,o.kt)("p",null,"Use ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployUtil.deployFromJson")," to convert the result and sent it to network with:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { Signer, CasperServiceByJsonRPC, DeployUtil } from 'casper-js-sdk';\n\nconst casperService = new CasperServiceByJsonRPC(GRPC_URL);\nconst deployJson = DeployUtil.deployToJson(deploy);\nSigner.sign(\n deployJson,\n accountPublicKey,\n recipientPublicKey\n).then((signedDeployJson) => {\n const signedDeploy = DeployUtil.deployFromJson(signedDeployJson);\n if (signedDeploy.ok) {\n casperService.deploy(signedDeploy.val! as DeployUtil.Deploy); // sent deploy\n }\n}\n")),(0,o.kt)("h4",{id:"2b-sign-the-deploy-ledger"},"2b. Sign the deploy (Ledger)"),(0,o.kt)("p",null,"You will need to connect with your ",(0,o.kt)("inlineCode",{parentName:"p"},"Ledger")," first to get the signature."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import TransportWebUSB from '@ledgerhq/hw-transport-webusb';\nimport LedgerApp, { ResponseBase } from '@zondax/ledger-casper';\nimport { DeployUtil } from 'casper-js-sdk';\n\nconst getBipPath = (index: number) => {\n const idx = index.toString();\n return `m/44'/506'/0'/0/${idx}`;\n};\n\nconst deployBytes = DeployUtil.deployToBytes(deploy) as Buffer;\nconst transport = await TransportWebUSB.create();\nconst ledgerApp = new LedgerApp(transport);\nconst res = await ledgerApp.sign(\n getBipPath(selectedAccountIndex),\n deployBytes\n);\n")),(0,o.kt)("p",null,"The Signature will be in a property called ",(0,o.kt)("inlineCode",{parentName:"p"},"res.signatureRS"),"."),(0,o.kt)("p",null,"After that, we can create a signed deploy,"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { DeployUtil, CLPublicKey } from 'casper-js-sdk';\n\nconst signedDeploy = DeployUtil.setSignature(\n deploy,\n signatureRS,\n CLPublicKey.fromHex(accountPublicKey)\n);\n")),(0,o.kt)("p",null,"We can then send it to a network."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"casperService.deploy(signedDeploy)\n")),(0,o.kt)("h3",{id:"costs-and-minimums"},"Costs and Minimums"),(0,o.kt)("p",null,"The following are costs and minimum amounts for version 1.5.1, but up-to-date values should be pulled from the network ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),"."),(0,o.kt)("p",null,"Transfer Cost: 100,000,000 motes or 0.1 ",(0,o.kt)("strong",{parentName:"p"},"CSPR")),(0,o.kt)("p",null,"Delegation Cost: 2,500,000,000 motes or 2.5 ",(0,o.kt)("strong",{parentName:"p"},"CSPR")),(0,o.kt)("p",null,"Minimum transfer amount: 2,500,000,000 motes, or 2.5 ",(0,o.kt)("strong",{parentName:"p"},"CSPR")),(0,o.kt)("p",null,"Minimum amount required for delegation: 500,000,000,000 motes, or 500 ",(0,o.kt)("strong",{parentName:"p"},"CSPR"),"."),(0,o.kt)("h3",{id:"the-delegation-cap"},"The Delegation Cap"),(0,o.kt)("p",null,"Casper includes a delegator limit rule, which limits the number of delegators that a single validator may have at ",(0,o.kt)("inlineCode",{parentName:"p"},"953"),". This is a temporary solution to prevent complications with Casper\u2019s fast sync mechanism - in which high bond counts could break fast sync."),(0,o.kt)("p",null,"Validators with a delegator count at or above ",(0,o.kt)("inlineCode",{parentName:"p"},"953")," at the time of the ",(0,o.kt)("strong",{parentName:"p"},"1.4.5")," upgrade were grandfathered in, however new delegators will not be able to delegate to any validator until the delegator count for that validator falls below ",(0,o.kt)("inlineCode",{parentName:"p"},"953"),"."),(0,o.kt)("p",null,"Existing delegators may continue to delegate additional CSPR, regardless of the current number of delegators staking their ",(0,o.kt)("strong",{parentName:"p"},"CSPR")," to that validator. However, no new delegators may join the validator until it drops below the ",(0,o.kt)("inlineCode",{parentName:"p"},"953")," limit."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6faae04c.f9e4da13.js b/assets/js/6faae04c.f9e4da13.js deleted file mode 100644 index 2f40ae8840..0000000000 --- a/assets/js/6faae04c.f9e4da13.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6986],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,s(s({ref:t},c),{},{components:n})):a.createElement(h,s({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[d]="string"==typeof e?e:r,s[1]=i;for(var p=2;p:7777 \\\n--amount 10000000000 \\\n--secret-key .pem \\\n--chain-name casper \\\n--target-account \\\n--payment-amount \n")),(0,o.kt)("p",null,"The payment amount varies based on the deploy and network ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". For node version ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1"),", wasmless transfers cost 10^8 motes."),(0,o.kt)("h3",{id:"bulk-or-batched-wasm-transfer"},"Bulk or batched Wasm transfer"),(0,o.kt)("p",null,"Bulk or batched Wasm transfers allow you to apply some logic before or after the transfer. They also allow for conditional transfers. You may also use them if you are doing a series of transfers between multiple purses. Listed below are five methods for the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/index.html"},"Rust contract API"),", which can be used in session code to achieve batched Wasm transfer:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_to_account"),": Transfers amount of motes from the main purse of the account to the purse of a target account. If the target purse does not exist, the transfer process will create one. Can be called from session code only and not a contract as a contract doesn't have a main purse."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_to_public_key"),": Transfers amount of motes from the main purse of the caller\u2019s account to the main purse of the target. If the account referenced by the target does not exist, the transfer will create a new account. Can be called from session code only and not from a contract as a contract doesn't have a main purse."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_from_purse_to_purse"),": Transfers amount of motes from source purse to target purse. If the target does not exist, the transfer fails."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_from_purse_to_public_key"),": Transfers amount of motes from source to the main purse of target. If the account referenced by the target does not exist, the transfer will create it."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"transfer_from_purse_to_account"),": Transfers amount of motes from source purse to target account's purse. If the target account does not exist, the transfer creates a new account.")),(0,o.kt)("p",null,"For more information on how to write session code, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/writing-session-code"},"Writing Session Code"),". There are equivalent ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/e01b528db64f96fc1d3eac8b3b8e58e1337b398d/smart_contracts/contract_as/assembly/purse.ts#L135-L305"},"assembly script")," methods available. Alternatively, you can program directly against the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/e01b528db64f96fc1d3eac8b3b8e58e1337b398d/smart_contracts/contract/src/ext_ffi.rs#L283-L370"},"ext-FFI")," methods."),(0,o.kt)("h2",{id:"integrating-cspr"},"Integrating CSPR"),(0,o.kt)("p",null,"You can integrate with the ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/"},"JSON-RPC API")," of a node on the Casper Mainnet. You can program directly against the RPC or if you prefer you can choose from the variety of SDK libraries that are available to use on a Casper network see ",(0,o.kt)("a",{parentName:"p",href:"/sdk"},"SDK Libraries"),". Casper also provides a stream server that gives you real-time information about a variety of events occurring on a node. Use of the stream is optional. You might want to use this feature as it notifies you of events instead of requiring you to ask periodically. For more information about various events, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/dapps/monitor-and-consume-events"},"Monitoring and Consuming Events"),"."),(0,o.kt)("h2",{id:"testing-the-integration"},"Testing the Integration"),(0,o.kt)("p",null,"Our recommended testing mechanism is to have a test environment that points at the official Casper ",(0,o.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"Testnet"),". Through this, you may run production like operations of your test exchange against the test environment. However, if you are not doing this and you just want to integrate with the ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"Mainnet"),", then you can do so with your own test accounts."),(0,o.kt)("p",null,"If you are not going to do a Testnet integration, then we suggest you create some additional test accounts and test the transactions on the Mainnet through your software prior to moving to the general public."),(0,o.kt)("h2",{id:"the-casper-protocol"},"The Casper Protocol"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Casper is integrated with BitGo for enterprise grade custody. If your exchange uses BitGo, support for Casper is available already."),(0,o.kt)("li",{parentName:"ul"},"Casper has an execution after consensus model, which means that transactions are executed after they are finalized. Transactions are not orphaned or uncle\u2019d on Casper and neither does chain reorganization happen on it. For more information on the execution process, see ",(0,o.kt)("a",{parentName:"li",href:"/concepts/design/casper-design#execution-semantics-head"},"Execution Semantics"),"."),(0,o.kt)("li",{parentName:"ul"},"Exchanges can check finality signatures. Validators send finality signatures after the finalized block is executed and global state is updated. The Casper node streams execution effects and finality signatures through an SSE architecture. For more information about various events, see ",(0,o.kt)("a",{parentName:"li",href:"/developers/dapps/monitor-and-consume-events"},"Monitoring and Consuming Events"),".")),(0,o.kt)("h2",{id:"staking-integration-for-exchanges"},"Staking Integration for Exchanges"),(0,o.kt)("p",null,"Exchanges seeking to integrate CSPR staking mechanisms will need to understand the processes of delegation, undelegation and redelegation through deploys on a Casper network. The following outlines the use of the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/casper-js-sdk/"},"JavaScript SDK")," to perform these actions, as well as parameters relating to staking. Further information about staking on a Casper network can be found ",(0,o.kt)("a",{parentName:"p",href:"/staking/"},"here"),"."),(0,o.kt)("h3",{id:"deploy-structures-and-parameters"},"Deploy Structures and Parameters"),(0,o.kt)("p",null,"Staking operations consists of two parts:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"/developers/cli/sending-deploys"},"Creating a deploy object")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"/developers/dapps/signing-a-deploy"},"Signing the deploy"))),(0,o.kt)("p",null,"The staking deploy requires the following information:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"The delegator's public key"),(0,o.kt)("li",{parentName:"ul"},"The validator's public key"),(0,o.kt)("li",{parentName:"ul"},"The new validator's public key (For redelegation only)"),(0,o.kt)("li",{parentName:"ul"},"The amount to be delegated"),(0,o.kt)("li",{parentName:"ul"},"The gas cost"),(0,o.kt)("li",{parentName:"ul"},"The auction manager contract's hash"),(0,o.kt)("li",{parentName:"ul"},"The appropriate entry point")),(0,o.kt)("p",null,"Casper provides a series of prebuilt Wasm files for use in these operations. They are provided for convenience, and you are free to create your own custom deploys. You can find them in our ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository, in the following locations:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/client/delegate"},"Delegate")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/client/undelegate"},"Undelegate")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/client/redelegate"},"Redelegate"))),(0,o.kt)("h4",{id:"1-creating-a-deploy-object"},"1. Creating a deploy object"),(0,o.kt)("p",null,"To create a deploy using the JavaScript SDK, we will need ",(0,o.kt)("inlineCode",{parentName:"p"},"deployParams"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"session")," and a ",(0,o.kt)("inlineCode",{parentName:"p"},"payment"),"."),(0,o.kt)("p",null,"Deploy params is a ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployUtil.DeployParams")," object created from the delegator's ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," and the network name as shown in the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { DeployUtil, CLPublicKey } from 'casper-js-sdk';\n\nconst deployParams = new DeployUtil.DeployParams(\n CLPublicKey.fromHex(publicKeyHex),\n network_name // 'testnet' | 'mainnet'\n);\n")),(0,o.kt)("p",null,"For creating a ",(0,o.kt)("inlineCode",{parentName:"p"},"session")," object, which is ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployUtil.ExecutableDeployItem"),", we need"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("strong",{parentName:"li"},"delegator")," and ",(0,o.kt)("strong",{parentName:"li"},"validator's public keys")),(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("strong",{parentName:"li"},"amount")," of tokens to delegate/undelegate/redelgate"),(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("strong",{parentName:"li"},"auction manager contract's hash")),(0,o.kt)("li",{parentName:"ul"},"The ",(0,o.kt)("strong",{parentName:"li"},"entry point"))),(0,o.kt)("p",null,"First, create a variable ",(0,o.kt)("inlineCode",{parentName:"p"},"RuntimeArgs")," from the public keys and the amount. We will need to use it below in ",(0,o.kt)("inlineCode",{parentName:"p"},"session"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { RuntimeArgs, CLValueBuilder, CLPublicKey } from 'casper-js-sdk';\n\nconst args = RuntimeArgs.fromMap({\n delegator: CLPublicKey.fromHex(delegatorPublicKeyHex),\n validator: CLPublicKey.fromHex(validatorPublicKeyHex),\n amount: CLValueBuilder.u512(amountMotes) // in motes\n});\n")),(0,o.kt)("p",null,"Second, create a ",(0,o.kt)("inlineCode",{parentName:"p"},"session")," parameter. It is a ",(0,o.kt)("inlineCode",{parentName:"p"},"Uint8Array")," consisting of the ",(0,o.kt)("inlineCode",{parentName:"p"},"auction manager contract's hash"),", the ",(0,o.kt)("inlineCode",{parentName:"p"},"entry points")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime arguments"),", which we previously created."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"auction manager contract's hash")," will depend on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Mainnet"),(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"Testnet"),(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")))),(0,o.kt)("p",null,"Your ",(0,o.kt)("inlineCode",{parentName:"p"},"entry point")," will depend on which action you are performing, with the following three available:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"delegate")," - Initial delegation to a validator"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"undelegate")," - Undelegating tokens from a validator back to the delegator"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"redelegate")," - Redelegating tokens to a new validator")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { decodeBase16, DeployUtil } from 'casper-js-sdk';\n\nconst session = DeployUtil.ExecutableDeployItem.newStoredContractByHash(\n decodeBase16(auction_manager_contract_hash), // auction manager contract hash\n contractEntryPoint, // auction manager entry point\n args\n);\n")),(0,o.kt)("p",null,"To create the ",(0,o.kt)("inlineCode",{parentName:"p"},"payment")," parameter for the deploy, we need a deploy cost. The actual costs can be pulled from the network chainspec. Here is the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.4.8/resources/production/chainspec.toml"},(0,o.kt)("inlineCode",{parentName:"a"},"chainspec for version 1.4.8")),". You will need the chainspec for the network version you are using."),(0,o.kt)("p",null,"Use the ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployUtil.standardPayment")," method for creating ",(0,o.kt)("inlineCode",{parentName:"p"},"payment"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { DeployUtil } from 'casper-js-sdk';\n\nconst payment = DeployUtil.standardPayment(deployCost);\n")),(0,o.kt)("p",null,"The last operation is creating the deploy:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { DeployUtil } from 'casper-js-sdk';\n\nDeployUtil.makeDeploy(deployParams, session, payment);\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Redelegation"),", occurs the same way as delegation, but with the introduction of a third public_key."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { RuntimeArgs, CLPublicKey, CLValueBuilder } from 'casper-js-sdk';\n\nconst args = RuntimeArgs.fromMap({\n delegator: CLPublicKey.fromHex(delegatorPublicKeyHex),\n validator: CLPublicKey.fromHex(validatorPublicKeyHex),\n new_validator: CLPublicKey.fromHex(redelegateValidatorPublicKeyHex),\n amount: CLValueBuilder.u512(amountMotes)\n})\n")),(0,o.kt)("h4",{id:"2a-sign-the-deploy-casper-signer"},"2a. Sign the deploy (Casper Signer)"),(0,o.kt)("p",null,"To get the signature, you will need to use ",(0,o.kt)("inlineCode",{parentName:"p"},"Signer.sign")," from the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/casper-js-sdk/"},"JavaScript SDK"),". It will return ",(0,o.kt)("inlineCode",{parentName:"p"},"Promise<{ deploy }>"),", which is the signed object."),(0,o.kt)("p",null,"Use ",(0,o.kt)("inlineCode",{parentName:"p"},"DeployUtil.deployFromJson")," to convert the result and sent it to network with:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { Signer, CasperServiceByJsonRPC, DeployUtil } from 'casper-js-sdk';\n\nconst casperService = new CasperServiceByJsonRPC(GRPC_URL);\nconst deployJson = DeployUtil.deployToJson(deploy);\nSigner.sign(\n deployJson,\n accountPublicKey,\n recipientPublicKey\n).then((signedDeployJson) => {\n const signedDeploy = DeployUtil.deployFromJson(signedDeployJson);\n if (signedDeploy.ok) {\n casperService.deploy(signedDeploy.val! as DeployUtil.Deploy); // sent deploy\n }\n}\n")),(0,o.kt)("h4",{id:"2b-sign-the-deploy-ledger"},"2b. Sign the deploy (Ledger)"),(0,o.kt)("p",null,"You will need to connect with your ",(0,o.kt)("inlineCode",{parentName:"p"},"Ledger")," first to get the signature."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import TransportWebUSB from '@ledgerhq/hw-transport-webusb';\nimport LedgerApp, { ResponseBase } from '@zondax/ledger-casper';\nimport { DeployUtil } from 'casper-js-sdk';\n\nconst getBipPath = (index: number) => {\n const idx = index.toString();\n return `m/44'/506'/0'/0/${idx}`;\n};\n\nconst deployBytes = DeployUtil.deployToBytes(deploy) as Buffer;\nconst transport = await TransportWebUSB.create();\nconst ledgerApp = new LedgerApp(transport);\nconst res = await ledgerApp.sign(\n getBipPath(selectedAccountIndex),\n deployBytes\n);\n")),(0,o.kt)("p",null,"The Signature will be in a property called ",(0,o.kt)("inlineCode",{parentName:"p"},"res.signatureRS"),"."),(0,o.kt)("p",null,"After that, we can create a signed deploy,"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import { DeployUtil, CLPublicKey } from 'casper-js-sdk';\n\nconst signedDeploy = DeployUtil.setSignature(\n deploy,\n signatureRS,\n CLPublicKey.fromHex(accountPublicKey)\n);\n")),(0,o.kt)("p",null,"We can then send it to a network."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"casperService.deploy(signedDeploy)\n")),(0,o.kt)("h3",{id:"costs-and-minimums"},"Costs and Minimums"),(0,o.kt)("p",null,"The following are costs and minimum amounts for version 1.5.1, but up-to-date values should be pulled from the network ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),"."),(0,o.kt)("p",null,"Transfer Cost: 100,000,000 motes or 0.1 ",(0,o.kt)("strong",{parentName:"p"},"CSPR")),(0,o.kt)("p",null,"Delegation Cost: 2,500,000,000 motes or 2.5 ",(0,o.kt)("strong",{parentName:"p"},"CSPR")),(0,o.kt)("p",null,"Minimum transfer amount: 2,500,000,000 motes, or 2.5 ",(0,o.kt)("strong",{parentName:"p"},"CSPR")),(0,o.kt)("p",null,"Minimum amount required for delegation: 500,000,000,000 motes, or 500 ",(0,o.kt)("strong",{parentName:"p"},"CSPR"),"."),(0,o.kt)("h3",{id:"the-delegation-cap"},"The Delegation Cap"),(0,o.kt)("p",null,"Casper includes a delegator limit rule, which limits the number of delegators that a single validator may have at ",(0,o.kt)("inlineCode",{parentName:"p"},"953"),". This is a temporary solution to prevent complications with Casper\u2019s fast sync mechanism - in which high bond counts could break fast sync."),(0,o.kt)("p",null,"Validators with a delegator count at or above ",(0,o.kt)("inlineCode",{parentName:"p"},"953")," at the time of the ",(0,o.kt)("strong",{parentName:"p"},"1.4.5")," upgrade were grandfathered in, however new delegators will not be able to delegate to any validator until the delegator count for that validator falls below ",(0,o.kt)("inlineCode",{parentName:"p"},"953"),"."),(0,o.kt)("p",null,"Existing delegators may continue to delegate additional CSPR, regardless of the current number of delegators staking their ",(0,o.kt)("strong",{parentName:"p"},"CSPR")," to that validator. However, no new delegators may join the validator until it drops below the ",(0,o.kt)("inlineCode",{parentName:"p"},"953")," limit."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6fc855ed.0d43a718.js b/assets/js/6fc855ed.0d43a718.js deleted file mode 100644 index f592c8eb8f..0000000000 --- a/assets/js/6fc855ed.0d43a718.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1263],{3905:function(e,t,r){r.d(t,{Zo:function(){return p},kt:function(){return k}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},g="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),g=c(r),d=a,k=g["".concat(s,".").concat(d)]||g[d]||u[d]||i;return r?n.createElement(k,l(l({ref:t},p),{},{components:r})):n.createElement(k,l({ref:t},p))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,l=new Array(i);l[0]=d;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[g]="string"==typeof e?e:a,l[1]=o;for(var c=2;c=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),c=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},g="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),g=c(r),d=a,k=g["".concat(s,".").concat(d)]||g[d]||u[d]||i;return r?n.createElement(k,l(l({ref:t},p),{},{components:r})):n.createElement(k,l({ref:t},p))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,l=new Array(i);l[0]=d;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[g]="string"==typeof e?e:a,l[1]=o;for(var c=2;c=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),d=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=d(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=d(n),h=i,y=p["".concat(c,".").concat(h)]||p[h]||u[h]||r;return n?a.createElement(y,o(o({ref:t},l),{},{components:n})):a.createElement(y,o({ref:t},l))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:i,o[1]=s;for(var d=2;dContractNamedKey lookup via a Contract's named keys.",id:"contractnamedkey-lookup-via-a-contracts-named-keys",level:3},{value:"URef lookup via the dictionary's seed URef.",id:"uref-lookup-via-the-dictionarys-seed-uref",level:3},{value:"Dictionary lookup via the unique dictionary item key.",id:"dictionary-lookup-via-the-unique-dictionary-item-key",level:3}],u={toc:p},h="wrapper";function y(e){var t=e.components,n=(0,i.Z)(e,o);return(0,r.kt)(h,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"dictionaries"},"Understanding Dictionaries"),(0,r.kt)("p",null,"In a Casper network, you can now store sets of data under ",(0,r.kt)("a",{parentName:"p",href:"/concepts/hash-types#hash-and-key-explanations"},(0,r.kt)("inlineCode",{parentName:"a"},"Keys")),". Previously, ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/U#uref"},"URefs")," were the exclusive means by which users could store data in global state. To maintain persistent access to these URefs, they would have to be stored within an ",(0,r.kt)("inlineCode",{parentName:"p"},"Account")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"Contract")," context. In the case of Contracts, sustained and continuous use of URefs would result in the expansion of the associated ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/N#namedkeys"},"NamedKeys")," structures."),(0,r.kt)("p",null,"Individual value changes to data stored within the NamedKeys would require deserializing the entire NamedKeys data structure, increasing gas costs over time and thus having a negative impact. Additionally, users storing large subsets of mapped data structures would face the same deep copy problem where minor or single updates required the complete deserialization of the map structure, also leading to increased gas costs."),(0,r.kt)("p",null,"As a solution to this problem, the Casper platform provides the ",(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary")," feature, which allows users a more efficient and scalable means to aggregate data over time."),(0,r.kt)("p",null,"In almost all cases, dictionaries are the better form of data storage. They allow greater flexibility in altering stored data at a lower cost."),(0,r.kt)("h2",{id:"seed-urefs"},"Seed URefs"),(0,r.kt)("p",null,"Items within a dictionary exist as individual records stored underneath their unique ",(0,r.kt)("a",{parentName:"p",href:"/concepts/hash-types#hash-and-key-explanations"},"dictionary address")," in global state. In other words, items associated with a specific dictionary share the same seed ",(0,r.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#uref-head"},(0,r.kt)("inlineCode",{parentName:"a"},"URef"))," but are otherwise independent of each other. Dictionary items are not stored beneath this URef, it is only used to create the dictionary key."),(0,r.kt)("p",null,"As each dictionary item exists as a stand-alone entity in global state, regularly used dictionary keys may be used directly without referencing their seed URef."),(0,r.kt)("h2",{id:"using-dictionaries"},"Using Dictionaries"),(0,r.kt)("p",null,"Dictionaries are ideal for storing larger volumes of data for which ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys")," would be less suitable."),(0,r.kt)("p",null,"Creating a new dictionary is fairly simple and done within the context of a ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," sent to a Casper network. The associated code is included within the ",(0,r.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/"},(0,r.kt)("inlineCode",{parentName:"a"},"casper_contract"))," crate. Creating a dictionary also stores the associated seed URef within the named keys of the current context."),(0,r.kt)("p",null,"Developers should always consider context when creating dictionaries. We recommend creating a dictionary within the context of a Contract."),(0,r.kt)("p",null,"While you can create a dictionary in the context of an Account and then pass associated access rights to a Contract, this approach can create potential security issues. If a third party uses the Contract, the initiating Account with access rights to the dictionary may be undesirable. To rectify this, you may send an additional ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," removing those access rights, but it is better to create the dictionary within the context of the Contract."),(0,r.kt)("p",null,"Dictionaries allow a contract to store additional data without drastically expanding the size of the ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys")," within their context. If a contract's ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys")," expand too far, they may run into system limitations that would unintentionally disable the contract's functionality."),(0,r.kt)("p",null,"A dictionary item key can be no longer than 64 bytes in length."),(0,r.kt)("h2",{id:"practical-dictionary-examples"},"Practical Dictionary Examples"),(0,r.kt)("p",null,"The ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep-78-enhanced-nft"},"Casper CEP-78 Enhanced NFT Standard")," includes several practical applications of dictionaries."),(0,r.kt)("p",null,"Simple examples for dictionary use within CEP-78 include the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep-78-enhanced-nft/blob/dev/contract/src/main.rs#L772"},(0,r.kt)("inlineCode",{parentName:"a"},"approve"))," dictionary."),(0,r.kt)("p",null,"More advanced dictionary functionality can be found in the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep-78-enhanced-nft#the-cep-78-page-system"},"CEP-78 Page System"),", which uses a series of dictionaries to keep track of token ownership. These dictionaries form the basis of the reverse lookup mode, which allows users to easily view a list of owned tokens by account or contract."),(0,r.kt)("h2",{id:"creating-dictionaries-in-a-contracts-context"},"Creating Dictionaries in a Contract's Context"),(0,r.kt)("p",null,"The following code snippet shows the most basic example of creating a dictionary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"\ncasper_contract::contract_api::storage::new_dictionary(dict_name)\n\n")),(0,r.kt)("p",null,"The following example includes the creation of a dictionary ",(0,r.kt)("inlineCode",{parentName:"p"},'"ledger"')," within a contract's context. In this instance, the dictionary will be used to track donations made to a fundraising purse also created by the ",(0,r.kt)("inlineCode",{parentName:"p"},"init")," entry point. In any case where you want to use a dictionary within your contract, it should be set up within the initializing entry point."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'\n#[no_mangle]\npub extern "C" fn init() {\n let fundraising_purse = system::create_purse();\n runtime::put_key("fundraising_purse", fundraising_purse.into());\n // Create a dictionary to track the mapping of account hashes to number of donations made.\n storage::new_dictionary("ledger").unwrap_or_revert();\n}\n\n')),(0,r.kt)("h2",{id:"writing-entries-into-a-dictionary"},"Writing Entries into a Dictionary"),(0,r.kt)("p",null,"After the creation of a dictionary, you may then add entries through the use of the following code:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"\nstorage::dictionary_put(dictionary_uref, &dictionary_item_key, value);\n\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"dictionary_uref")," refers to the seed URef established during the dictionary creation process. The ",(0,r.kt)("inlineCode",{parentName:"p"},"key")," is the unique identifier for this dictionary item, and the ",(0,r.kt)("inlineCode",{parentName:"p"},"value")," is the data to be stored within the dictionary."),(0,r.kt)("p",null,"As stated above, these dictionary items do not require the seed URef, and they exist as individual keys in global state. If you know an individual key's address, you do not need to go through the process of identifying the seed URef first."),(0,r.kt)("p",null,"The following function serves to add an entry to the dictionary. If the item already exists, the entry point will update the value stored and referenced by that key. In this case, the code is storing the number of donations made. Any Rust structure may be stored under a dictionary item, but when updating a value within a larger structure (i.e., a list), the entire structure will be overwritten as part of the update. Updating a larger structure will incur the full cost of writing the structure to a dictionary item."),(0,r.kt)("p",null,"The first section acquiring the ",(0,r.kt)("inlineCode",{parentName:"p"},"LEDGER")," seed URef to assign the new dictionary item to the proper dictionary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'\nfn update_ledger_record(dictionary_item_key: String) {\n // Acquiring the LEDGER seed URef to properly assign the dictionary item.\n let ledger_seed_uref = *runtime::get_key("ledger")\n .unwrap_or_revert_with(FundRaisingError::MissingLedgerSeedURef)\n .as_uref()\n .unwrap_or_revert();\n\n')),(0,r.kt)("p",null,"The second section uses ",(0,r.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.dictionary_get.html"},(0,r.kt)("inlineCode",{parentName:"a"},"dictionary_get"))," to read an entry within the ",(0,r.kt)("inlineCode",{parentName:"p"},"LEDGER")," dictionary. If the entry does not exist on global state, it will create the entry. If it already exists, the entry is updated with the current value using a ",(0,r.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.dictionary_put.html"},(0,r.kt)("inlineCode",{parentName:"a"},"dictionary_put"))," operation. As stated above, regardless of the size of the change within the entry, the entire dictionary entry will need to be overwritten and will incur the associated cost."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"\n // This identifies an item within the dictionary and either creates or updates the associated value.\n match storage::dictionary_get::(ledger_seed_uref, &dictionary_item_key).unwrap_or_revert()\n {\n None => storage::dictionary_put(ledger_seed_uref, &dictionary_item_key, 1u64),\n Some(current_number_of_donations) => storage::dictionary_put(\n ledger_seed_uref,\n &dictionary_item_key,\n current_number_of_donations + 1u64,\n ),\n }\n}\n\n")),(0,r.kt)("h2",{id:"reading-items-from-a-dictionary-using-the-json-rpc"},"Reading Items from a Dictionary using the JSON-RPC"),(0,r.kt)("p",null,"The Casper platform provides several means of looking up a dictionary item. These means are explained within the ",(0,r.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#dictionaryidentifier"},(0,r.kt)("inlineCode",{parentName:"a"},"DictionaryIdentifier"))," JSON-RPC type. The following explains how to query the dictionary items using the ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/casper-client"},"Casper client"),"."),(0,r.kt)("h3",{id:"contractnamedkey-lookup-via-a-contracts-named-keys"},(0,r.kt)("inlineCode",{parentName:"h3"},"ContractNamedKey")," lookup via a Contract's named keys."),(0,r.kt)("p",null,"Reading a dictionary item using the Contract's ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys")," requires the following parameters:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"Node Address")," - The IP and port of a node on a Casper network. In the example below, the node address is pointing to a local NCTL network.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"State Root Hash")," - The current state root hash of a Casper network hosting the dictionary item you are attempting to read.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"Contract Hash")," - The hash of the contract that references the dictionary in its ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys"),".")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary Name")," - The name of the dictionary as a ",(0,r.kt)("inlineCode",{parentName:"p"},"String")," stored in the Contract's ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys"),".")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary Item Key")," - The specific dictionary item key to be read, as a ",(0,r.kt)("inlineCode",{parentName:"p"},"String"),"."))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"\ncasper-client get-dictionary-item \\\n --node-address http://localhost:11101 \\\n --state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \\\n --contract-hash hash-09c8fa7c1441ae7c1cbe27ae3a722fd4ffc5290315f8546454454c1b9f85c842 \\\n --dictionary-name \\\n --dictionary-item-key \n\n")),(0,r.kt)("h3",{id:"uref-lookup-via-the-dictionarys-seed-uref"},(0,r.kt)("inlineCode",{parentName:"h3"},"URef")," lookup via the dictionary's seed URef."),(0,r.kt)("p",null,"Reading a dictionary item using the dictionary's seed URef requires the ",(0,r.kt)("inlineCode",{parentName:"p"},"Node Address"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"State Root Hash")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary Item Key")," as above. However, it does not require the ",(0,r.kt)("inlineCode",{parentName:"p"},"Contract Hash")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary Name"),". Instead, it requires:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"Seed URef")," - The ",(0,r.kt)("a",{parentName:"li",href:"#seed-urefs"},"Seed URef")," of the dictionary to reference.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"\ncasper-client get-dictionary-item \\\n --node-address http://localhost:11101 \\\n --state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \\\n --dictionary-item-key \\\n --seed-uref uref-90b4a8d936b881d3b45b73a102adb2b652181d75c76b7547ae9d1bb213f8db6b-007\n\n")),(0,r.kt)("h3",{id:"dictionary-lookup-via-the-unique-dictionary-item-key"},(0,r.kt)("inlineCode",{parentName:"h3"},"Dictionary")," lookup via the unique dictionary item key."),(0,r.kt)("p",null,"In the event that you know the ",(0,r.kt)("inlineCode",{parentName:"p"},"dictionary address")," of the dictionary item key you need to read, you can read it directly using the following Casper client command."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"\ncasper-client get-dictionary-item \\\n --node-address http://localhost:11101 \\\n --state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \\\n --dictionary-address dictionary-\n\n")))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7157e7af.8c7a2f2d.js b/assets/js/7157e7af.8c7a2f2d.js new file mode 100644 index 0000000000..28b23d84d4 --- /dev/null +++ b/assets/js/7157e7af.8c7a2f2d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9212],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return y}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=a.createContext({}),d=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=d(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=d(n),h=i,y=p["".concat(c,".").concat(h)]||p[h]||u[h]||r;return n?a.createElement(y,o(o({ref:t},l),{},{components:n})):a.createElement(y,o({ref:t},l))}));function y(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:i,o[1]=s;for(var d=2;dContractNamedKey lookup via a Contract's named keys.",id:"contractnamedkey-lookup-via-a-contracts-named-keys",level:3},{value:"URef lookup via the dictionary's seed URef.",id:"uref-lookup-via-the-dictionarys-seed-uref",level:3},{value:"Dictionary lookup via the unique dictionary item key.",id:"dictionary-lookup-via-the-unique-dictionary-item-key",level:3}],u={toc:p},h="wrapper";function y(e){var t=e.components,n=(0,i.Z)(e,o);return(0,r.kt)(h,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"dictionaries"},"Understanding Dictionaries"),(0,r.kt)("p",null,"In a Casper network, you can now store sets of data under ",(0,r.kt)("a",{parentName:"p",href:"/concepts/hash-types#hash-and-key-explanations"},(0,r.kt)("inlineCode",{parentName:"a"},"Keys")),". Previously, ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/U#uref"},"URefs")," were the exclusive means by which users could store data in global state. To maintain persistent access to these URefs, they would have to be stored within an ",(0,r.kt)("inlineCode",{parentName:"p"},"Account")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"Contract")," context. In the case of Contracts, sustained and continuous use of URefs would result in the expansion of the associated ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/N#namedkeys"},"NamedKeys")," structures."),(0,r.kt)("p",null,"Individual value changes to data stored within the NamedKeys would require deserializing the entire NamedKeys data structure, increasing gas costs over time and thus having a negative impact. Additionally, users storing large subsets of mapped data structures would face the same deep copy problem where minor or single updates required the complete deserialization of the map structure, also leading to increased gas costs."),(0,r.kt)("p",null,"As a solution to this problem, the Casper platform provides the ",(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary")," feature, which allows users a more efficient and scalable means to aggregate data over time."),(0,r.kt)("p",null,"In almost all cases, dictionaries are the better form of data storage. They allow greater flexibility in altering stored data at a lower cost."),(0,r.kt)("h2",{id:"seed-urefs"},"Seed URefs"),(0,r.kt)("p",null,"Items within a dictionary exist as individual records stored underneath their unique ",(0,r.kt)("a",{parentName:"p",href:"/concepts/hash-types#hash-and-key-explanations"},"dictionary address")," in global state. In other words, items associated with a specific dictionary share the same seed ",(0,r.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#uref-head"},(0,r.kt)("inlineCode",{parentName:"a"},"URef"))," but are otherwise independent of each other. Dictionary items are not stored beneath this URef, it is only used to create the dictionary key."),(0,r.kt)("p",null,"As each dictionary item exists as a stand-alone entity in global state, regularly used dictionary keys may be used directly without referencing their seed URef."),(0,r.kt)("h2",{id:"using-dictionaries"},"Using Dictionaries"),(0,r.kt)("p",null,"Dictionaries are ideal for storing larger volumes of data for which ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys")," would be less suitable."),(0,r.kt)("p",null,"Creating a new dictionary is fairly simple and done within the context of a ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," sent to a Casper network. The associated code is included within the ",(0,r.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/"},(0,r.kt)("inlineCode",{parentName:"a"},"casper_contract"))," crate. Creating a dictionary also stores the associated seed URef within the named keys of the current context."),(0,r.kt)("p",null,"Developers should always consider context when creating dictionaries. We recommend creating a dictionary within the context of a Contract."),(0,r.kt)("p",null,"While you can create a dictionary in the context of an Account and then pass associated access rights to a Contract, this approach can create potential security issues. If a third party uses the Contract, the initiating Account with access rights to the dictionary may be undesirable. To rectify this, you may send an additional ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," removing those access rights, but it is better to create the dictionary within the context of the Contract."),(0,r.kt)("p",null,"Dictionaries allow a contract to store additional data without drastically expanding the size of the ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys")," within their context. If a contract's ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys")," expand too far, they may run into system limitations that would unintentionally disable the contract's functionality."),(0,r.kt)("p",null,"A dictionary item key can be no longer than 64 bytes in length."),(0,r.kt)("h2",{id:"practical-dictionary-examples"},"Practical Dictionary Examples"),(0,r.kt)("p",null,"The ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep-78-enhanced-nft"},"Casper CEP-78 Enhanced NFT Standard")," includes several practical applications of dictionaries."),(0,r.kt)("p",null,"Simple examples for dictionary use within CEP-78 include the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep-78-enhanced-nft/blob/dev/contract/src/main.rs#L772"},(0,r.kt)("inlineCode",{parentName:"a"},"approve"))," dictionary."),(0,r.kt)("p",null,"More advanced dictionary functionality can be found in the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep-78-enhanced-nft#the-cep-78-page-system"},"CEP-78 Page System"),", which uses a series of dictionaries to keep track of token ownership. These dictionaries form the basis of the reverse lookup mode, which allows users to easily view a list of owned tokens by account or contract."),(0,r.kt)("h2",{id:"creating-dictionaries-in-a-contracts-context"},"Creating Dictionaries in a Contract's Context"),(0,r.kt)("p",null,"The following code snippet shows the most basic example of creating a dictionary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"\ncasper_contract::contract_api::storage::new_dictionary(dict_name)\n\n")),(0,r.kt)("p",null,"The following example includes the creation of a dictionary ",(0,r.kt)("inlineCode",{parentName:"p"},'"ledger"')," within a contract's context. In this instance, the dictionary will be used to track donations made to a fundraising purse also created by the ",(0,r.kt)("inlineCode",{parentName:"p"},"init")," entry point. In any case where you want to use a dictionary within your contract, it should be set up within the initializing entry point."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'\n#[no_mangle]\npub extern "C" fn init() {\n let fundraising_purse = system::create_purse();\n runtime::put_key("fundraising_purse", fundraising_purse.into());\n // Create a dictionary to track the mapping of account hashes to number of donations made.\n storage::new_dictionary("ledger").unwrap_or_revert();\n}\n\n')),(0,r.kt)("h2",{id:"writing-entries-into-a-dictionary"},"Writing Entries into a Dictionary"),(0,r.kt)("p",null,"After the creation of a dictionary, you may then add entries through the use of the following code:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"\nstorage::dictionary_put(dictionary_uref, &dictionary_item_key, value);\n\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"dictionary_uref")," refers to the seed URef established during the dictionary creation process. The ",(0,r.kt)("inlineCode",{parentName:"p"},"key")," is the unique identifier for this dictionary item, and the ",(0,r.kt)("inlineCode",{parentName:"p"},"value")," is the data to be stored within the dictionary."),(0,r.kt)("p",null,"As stated above, these dictionary items do not require the seed URef, and they exist as individual keys in global state. If you know an individual key's address, you do not need to go through the process of identifying the seed URef first."),(0,r.kt)("p",null,"The following function serves to add an entry to the dictionary. If the item already exists, the entry point will update the value stored and referenced by that key. In this case, the code is storing the number of donations made. Any Rust structure may be stored under a dictionary item, but when updating a value within a larger structure (i.e., a list), the entire structure will be overwritten as part of the update. Updating a larger structure will incur the full cost of writing the structure to a dictionary item."),(0,r.kt)("p",null,"The first section acquiring the ",(0,r.kt)("inlineCode",{parentName:"p"},"LEDGER")," seed URef to assign the new dictionary item to the proper dictionary."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'\nfn update_ledger_record(dictionary_item_key: String) {\n // Acquiring the LEDGER seed URef to properly assign the dictionary item.\n let ledger_seed_uref = *runtime::get_key("ledger")\n .unwrap_or_revert_with(FundRaisingError::MissingLedgerSeedURef)\n .as_uref()\n .unwrap_or_revert();\n\n')),(0,r.kt)("p",null,"The second section uses ",(0,r.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.dictionary_get.html"},(0,r.kt)("inlineCode",{parentName:"a"},"dictionary_get"))," to read an entry within the ",(0,r.kt)("inlineCode",{parentName:"p"},"LEDGER")," dictionary. If the entry does not exist on global state, it will create the entry. If it already exists, the entry is updated with the current value using a ",(0,r.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.dictionary_put.html"},(0,r.kt)("inlineCode",{parentName:"a"},"dictionary_put"))," operation. As stated above, regardless of the size of the change within the entry, the entire dictionary entry will need to be overwritten and will incur the associated cost."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},"\n // This identifies an item within the dictionary and either creates or updates the associated value.\n match storage::dictionary_get::(ledger_seed_uref, &dictionary_item_key).unwrap_or_revert()\n {\n None => storage::dictionary_put(ledger_seed_uref, &dictionary_item_key, 1u64),\n Some(current_number_of_donations) => storage::dictionary_put(\n ledger_seed_uref,\n &dictionary_item_key,\n current_number_of_donations + 1u64,\n ),\n }\n}\n\n")),(0,r.kt)("h2",{id:"reading-items-from-a-dictionary-using-the-json-rpc"},"Reading Items from a Dictionary using the JSON-RPC"),(0,r.kt)("p",null,"The Casper platform provides several means of looking up a dictionary item. These means are explained within the ",(0,r.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#dictionaryidentifier"},(0,r.kt)("inlineCode",{parentName:"a"},"DictionaryIdentifier"))," JSON-RPC type. The following explains how to query the dictionary items using the ",(0,r.kt)("a",{parentName:"p",href:"https://crates.io/crates/casper-client"},"Casper client"),"."),(0,r.kt)("h3",{id:"contractnamedkey-lookup-via-a-contracts-named-keys"},(0,r.kt)("inlineCode",{parentName:"h3"},"ContractNamedKey")," lookup via a Contract's named keys."),(0,r.kt)("p",null,"Reading a dictionary item using the Contract's ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys")," requires the following parameters:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"Node Address")," - The IP and port of a node on a Casper network. In the example below, the node address is pointing to a local NCTL network.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"State Root Hash")," - The current state root hash of a Casper network hosting the dictionary item you are attempting to read.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"Contract Hash")," - The hash of the contract that references the dictionary in its ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys"),".")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary Name")," - The name of the dictionary as a ",(0,r.kt)("inlineCode",{parentName:"p"},"String")," stored in the Contract's ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys"),".")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary Item Key")," - The specific dictionary item key to be read, as a ",(0,r.kt)("inlineCode",{parentName:"p"},"String"),"."))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"\ncasper-client get-dictionary-item \\\n --node-address http://localhost:11101 \\\n --state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \\\n --contract-hash hash-09c8fa7c1441ae7c1cbe27ae3a722fd4ffc5290315f8546454454c1b9f85c842 \\\n --dictionary-name \\\n --dictionary-item-key \n\n")),(0,r.kt)("h3",{id:"uref-lookup-via-the-dictionarys-seed-uref"},(0,r.kt)("inlineCode",{parentName:"h3"},"URef")," lookup via the dictionary's seed URef."),(0,r.kt)("p",null,"Reading a dictionary item using the dictionary's seed URef requires the ",(0,r.kt)("inlineCode",{parentName:"p"},"Node Address"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"State Root Hash")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary Item Key")," as above. However, it does not require the ",(0,r.kt)("inlineCode",{parentName:"p"},"Contract Hash")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"Dictionary Name"),". Instead, it requires:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"Seed URef")," - The ",(0,r.kt)("a",{parentName:"li",href:"#seed-urefs"},"Seed URef")," of the dictionary to reference.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"\ncasper-client get-dictionary-item \\\n --node-address http://localhost:11101 \\\n --state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \\\n --dictionary-item-key \\\n --seed-uref uref-90b4a8d936b881d3b45b73a102adb2b652181d75c76b7547ae9d1bb213f8db6b-007\n\n")),(0,r.kt)("h3",{id:"dictionary-lookup-via-the-unique-dictionary-item-key"},(0,r.kt)("inlineCode",{parentName:"h3"},"Dictionary")," lookup via the unique dictionary item key."),(0,r.kt)("p",null,"In the event that you know the ",(0,r.kt)("inlineCode",{parentName:"p"},"dictionary address")," of the dictionary item key you need to read, you can read it directly using the following Casper client command."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"\ncasper-client get-dictionary-item \\\n --node-address http://localhost:11101 \\\n --state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \\\n --dictionary-address dictionary-\n\n")))}y.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/71c4e358.4e82d2d4.js b/assets/js/71c4e358.6a76edb9.js similarity index 52% rename from assets/js/71c4e358.4e82d2d4.js rename to assets/js/71c4e358.6a76edb9.js index 2c9821c691..1af5712317 100644 --- a/assets/js/71c4e358.4e82d2d4.js +++ b/assets/js/71c4e358.6a76edb9.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7080],{3905:function(e,t,r){r.d(t,{Zo:function(){return i},kt:function(){return m}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),y=a,m=u["".concat(p,".").concat(y)]||u[y]||f[y]||o;return r?n.createElement(m,s(s({ref:t},i),{},{components:r})):n.createElement(m,s({ref:t},i))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),y=a,m=u["".concat(p,".").concat(y)]||u[y]||f[y]||o;return r?n.createElement(m,s(s({ref:t},i),{},{components:r})):n.createElement(m,s({ref:t},i))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),l=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",_={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,i=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,d=u["".concat(i,".").concat(h)]||u[h]||_[h]||s;return n?a.createElement(d,c(c({ref:t},p),{},{components:n})):a.createElement(d,c({ref:t},p))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,c=new Array(s);c[0]=h;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[u]="string"==typeof e?e:r,c[1]=o;for(var l=2;l (InMemoryWasmTestBuilder, TestContext) {\n setup_with_args(runtime_args! {\n ARG_NAME => TOKEN_NAME,\n ARG_SYMBOL => TOKEN_SYMBOL,\n ARG_DECIMALS => TOKEN_DECIMALS,\n ARG_TOTAL_SUPPLY => U256::from(TOKEN_TOTAL_SUPPLY),\n })\n}\n\n// Establishing test accounts.\n\npub(crate) fn setup_with_args(install_args: RuntimeArgs) -> (InMemoryWasmTestBuilder, TestContext) {\n let mut builder = InMemoryWasmTestBuilder::default();\n builder.run_genesis(&PRODUCTION_RUN_GENESIS_REQUEST);\n\n let id: Option = None;\n let transfer_1_args = runtime_args! {\n mint::ARG_TARGET => *ACCOUNT_1_ADDR,\n mint::ARG_AMOUNT => MINIMUM_ACCOUNT_CREATION_BALANCE,\n mint::ARG_ID => id,\n };\n let transfer_2_args = runtime_args! {\n mint::ARG_TARGET => *ACCOUNT_2_ADDR,\n mint::ARG_AMOUNT => MINIMUM_ACCOUNT_CREATION_BALANCE,\n mint::ARG_ID => id,\n };\n\n let transfer_request_1 =\n ExecuteRequestBuilder::transfer(*DEFAULT_ACCOUNT_ADDR, transfer_1_args).build();\n let transfer_request_2 =\n ExecuteRequestBuilder::transfer(*DEFAULT_ACCOUNT_ADDR, transfer_2_args).build();\n\n // Installing the test version of CEP-18 with the default account.\n\n let install_request_1 =\n ExecuteRequestBuilder::standard(*DEFAULT_ACCOUNT_ADDR, CEP18_CONTRACT_WASM, install_args)\n .build();\n\n let install_request_2 = ExecuteRequestBuilder::standard(\n *DEFAULT_ACCOUNT_ADDR,\n CEP18_TEST_CONTRACT_WASM,\n RuntimeArgs::default(),\n )\n .build();\n\n builder.exec(transfer_request_1).expect_success().commit();\n builder.exec(transfer_request_2).expect_success().commit();\n builder.exec(install_request_1).expect_success().commit();\n builder.exec(install_request_2).expect_success().commit();\n\n let account = builder\n .get_account(*DEFAULT_ACCOUNT_ADDR)\n .expect("should have account");\n\n let cep18_token = account\n .named_keys()\n .get(CEP18_TOKEN_CONTRACT_KEY)\n .and_then(|key| key.into_hash())\n .map(ContractHash::new)\n .expect("should have contract hash");\n\n let cep18_test_contract_package = account\n .named_keys()\n .get(CEP18_TEST_CONTRACT_KEY)\n .and_then(|key| key.into_hash())\n .map(ContractPackageHash::new)\n .expect("should have contract package hash");\n\n let test_context = TestContext {\n cep18_token,\n cep18_test_contract_package,\n };\n\n (builder, test_context)\n}\n'))),(0,s.kt)("h3",{id:"creating-helper-functions"},"Creating Helper Functions"),(0,s.kt)("p",null,"The previous step has simulated sending a real deploy on the network. The next code snippet in ",(0,s.kt)("inlineCode",{parentName:"p"},"installer_request_builders.rs")," defines helper functions that will be used throughout the testing framework:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cep18_check_total_supply")," - A function for testing the total supply of the CEP-18 contract instance."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cep18_check_balance_of")," - A function for checking an account's balance of CEP-18 tokens."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cep18_check_allowance_of")," - A function for checking an account's spending allowance from another account's balance.")),(0,s.kt)("p",null,"These are followed by functions that check specific aspects of the CEP-18 contract. These include ",(0,s.kt)("inlineCode",{parentName:"p"},"test_cep18_transfer"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"make_cep18_approve_request")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"test_approve_for"),"."),(0,s.kt)("p",null,"The following code snippet is an example function that tests the ability to transfer CEP-18 tokens from the default address to the two other addresses established in ",(0,s.kt)("a",{parentName:"p",href:"#installing-the-contract-deploying-the-contract"},"contract installation"),":"),(0,s.kt)("details",null,(0,s.kt)("summary",null,"Example helper function"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"// File https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/utility/installer_request_builders.rs\n\npub(crate) fn test_cep18_transfer(\n builder: &mut InMemoryWasmTestBuilder,\n test_context: &TestContext,\n sender1: Key,\n recipient1: Key,\n sender2: Key,\n recipient2: Key) {\n let TestContext { cep18_token, .. } = test_context;\n\n // Defining the amount to be transferred to each account.\n\n let transfer_amount_1 = U256::from(TRANSFER_AMOUNT_1);\n let transfer_amount_2 = U256::from(TRANSFER_AMOUNT_2);\n\n // Checking the pre-existing balances of the default address and the two receiving addresses.\n\n let sender_balance_before = cep18_check_balance_of(builder, cep18_token, sender1);\n assert_ne!(sender_balance_before, U256::zero());\n\n let account_1_balance_before = cep18_check_balance_of(builder, cep18_token, recipient1);\n assert_eq!(account_1_balance_before, U256::zero());\n\n let account_2_balance_before = cep18_check_balance_of(builder, cep18_token, recipient1);\n assert_eq!(account_2_balance_before, U256::zero());\n\n // Creating the first transfer request.\n\n let token_transfer_request_1 =\n make_cep18_transfer_request(sender1, cep18_token, recipient1, transfer_amount_1);\n\n builder\n .exec(token_transfer_request_1)\n .expect_success()\n .commit();\n\n // Checking the prior balance against the new balance to ensure the transfer occurred correctly.\n\n let account_1_balance_after = cep18_check_balance_of(builder, cep18_token, recipient1);\n assert_eq!(account_1_balance_after, transfer_amount_1);\n let account_1_balance_before = account_1_balance_after;\n\n let sender_balance_after = cep18_check_balance_of(builder, cep18_token, sender1);\n assert_eq!(\n sender_balance_after,\n sender_balance_before - transfer_amount_1\n );\n let sender_balance_before = sender_balance_after;\n\n // Creating the second transfer request.\n\n let token_transfer_request_2 =\n make_cep18_transfer_request(sender2, cep18_token, recipient2, transfer_amount_2);\n\n builder\n .exec(token_transfer_request_2)\n .expect_success()\n .commit();\n\n // Checking prior balances against new balances.\n\n let sender_balance_after = cep18_check_balance_of(builder, cep18_token, sender1);\n assert_eq!(sender_balance_after, sender_balance_before);\n\n let account_1_balance_after = cep18_check_balance_of(builder, cep18_token, recipient1);\n assert!(account_1_balance_after < account_1_balance_before);\n assert_eq!(\n account_1_balance_after,\n transfer_amount_1 - transfer_amount_2\n );\n\n let account_2_balance_after = cep18_check_balance_of(builder, cep18_token, recipient2);\n assert_eq!(account_2_balance_after, transfer_amount_2);\n}\n"))),(0,s.kt)("h2",{id:"creating-unit-tests"},"Creating Unit Tests"),(0,s.kt)("p",null,"Within this testing context, the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/tree/dev/tests/src"},(0,s.kt)("inlineCode",{parentName:"a"},"tests")," directory")," includes a variety of unit tests, which verify the contract code by invoking the functions defined in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/utility/installer_request_builders.rs"},"installer_request_builders.rs")," file."),(0,s.kt)("p",null,"The example below shows one of the tests. Visit ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/tree/dev/tests/src"},"GitHub")," to find all the available tests."),(0,s.kt)("details",null,(0,s.kt)("summary",null,"Example test querying token properties"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"// File https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/install.rs\n\nuse casper_engine_test_support::DEFAULT_ACCOUNT_ADDR;\nuse casper_types::{Key, U256};\n\nuse crate::utility::{\n constants::{\n ALLOWANCES_KEY, BALANCES_KEY, DECIMALS_KEY, NAME_KEY, SYMBOL_KEY, TOKEN_DECIMALS,\n TOKEN_NAME, TOKEN_SYMBOL, TOKEN_TOTAL_SUPPLY, TOTAL_SUPPLY_KEY,\n },\n installer_request_builders::{\n cep18_check_balance_of, invert_cep18_address, setup, TestContext,\n },\n};\n\n#[test]\nfn should_have_queryable_properties() {\n let (mut builder, TestContext { cep18_token, .. }) = setup();\n\n let name: String = builder.get_value(cep18_token, NAME_KEY);\n assert_eq!(name, TOKEN_NAME);\n\n let symbol: String = builder.get_value(cep18_token, SYMBOL_KEY);\n assert_eq!(symbol, TOKEN_SYMBOL);\n\n let decimals: u8 = builder.get_value(cep18_token, DECIMALS_KEY);\n assert_eq!(decimals, TOKEN_DECIMALS);\n\n let total_supply: U256 = builder.get_value(cep18_token, TOTAL_SUPPLY_KEY);\n assert_eq!(total_supply, U256::from(TOKEN_TOTAL_SUPPLY));\n\n let owner_key = Key::Account(*DEFAULT_ACCOUNT_ADDR);\n\n let owner_balance = cep18_check_balance_of(&mut builder, &cep18_token, owner_key);\n assert_eq!(owner_balance, total_supply);\n\n let contract_balance =\n cep18_check_balance_of(&mut builder, &cep18_token, Key::Hash(cep18_token.value()));\n assert_eq!(contract_balance, U256::zero());\n\n // Ensures that Account and Contract ownership is respected and we're not keying ownership under\n // the raw bytes regardless of variant.\n let inverted_owner_key = invert_cep18_address(owner_key);\n let inverted_owner_balance =\n cep18_check_balance_of(&mut builder, &cep18_token, inverted_owner_key);\n assert_eq!(inverted_owner_balance, U256::zero());\n}\n"))),(0,s.kt)("h2",{id:"running-the-tests"},"Running the Tests"),(0,s.kt)("p",null,"The ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/lib.rs"},"lib.rs")," file is configured to run the example integration tests via the ",(0,s.kt)("inlineCode",{parentName:"p"},"make test")," command:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"#[cfg(test)]\nmod allowance;\n#[cfg(test)]\nmod install;\n#[cfg(test)]\nmod mint_and_burn;\n#[cfg(test)]\nmod transfer;\n#[cfg(test)]\nmod utility;\n")),(0,s.kt)("p",null,"To run the tests, navigate to the parent ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18"},"cep18 directory")," and run the command:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"make test\n")),(0,s.kt)("p",null,"This example uses ",(0,s.kt)("inlineCode",{parentName:"p"},"bash"),". If you are using a Rust IDE, you need to configure it to run the tests."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/71e073ea.e55ea1bc.js b/assets/js/71e073ea.e55ea1bc.js new file mode 100644 index 0000000000..60514252cd --- /dev/null +++ b/assets/js/71e073ea.e55ea1bc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7059],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return d}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function c(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),l=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",_={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,i=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,d=u["".concat(i,".").concat(h)]||u[h]||_[h]||s;return n?a.createElement(d,c(c({ref:t},p),{},{components:n})):a.createElement(d,c({ref:t},p))}));function d(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,c=new Array(s);c[0]=h;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[u]="string"==typeof e?e:r,c[1]=o;for(var l=2;l (InMemoryWasmTestBuilder, TestContext) {\n setup_with_args(runtime_args! {\n ARG_NAME => TOKEN_NAME,\n ARG_SYMBOL => TOKEN_SYMBOL,\n ARG_DECIMALS => TOKEN_DECIMALS,\n ARG_TOTAL_SUPPLY => U256::from(TOKEN_TOTAL_SUPPLY),\n })\n}\n\n// Establishing test accounts.\n\npub(crate) fn setup_with_args(install_args: RuntimeArgs) -> (InMemoryWasmTestBuilder, TestContext) {\n let mut builder = InMemoryWasmTestBuilder::default();\n builder.run_genesis(&PRODUCTION_RUN_GENESIS_REQUEST);\n\n let id: Option = None;\n let transfer_1_args = runtime_args! {\n mint::ARG_TARGET => *ACCOUNT_1_ADDR,\n mint::ARG_AMOUNT => MINIMUM_ACCOUNT_CREATION_BALANCE,\n mint::ARG_ID => id,\n };\n let transfer_2_args = runtime_args! {\n mint::ARG_TARGET => *ACCOUNT_2_ADDR,\n mint::ARG_AMOUNT => MINIMUM_ACCOUNT_CREATION_BALANCE,\n mint::ARG_ID => id,\n };\n\n let transfer_request_1 =\n ExecuteRequestBuilder::transfer(*DEFAULT_ACCOUNT_ADDR, transfer_1_args).build();\n let transfer_request_2 =\n ExecuteRequestBuilder::transfer(*DEFAULT_ACCOUNT_ADDR, transfer_2_args).build();\n\n // Installing the test version of CEP-18 with the default account.\n\n let install_request_1 =\n ExecuteRequestBuilder::standard(*DEFAULT_ACCOUNT_ADDR, CEP18_CONTRACT_WASM, install_args)\n .build();\n\n let install_request_2 = ExecuteRequestBuilder::standard(\n *DEFAULT_ACCOUNT_ADDR,\n CEP18_TEST_CONTRACT_WASM,\n RuntimeArgs::default(),\n )\n .build();\n\n builder.exec(transfer_request_1).expect_success().commit();\n builder.exec(transfer_request_2).expect_success().commit();\n builder.exec(install_request_1).expect_success().commit();\n builder.exec(install_request_2).expect_success().commit();\n\n let account = builder\n .get_account(*DEFAULT_ACCOUNT_ADDR)\n .expect("should have account");\n\n let cep18_token = account\n .named_keys()\n .get(CEP18_TOKEN_CONTRACT_KEY)\n .and_then(|key| key.into_hash())\n .map(ContractHash::new)\n .expect("should have contract hash");\n\n let cep18_test_contract_package = account\n .named_keys()\n .get(CEP18_TEST_CONTRACT_KEY)\n .and_then(|key| key.into_hash())\n .map(ContractPackageHash::new)\n .expect("should have contract package hash");\n\n let test_context = TestContext {\n cep18_token,\n cep18_test_contract_package,\n };\n\n (builder, test_context)\n}\n'))),(0,s.kt)("h3",{id:"creating-helper-functions"},"Creating Helper Functions"),(0,s.kt)("p",null,"The previous step has simulated sending a real deploy on the network. The next code snippet in ",(0,s.kt)("inlineCode",{parentName:"p"},"installer_request_builders.rs")," defines helper functions that will be used throughout the testing framework:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cep18_check_total_supply")," - A function for testing the total supply of the CEP-18 contract instance."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cep18_check_balance_of")," - A function for checking an account's balance of CEP-18 tokens."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cep18_check_allowance_of")," - A function for checking an account's spending allowance from another account's balance.")),(0,s.kt)("p",null,"These are followed by functions that check specific aspects of the CEP-18 contract. These include ",(0,s.kt)("inlineCode",{parentName:"p"},"test_cep18_transfer"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"make_cep18_approve_request")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"test_approve_for"),"."),(0,s.kt)("p",null,"The following code snippet is an example function that tests the ability to transfer CEP-18 tokens from the default address to the two other addresses established in ",(0,s.kt)("a",{parentName:"p",href:"#installing-the-contract-deploying-the-contract"},"contract installation"),":"),(0,s.kt)("details",null,(0,s.kt)("summary",null,"Example helper function"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"// File https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/utility/installer_request_builders.rs\n\npub(crate) fn test_cep18_transfer(\n builder: &mut InMemoryWasmTestBuilder,\n test_context: &TestContext,\n sender1: Key,\n recipient1: Key,\n sender2: Key,\n recipient2: Key) {\n let TestContext { cep18_token, .. } = test_context;\n\n // Defining the amount to be transferred to each account.\n\n let transfer_amount_1 = U256::from(TRANSFER_AMOUNT_1);\n let transfer_amount_2 = U256::from(TRANSFER_AMOUNT_2);\n\n // Checking the pre-existing balances of the default address and the two receiving addresses.\n\n let sender_balance_before = cep18_check_balance_of(builder, cep18_token, sender1);\n assert_ne!(sender_balance_before, U256::zero());\n\n let account_1_balance_before = cep18_check_balance_of(builder, cep18_token, recipient1);\n assert_eq!(account_1_balance_before, U256::zero());\n\n let account_2_balance_before = cep18_check_balance_of(builder, cep18_token, recipient1);\n assert_eq!(account_2_balance_before, U256::zero());\n\n // Creating the first transfer request.\n\n let token_transfer_request_1 =\n make_cep18_transfer_request(sender1, cep18_token, recipient1, transfer_amount_1);\n\n builder\n .exec(token_transfer_request_1)\n .expect_success()\n .commit();\n\n // Checking the prior balance against the new balance to ensure the transfer occurred correctly.\n\n let account_1_balance_after = cep18_check_balance_of(builder, cep18_token, recipient1);\n assert_eq!(account_1_balance_after, transfer_amount_1);\n let account_1_balance_before = account_1_balance_after;\n\n let sender_balance_after = cep18_check_balance_of(builder, cep18_token, sender1);\n assert_eq!(\n sender_balance_after,\n sender_balance_before - transfer_amount_1\n );\n let sender_balance_before = sender_balance_after;\n\n // Creating the second transfer request.\n\n let token_transfer_request_2 =\n make_cep18_transfer_request(sender2, cep18_token, recipient2, transfer_amount_2);\n\n builder\n .exec(token_transfer_request_2)\n .expect_success()\n .commit();\n\n // Checking prior balances against new balances.\n\n let sender_balance_after = cep18_check_balance_of(builder, cep18_token, sender1);\n assert_eq!(sender_balance_after, sender_balance_before);\n\n let account_1_balance_after = cep18_check_balance_of(builder, cep18_token, recipient1);\n assert!(account_1_balance_after < account_1_balance_before);\n assert_eq!(\n account_1_balance_after,\n transfer_amount_1 - transfer_amount_2\n );\n\n let account_2_balance_after = cep18_check_balance_of(builder, cep18_token, recipient2);\n assert_eq!(account_2_balance_after, transfer_amount_2);\n}\n"))),(0,s.kt)("h2",{id:"creating-unit-tests"},"Creating Unit Tests"),(0,s.kt)("p",null,"Within this testing context, the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/tree/dev/tests/src"},(0,s.kt)("inlineCode",{parentName:"a"},"tests")," directory")," includes a variety of unit tests, which verify the contract code by invoking the functions defined in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/utility/installer_request_builders.rs"},"installer_request_builders.rs")," file."),(0,s.kt)("p",null,"The example below shows one of the tests. Visit ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/tree/dev/tests/src"},"GitHub")," to find all the available tests."),(0,s.kt)("details",null,(0,s.kt)("summary",null,"Example test querying token properties"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"// File https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/install.rs\n\nuse casper_engine_test_support::DEFAULT_ACCOUNT_ADDR;\nuse casper_types::{Key, U256};\n\nuse crate::utility::{\n constants::{\n ALLOWANCES_KEY, BALANCES_KEY, DECIMALS_KEY, NAME_KEY, SYMBOL_KEY, TOKEN_DECIMALS,\n TOKEN_NAME, TOKEN_SYMBOL, TOKEN_TOTAL_SUPPLY, TOTAL_SUPPLY_KEY,\n },\n installer_request_builders::{\n cep18_check_balance_of, invert_cep18_address, setup, TestContext,\n },\n};\n\n#[test]\nfn should_have_queryable_properties() {\n let (mut builder, TestContext { cep18_token, .. }) = setup();\n\n let name: String = builder.get_value(cep18_token, NAME_KEY);\n assert_eq!(name, TOKEN_NAME);\n\n let symbol: String = builder.get_value(cep18_token, SYMBOL_KEY);\n assert_eq!(symbol, TOKEN_SYMBOL);\n\n let decimals: u8 = builder.get_value(cep18_token, DECIMALS_KEY);\n assert_eq!(decimals, TOKEN_DECIMALS);\n\n let total_supply: U256 = builder.get_value(cep18_token, TOTAL_SUPPLY_KEY);\n assert_eq!(total_supply, U256::from(TOKEN_TOTAL_SUPPLY));\n\n let owner_key = Key::Account(*DEFAULT_ACCOUNT_ADDR);\n\n let owner_balance = cep18_check_balance_of(&mut builder, &cep18_token, owner_key);\n assert_eq!(owner_balance, total_supply);\n\n let contract_balance =\n cep18_check_balance_of(&mut builder, &cep18_token, Key::Hash(cep18_token.value()));\n assert_eq!(contract_balance, U256::zero());\n\n // Ensures that Account and Contract ownership is respected and we're not keying ownership under\n // the raw bytes regardless of variant.\n let inverted_owner_key = invert_cep18_address(owner_key);\n let inverted_owner_balance =\n cep18_check_balance_of(&mut builder, &cep18_token, inverted_owner_key);\n assert_eq!(inverted_owner_balance, U256::zero());\n}\n"))),(0,s.kt)("h2",{id:"running-the-tests"},"Running the Tests"),(0,s.kt)("p",null,"The ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/lib.rs"},"lib.rs")," file is configured to run the example integration tests via the ",(0,s.kt)("inlineCode",{parentName:"p"},"make test")," command:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"#[cfg(test)]\nmod allowance;\n#[cfg(test)]\nmod install;\n#[cfg(test)]\nmod mint_and_burn;\n#[cfg(test)]\nmod transfer;\n#[cfg(test)]\nmod utility;\n")),(0,s.kt)("p",null,"To run the tests, navigate to the parent ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18"},"cep18 directory")," and run the command:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"make test\n")),(0,s.kt)("p",null,"This example uses ",(0,s.kt)("inlineCode",{parentName:"p"},"bash"),". If you are using a Rust IDE, you need to configure it to run the tests."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/72301f79.00a85676.js b/assets/js/72301f79.00a85676.js deleted file mode 100644 index c0a11b371c..0000000000 --- a/assets/js/72301f79.00a85676.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4970],{3905:function(e,n,t){t.d(n,{Zo:function(){return d},kt:function(){return m}});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function c(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var i=a.createContext({}),l=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},d=function(e){var n=l(e.components);return a.createElement(i.Provider,{value:n},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},u=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=l(t),u=r,m=p["".concat(i,".").concat(u)]||p[u]||h[u]||o;return t?a.createElement(m,c(c({ref:n},d),{},{components:t})):a.createElement(m,c({ref:n},d))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,c=new Array(o);c[0]=u;var s={};for(var i in n)hasOwnProperty.call(n,i)&&(s[i]=n[i]);s.originalType=e,s[p]="string"==typeof e?e:r,c[1]=s;for(var l=2;l = BTreeMap::new();\n\n // Insert the new value into the named keys\n named_keys.insert(String::from("message"),value_ref.into()); // use into to wrap the Uref into a casper_types::Key\n // Create a new vector\n let mut params = Vec::new();\n vec.push(Parameter::new("message", CLType::String));\n\n // Create an Entry Point Object\n let mut entry_points = EntryPoints::new();\n\n // Describing the metadata for the entry point\n entry_points.add_entry_point(EntryPoint::new(\n "update_msg", // the name of the entry point\n vec, // the arguments which can be passed into the entry point\n CLType::Unit, // return type of the entry point\n EntryPointAccess::Public, // access permissions - public can be accessed always\n EntryPointType::Contract // in most cases it will be contract\n ));\n\n // The contract is stored in the global state\n let (stored_contract_hash, _contract_version) = storage::new_contract(\n entry_points, // entry points\n Some(named_keys), // named keys\n Some("Hello_world_package_name".to_string()), // package name\n Some("Hello_world_access_uref".to_string()) // access uref\n );\n\n // To access the contract hash from the accounts named keys\n runtime::put_key("hello_world_contract", stored_contract_hash.into());\n\n}\n')),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"runtime")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"storage")," appear frequently in our code. If these terms are unfamiliar to you, you should familiarize yourself with the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/index.html"},"Contract API Modules"),".")),(0,o.kt)("p",null,"The metadata for each of the contract's entry points is defined in the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point. When installing the contract, the system will look for the name of the entry point as specified by the metadata for that entry point. Therefore, each of the entry points defined in the code must share the same name as the ",(0,o.kt)("inlineCode",{parentName:"p"},"String")," value passed when defining the metadata for the entry point."),(0,o.kt)("p",null,"The #","[no_mangle]"," flag ensures that the compiler does not modify the name of the entry point. The compiler will not enforce the condition that the name of the entry point is the same value present in its metadata definition, therefore the developer must be careful when defining their entry points."),(0,o.kt)("p",null,"In our case, we will define the entry point ",(0,o.kt)("inlineCode",{parentName:"p"},"update_msg")," in the contract code just before ",(0,o.kt)("inlineCode",{parentName:"p"},"call"),"."),(0,o.kt)("p",null,"Your complete contract should match the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'#![no_std]\n#![no_main]\n\n#[cfg(not(target_arch = "wasm32"))]\ncompile_error!("target arch should be wasm32: compile with \'--target wasm32-unknown-unknown\'");\n\n// We need to explicitly import the std alloc crate and `alloc::string::String` as we are in a\n// `no_std` environment.\nextern crate alloc;\n\n// The elementary types\nuse alloc::string::String;\nuse alloc::vec::Vec;\nuse alloc::collections::BTreeMap;\nuse crate::alloc::string::ToString;\n\n\n// Casper crates\nuse casper_types::{Key, CLType, Parameter, EntryPoint, EntryPoints, EntryPointType, EntryPointAccess};\n\nuse casper_contract::{\n contract_api::{runtime, storage},\n unwrap_or_revert::UnwrapOrRevert,\n};\n\n#[no_mangle]\npub extern "C" fn update_msg() {\n\n let value: String = runtime::get_named_arg("message");\n // Get the uref of the message stored in global state\n let uref = runtime::get_key("message").unwrap_or_revert().into_uref().unwrap_or_revert();\n // Write the message to global state\n storage::write(uref, String::from(value));\n}\n\n\n#[no_mangle]\npub extern "C" fn call() {\n // Get the value of a passed parameter with the key "message"\n let value: String = runtime::get_named_arg("message");\n // The value will be wraped in a URef\n let value_ref = storage::new_uref(value);\n // Creating the new set of named keys\n // The keys are a Map of Key/Value\n let mut named_keys: BTreeMap = BTreeMap::new();\n // Insert the new value into the named keys\n named_keys.insert(String::from("message"),value_ref.into()); // use into to wrap the value to the key\n // Create a new vector\n let mut vec = Vec::new();\n vec.push(Parameter::new("message", CLType::String));\n // Create an Entry Point Object\n let mut entry_points = EntryPoints::new();\n\n // Define the metadata for the entry point `update_msg`\n entry_points.add_entry_point(EntryPoint::new(\n "update_msg",\n vec,\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract\n ));\n\n // The contract is stored in the global state\n let (stored_contract_hash, _contract_version) = storage::new_contract(\n entry_points, // entry points metadata\n Some(named_keys), // named keys\n Some("Hello_world_package_name".to_string()), // package name\n Some("Hello_world_access_uref".to_string()) // access uref\n );\n\n // To access from the account - named keys of the account\n runtime::put_key("hello_world_contract", stored_contract_hash.into());\n}\n')),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"There is a distinction between storing data in a contract\u2019s ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys")," and using a dictionary. ",(0,o.kt)("a",{parentName:"p",href:"/concepts/dictionaries"},"Dictionaries")," can be used to store dApp-centric data, but they are not a SQL database and should only be used for data that needs to be stored in global state. Objects referenced in a contract should only be used as links within a bigger application.")),(0,o.kt)("h2",{id:"deploying-contract"},"Deploying the Contract"),(0,o.kt)("p",null,"There are many tools available to send a deploy to a Casper network. The simplest method is to use the Rust CLI with the subcommand ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts#installing-contract-code"},"put_deploy"),"."),(0,o.kt)("p",null,"Be sure to go through the prerequisites from the ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts"},"Installing Smart Contracts and Querying Global State")," documentation."),(0,o.kt)("p",null,"Make sure that after doing this you have:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"A valid private key for your account."),(0,o.kt)("li",{parentName:"ol"},"Funded your account with 2000 CSPR on the Testnet, which you can use for testing your smart contract.")),(0,o.kt)("p",null,"Create the ",(0,o.kt)("inlineCode",{parentName:"p"},"keys")," folder in the main folder of your project and make sure that the private key which you put into the folder is called ",(0,o.kt)("inlineCode",{parentName:"p"},"secret_key.pem"),"."),(0,o.kt)("p",null,"Compile the contract in the contract directory so you obtain the contracts ",(0,o.kt)("inlineCode",{parentName:"p"},".wasm"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd cross-contract\nmake prepare\nmake build-contract\n")),(0,o.kt)("p",null,"This should produce the following outcome:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd contract && cargo build --release --target wasm32-unknown-unknown\n Finished release [optimized] target(s) in 0.13s\nwasm-strip contract/target/wasm32-unknown-unknown/release/contract.wasm 2>/dev/null | true\n")),(0,o.kt)("p",null,"With this step everything is in place to deploy the contract."),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"When working with lengthy command strings, it may help to maintain a .txt file where you can edit the runtime arguments of the commands before sending them to the CLI. This will save you time and frustration when working with multiple contracts and commands.")),(0,o.kt)("p",null,"Since we are using a default contract structure, the command called from the ",(0,o.kt)("inlineCode",{parentName:"p"},"cross-contract")," folder should be the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n --node-address http://136.243.187.84:7777 \\\n --chain-name casper-test \\\n --secret-key ./keys/secret_key.pem \\\n --payment-amount 20000000000 \\\n --session-path ./contract/target/wasm32-unknown-unknown/release/contract.wasm \\\n --session-arg \"message:string='hello world'\"\n")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"The parameters used in this command need to be adjusted based on your use case. For details, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#acquire-node-address-from-network-peers"},"querying a node")," and ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts"},"installing contracts"),". The payment amount may also need to be adjusted based on the latest Testnet ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),".")),(0,o.kt)("p",null,"The output of this command is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -9119604526598719721,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy_hash": "af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832"\n }\n}\n')),(0,o.kt)("p",null,"To verify that the contract was successfully deployed, use the ",(0,o.kt)("inlineCode",{parentName:"p"},"get-deploy")," subcommand, providing as a parameter the ",(0,o.kt)("inlineCode",{parentName:"p"},"deploy_hash")," received from the ",(0,o.kt)("inlineCode",{parentName:"p"},"put-deploy")," above."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --node-address http://136.243.187.84:7777 af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832\n")),(0,o.kt)("p",null,"This should return a JSON output containing information such as header data, approvers and payments. You can also receive this information by using the ",(0,o.kt)("inlineCode",{parentName:"p"},"verbose")," flag with the ",(0,o.kt)("inlineCode",{parentName:"p"},"put-deploy")," subcommand. Take time to familiarize yourself with the structure of the output."),(0,o.kt)("p",null,"We can use the supplied deploy hash, ",(0,o.kt)("inlineCode",{parentName:"p"},"af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832")," to find this contract using a block explorer. When viewed through the explorer, the status of the Deploy should be marked as ",(0,o.kt)("inlineCode",{parentName:"p"},"Success"),"."),(0,o.kt)("p",null,"From your ",(0,o.kt)("inlineCode",{parentName:"p"},"cspr.live")," account, you will find a tab called ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys"),". This tab includes a list of all contracts deployed using the private key connected to your account."),(0,o.kt)("p",null,"By clicking the contract hash, you can see all entry points included in the contract, as well as the ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys")," under which your contract\u2019s name is stored. You should keep these named keys organized to avoid losing track while creating larger implementations."),(0,o.kt)("p",null,"An additional tab, ",(0,o.kt)("inlineCode",{parentName:"p"},"Deploys"),", that is currently empty. If our contract included a cross-contract call that called an entry point from another contract, it would appear here. For now, we can note the hash of the contract, which is ",(0,o.kt)("inlineCode",{parentName:"p"},"hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea"),"."),(0,o.kt)("h2",{id:"cross-contract"},"Create Another Contract for the Cross-Contract Call"),(0,o.kt)("p",null,"This section describes the process of writing an additional contract, which will use an entry point titled ",(0,o.kt)("inlineCode",{parentName:"p"},"call_contract_2")," to invoke the ",(0,o.kt)("inlineCode",{parentName:"p"},"update_msg")," entry point on the previous contract."),(0,o.kt)("p",null,"In this tutorial we will be passing the contract hash, as an argument, into the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point and use this to perform the calls to the destination contract."),(0,o.kt)("p",null,"Prepare the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point as described below:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'\n#[no_mangle]\npub extern "C" fn call() {\n\n // Create the list of required runtime arguments for the given entry point.\n let mut vec = Vec::new();\n vec.push(Parameter::new("new_message", CLType::String));\n vec.push(Parameter::new("hello_world_contract", CLType::Key));\n\n // In the named keys of the contract, add a key for the count.\n let mut named_keys = NamedKeys::new();\n\n // Create an Entry Point Object\n let mut entry_points = EntryPoints::new();\n\n // Add the entry point metadata definition.\n entry_points.add_entry_point(EntryPoint::new(\n "call_contract_2",\n vec,\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract\n ));\n\n // The contract is stored in the global state\n let (stored_contract_hash, _contract_version) = storage::new_contract(\n entry_points, // entry points\n Some(named_keys), // named keys\n Some("contract2_package_name".to_string()), // package name\n Some("contract2_access_uref".to_string()) // access uref\n );\n\n // To access from the account - named keys of the account\n runtime::put_key("cross_contract_2", stored_contract_hash.into());\n}\n\n')),(0,o.kt)("p",null,"This would be the easiest implementation of the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point. There is only one entry point which accepts the key ",(0,o.kt)("inlineCode",{parentName:"p"},"contract2")," of type ",(0,o.kt)("inlineCode",{parentName:"p"},"String")," and the key ",(0,o.kt)("inlineCode",{parentName:"p"},"hello_world_contract")," of the type ",(0,o.kt)("inlineCode",{parentName:"p"},"Key"),". There aren't any named keys which will be saved in the contract's context. The contract is then stored in global state and placed as an entry within the account's named keys."),(0,o.kt)("p",null,"Now that we have defined the metadata for the ",(0,o.kt)("inlineCode",{parentName:"p"},"call_contract_2")," entry point, we must now define the entry point itself. This entry point will take the second contract hash as an argument and call the entry point ",(0,o.kt)("inlineCode",{parentName:"p"},"update_msg"),". It will then pass a message to the second contract as a parameter, which will be stored in that contract\u2019s context."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'#[no_mangle]\npub extern "C" fn call_contract_2() {\n\n // Get the contract hash from the named arguments passed to the `call_contract_2` entry point.\n let contract_hash: ContractHash = runtime::get_named_arg::(CONTRACT_HASH)\n .into_hash()\n .map(|hash| ContractHash::new(hash))\n .unwrap();\n\n // Get the value of the message from the second parameter\n let new_value: String = runtime::get_named_arg("new_message");\n\n // Call the update_msg entry point on the other contract with the parameter values\n let _: () = runtime::call_contract(\n contract_hash,\n "update_msg",\n runtime_args! {\n "message" => new_value,\n },\n );\n\n}\n')),(0,o.kt)("p",null,"Your complete contract implementation should look as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'\n#![no_std]\n#![no_main]\n\n#[cfg(not(target_arch = "wasm32"))]\ncompile_error!("target arch should be wasm32: compile with \'--target wasm32-unknown-unknown\'");\n\n// We need to explicitly import the std alloc crate and `alloc::string::String` as we are in a\n// `no_std` environment.\nextern crate alloc;\n\n// The elementary types\nuse alloc::string::String;\nuse alloc::vec::Vec;\nuse crate::alloc::string::ToString;\nuse crate::runtime_args::RuntimeArgs;\n\n// Casper crates\nuse casper_types::{\n api_error::ApiError,\n contracts::NamedKeys, runtime_args, CLType, Key, ContractHash, Parameter, EntryPoint, EntryPoints, EntryPointType, EntryPointAccess};\n\nuse casper_contract::{\n unwrap_or_revert::UnwrapOrRevert,\n contract_api::{runtime, storage},\n};\n\n// The contract key in the account named keys\nconst CONTRACT_HASH: &str = "hello_world_contract";\n\n#[no_mangle]\npub extern "C" fn call_contract_2() {\n\n let contract_hash: ContractHash = runtime::get_named_arg::(CONTRACT_HASH)\n .into_hash()\n .map(|hash| ContractHash::new(hash))\n .unwrap();\n\n let new_value: String = runtime::get_named_arg("new_message");\n\n let _: () = runtime::call_contract(\n contract_hash,\n "update_msg",\n runtime_args! {\n // key => value\n "message" => new_value,\n },\n );\n\n}\n\n#[no_mangle]\npub extern "C" fn call() {\n\n // Create a new vector - this will be the signature of the entrypoint\n let mut vec = Vec::new();\n vec.push(Parameter::new("new_message", CLType::String));\n vec.push(Parameter::new("hello_world_contract", CLType::Key));\n\n // In the named keys of the contract, add a key for the count.\n let named_keys = NamedKeys::new();\n\n // Create an Entry Point Object\n let mut entry_points = EntryPoints::new();\n\n // Add the entry point to the entry points object\n entry_points.add_entry_point(EntryPoint::new(\n "call_contract_2",\n vec,\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract\n ));\n\n // The contract is stored in global state\n let (stored_contract_hash, _contract_version) = storage::new_contract(\n entry_points, // entry points\n Some(named_keys), // named keys\n Some("contract2_package_name".to_string()), // package name\n Some("contract2_access_uref".to_string()) // access uref\n );\n\n // To access from the account - named keys of the account\n runtime::put_key("cross_contract_2", stored_contract_hash.into());\n\n}\n')),(0,o.kt)("p",null,"After you run ",(0,o.kt)("inlineCode",{parentName:"p"},"make build-contract")," in your second contract's directory, you should obtain the outcome:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd contract && cargo build --release --target wasm32-unknown-unknown\n Compiling contract v0.1.0 (/Users/karolmarter/Desktop/Rust_Projects/cross-contract-2/contract)\n Finished release [optimized] target(s) in 0.69s\nwasm-strip contract/target/wasm32-unknown-unknown/release/contract.wasm 2>/dev/null | true\n")),(0,o.kt)("p",null,"Create the ",(0,o.kt)("inlineCode",{parentName:"p"},"keys")," subfolder and copy the keys from the ",(0,o.kt)("inlineCode",{parentName:"p"},"keys")," subfolder in the first contract into this subfolder. The call from the terminal will look as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n --node-address http://136.243.187.84:7777 \\\n --chain-name casper-test \\\n --secret-key ./keys/secret_key.pem \\\n --payment-amount 20000000000 \\\n --session-path ./contract/target/wasm32-unknown-unknown/release/contract.wasm\n")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"You may have noticed that the contract.wasm is always output to the same filename for each new ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper")," project. You can change this by editing the ",(0,o.kt)("inlineCode",{parentName:"p"},"Makefile")," in the main directory. You can then observe the result by recompiling your contract with these commands;"),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"make prepare\nmake build-contract\n"))),(0,o.kt)("p",null,"After the deploy we can check if it was successful and inspect the runtime arguments of the deployed entry points."),(0,o.kt)("p",null,"The result of invoking the ",(0,o.kt)("inlineCode",{parentName:"p"},"put-deploy")," subcommand is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -7557689417621513622,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy_hash": "faeb7e4f010c20c88d2dd126da545933c26fd8ce370282b8cd49f7f6fe7304b9"\n }\n}\n')),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"If the contract name doesn't change during concurrent deploys, the urefs/hashes will be overwritten in the account's named keys.")),(0,o.kt)("p",null,"Observing the deploy, we can see that it succeeded:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --node-address http://136.243.187.84:7777 af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832\n")),(0,o.kt)("p",null,"In the ",(0,o.kt)("inlineCode",{parentName:"p"},"execution_results"),' JSON element we should see "Success".'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'\n "execution_results": [\n {\n "block_hash": "bc3040214e46fe0eaa9d98150a8a67a1033b931619dbc3e5f1a841d3a2d6f869",\n "result": {\n "Success": {\n "cost": "16580565260",\n "effect": { ...\n\n }\n }\n }\n }\n ]\n\n')),(0,o.kt)("p",null,"Get the state root hash of the current network state:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address http://136.243.187.84:7777\n")),(0,o.kt)("p",null,"The result of invoking the",(0,o.kt)("inlineCode",{parentName:"p"},"get-state-root-hash")," command is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -3631326529646611302,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "state_root_hash": "2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb"\n }\n}\n')),(0,o.kt)("p",null,"Query the state of Casper network using the account hash:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," casper-client query-global-state \\\n --node-address http://136.243.187.84:7777 \\\n --state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \\\n --key account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9\n")),(0,o.kt)("p",null,"If we check the account's named keys, we can see all of the account's deployed contracts:"),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Account's named keys"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -6842818667609668962,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[30424 hex chars]",\n "stored_value": {\n "Account": {\n "account_hash": "account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9",\n "weight": 1\n }\n ],\n "main_purse": "uref-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5-007",\n "named_keys": [\n {\n "key": "uref-94c54f24273f1fb874eff33f3d4211a254622edfd1b980d5e758bd719b46fd0d-007",\n "name": "Hello_world_access_uref"\n },\n {\n "key": "hash-7a581d353665b74779dc8d446d33a5086bb367a29a558490d1e524f9c12002d3",\n "name": "Hello_world_package_name"\n },\n {\n "key": "uref-ae2f94bf959ec06a80b2035f31d7e4c65c01bf24bbbf794a473bc743c4b2f655-007",\n "name": "contract2_access_uref"\n },\n {\n "key": "hash-a7810282c275d525f083a756aba6912513a4a494ae317503cf6018c0fbaf9c4d",\n "name": "contract2_package_name"\n },\n {\n "key": "hash-32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92",\n "name": "cross_contract_2"\n },\n {\n "key": "hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea",\n "name": "hello_world_contract"\n }\n ]\n }\n }\n }\n}\n'))),(0,o.kt)("br",null),(0,o.kt)("p",null,"As we have now managed to deploy two contracts, we can call the entry point of this contract, passing appropriate arguments to the function."),(0,o.kt)("p",null,"The Uref of the message variable is stored under the Named Keys in the contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n --node-address http://136.243.187.84:7777 \\\n --state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \\\n --key hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 2434670480361972874,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[25224 hex chars]",\n "stored_value": {\n "Contract": {\n "contract_package_hash": "contract-package-wasm7a581d353665b74779dc8d446d33a5086bb367a29a558490d1e524f9c12002d3",\n "contract_wasm_hash": "contract-wasm-c0384d4041950780bd3b167b4516a306e308e2d4729d08f6d2b10dfa1dbdaad6",\n "entry_points": [\n {\n "access": "Public",\n "args": [\n {\n "cl_type": "String",\n "name": "message"\n }\n ],\n "entry_point_type": "Contract",\n "name": "update_msg",\n "ret": "Unit"\n }\n ],\n "named_keys": [\n {\n "key": "uref-aa758090d9bc1364754180f9f6bfc8821275038fd5d794a5dfb60bd2838a8670-007",\n "name": "message"\n }\n ],\n "protocol_version": "1.4.13"\n }\n }\n }\n}\n')),(0,o.kt)("p",null,"Checking the state of the message in the first contract, we observe the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://136.243.187.84:7777 \\\n --state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \\\n --key hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea -q "message"\n')),(0,o.kt)("p",null,"This is a simple ",(0,o.kt)("inlineCode",{parentName:"p"},"hello world")," string. After invoking the entry point using the command below this value should change."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"--session-hash")," - is the contract hash, which is returned from the put-deploy."),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"--session-arg"),' "hello world_contract:Key= ..." - the hash of the contract which we want to call from within the contract identified by the session-hash.')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address http://136.243.187.84:7777 \\\n --chain-name casper-test \\\n --secret-key ./keys/secret_key.pem \\\n --payment-amount 20000000000 \\\n --session-hash hash-32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92 \\\n --session-entry-point "call_contract_2" \\\n --session-arg "new_message:string=\'Hello new message!\'" \\\n --session-arg "hello_world_contract:Key=\'hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea\'"\n')),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"The contract hash has to be of type ",(0,o.kt)("inlineCode",{parentName:"p"},"ContractHash")," in the contract itself. We can pass the hash as a ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," argument and change it to ",(0,o.kt)("inlineCode",{parentName:"p"},"ContractHash")," in the smart contract.")),(0,o.kt)("p",null,"The output of the above command is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -6419793201665396463,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy_hash": "15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537"\n }\n}\n')),(0,o.kt)("p",null,"Check the deploy with:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --node-address http://136.243.187.84:7777 15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537\n")),(0,o.kt)("p",null,"After the deploy finishes successfully, you should see a similar outcome to the following:"),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Deploy details"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 3968762702269106998,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy": {\n "approvals": [\n {\n "signature": "01319eee9bcfde6963e5b47164dd2c8044f0c20dd59f0c2993db55bec6bd3802fec2c9c6cae6ca8993c8aee0440be43f6c38bdc4bbdce501837ff5ca66fbd7c902",\n "signer": "010e732fe2fbbcf62f2e46500d4cd8ff58a3bfd8dcb44c8b6f9a87dc5d573556af"\n }\n ],\n "hash": "15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537",\n "header": {\n "account": "010e732fe2fbbcf62f2e46500d4cd8ff58a3bfd8dcb44c8b6f9a87dc5d573556af",\n "body_hash": "26282fa50b8e7c240025d683f197661ca846f2c1a3521a5dd604e6066d89d6d7",\n "chain_name": "casper-test",\n "dependencies": [],\n "gas_price": 1,\n "timestamp": "2023-03-09T14:39:24.974Z",\n "ttl": "30m"\n },\n "payment": {\n "ModuleBytes": {\n "args": [\n [\n "amount",\n {\n "bytes": "0500c817a804",\n "cl_type": "U512",\n "parsed": "20000000000"\n }\n ]\n ],\n "module_bytes": ""\n }\n },\n "session": {\n "StoredContractByHash": {\n "args": [\n [\n "new_message",\n {\n "bytes": "1200000048656c6c6f206e6577206d65737361676521",\n "cl_type": "String",\n "parsed": "Hello new message!"\n }\n ],\n [\n "hello_world_contract",\n {\n "bytes": "01b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea",\n "cl_type": "Key",\n "parsed": {\n "Hash": "hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea"\n }\n }\n ]\n ],\n "entry_point": "call_contract_2",\n "hash": "32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92"\n }\n }\n },\n "execution_results": [\n {\n "block_hash": "9c81259ac5ef7b953656a9327a479ae771a15c5ef131c91216e9e697dfdb09eb",\n "result": {\n "Success": {\n "cost": "462273650",\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5",\n "transform": {\n "WriteCLValue": {\n "bytes": "0600876bf27301",\n "cl_type": "U512",\n "parsed": "1597500000000"\n }\n }\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "AddUInt512": "20000000000"\n }\n },\n {\n "key": "hash-32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92",\n "transform": "Identity"\n },\n {\n "key": "hash-a7810282c275d525f083a756aba6912513a4a494ae317503cf6018c0fbaf9c4d",\n "transform": "Identity"\n },\n {\n "key": "hash-b48ccc725ba948405d01205e64acff09ac24c899aed8d649f7bc1572216266c2",\n "transform": "Identity"\n },\n {\n "key": "hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea",\n "transform": "Identity"\n },\n {\n "key": "hash-7a581d353665b74779dc8d446d33a5086bb367a29a558490d1e524f9c12002d3",\n "transform": "Identity"\n },\n {\n "key": "hash-c0384d4041950780bd3b167b4516a306e308e2d4729d08f6d2b10dfa1dbdaad6",\n "transform": "Identity"\n },\n {\n "key": "uref-aa758090d9bc1364754180f9f6bfc8821275038fd5d794a5dfb60bd2838a8670-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "1200000048656c6c6f206e6577206d65737361676521",\n "cl_type": "String",\n "parsed": "Hello new message!"\n }\n }\n },\n {\n "key": "deploy-15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537",\n "from": "account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9",\n "gas": "462273650",\n "source": "uref-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5-007",\n "transfers": []\n }\n }\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-bb9f47c30ddbe192438fad10b7db8200247529d6592af7159d92c5f3aa7716a1",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "WriteCLValue": {\n "bytes": "00",\n "cl_type": "U512",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-bb9f47c30ddbe192438fad10b7db8200247529d6592af7159d92c5f3aa7716a1",\n "transform": {\n "AddUInt512": "20000000000"\n }\n }\n ]\n },\n "transfers": []\n }\n }\n }\n ]\n }\n}\n'))),(0,o.kt)("br",null),(0,o.kt)("p",null,"We would expect that the value of the message reference in the other contract would have changed, which we can check:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://136.243.187.84:7777 \\\n --state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \\\n --key hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea -q "message"\n')),(0,o.kt)("p",null,"The output of the above command is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -5477027327608594231,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[61444 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "1200000048656c6c6f206e6577206d65737361676521",\n "cl_type": "String",\n "parsed": "Hello new message!"\n }\n }\n }\n}\n')),(0,o.kt)("p",null,"With this we have succeeded in cross-contract communication between two contracts."),(0,o.kt)("h2",{id:"summary"},"Summary"),(0,o.kt)("p",null,"In this tutorial, we:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Developed two Rust contracts on a Casper network, where one smart contract is calling an entry point of the second smart contract"),(0,o.kt)("li",{parentName:"ul"},"Called an entry point on one contract from the other contract, passing a value as an argument to this entry point.")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/72301f79.47a57eba.js b/assets/js/72301f79.47a57eba.js new file mode 100644 index 0000000000..e39c82150f --- /dev/null +++ b/assets/js/72301f79.47a57eba.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4970],{3905:function(e,n,t){t.d(n,{Zo:function(){return d},kt:function(){return m}});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function c(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var i=a.createContext({}),l=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},d=function(e){var n=l(e.components);return a.createElement(i.Provider,{value:n},e.children)},p="mdxType",h={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},u=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=l(t),u=r,m=p["".concat(i,".").concat(u)]||p[u]||h[u]||o;return t?a.createElement(m,c(c({ref:n},d),{},{components:t})):a.createElement(m,c({ref:n},d))}));function m(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,c=new Array(o);c[0]=u;var s={};for(var i in n)hasOwnProperty.call(n,i)&&(s[i]=n[i]);s.originalType=e,s[p]="string"==typeof e?e:r,c[1]=s;for(var l=2;l = BTreeMap::new();\n\n // Insert the new value into the named keys\n named_keys.insert(String::from("message"),value_ref.into()); // use into to wrap the Uref into a casper_types::Key\n // Create a new vector\n let mut params = Vec::new();\n vec.push(Parameter::new("message", CLType::String));\n\n // Create an Entry Point Object\n let mut entry_points = EntryPoints::new();\n\n // Describing the metadata for the entry point\n entry_points.add_entry_point(EntryPoint::new(\n "update_msg", // the name of the entry point\n vec, // the arguments which can be passed into the entry point\n CLType::Unit, // return type of the entry point\n EntryPointAccess::Public, // access permissions - public can be accessed always\n EntryPointType::Contract // in most cases it will be contract\n ));\n\n // The contract is stored in the global state\n let (stored_contract_hash, _contract_version) = storage::new_contract(\n entry_points, // entry points\n Some(named_keys), // named keys\n Some("Hello_world_package_name".to_string()), // package name\n Some("Hello_world_access_uref".to_string()) // access uref\n );\n\n // To access the contract hash from the accounts named keys\n runtime::put_key("hello_world_contract", stored_contract_hash.into());\n\n}\n')),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"runtime")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"storage")," appear frequently in our code. If these terms are unfamiliar to you, you should familiarize yourself with the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/index.html"},"Contract API Modules"),".")),(0,o.kt)("p",null,"The metadata for each of the contract's entry points is defined in the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point. When installing the contract, the system will look for the name of the entry point as specified by the metadata for that entry point. Therefore, each of the entry points defined in the code must share the same name as the ",(0,o.kt)("inlineCode",{parentName:"p"},"String")," value passed when defining the metadata for the entry point."),(0,o.kt)("p",null,"The #","[no_mangle]"," flag ensures that the compiler does not modify the name of the entry point. The compiler will not enforce the condition that the name of the entry point is the same value present in its metadata definition, therefore the developer must be careful when defining their entry points."),(0,o.kt)("p",null,"In our case, we will define the entry point ",(0,o.kt)("inlineCode",{parentName:"p"},"update_msg")," in the contract code just before ",(0,o.kt)("inlineCode",{parentName:"p"},"call"),"."),(0,o.kt)("p",null,"Your complete contract should match the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'#![no_std]\n#![no_main]\n\n#[cfg(not(target_arch = "wasm32"))]\ncompile_error!("target arch should be wasm32: compile with \'--target wasm32-unknown-unknown\'");\n\n// We need to explicitly import the std alloc crate and `alloc::string::String` as we are in a\n// `no_std` environment.\nextern crate alloc;\n\n// The elementary types\nuse alloc::string::String;\nuse alloc::vec::Vec;\nuse alloc::collections::BTreeMap;\nuse crate::alloc::string::ToString;\n\n\n// Casper crates\nuse casper_types::{Key, CLType, Parameter, EntryPoint, EntryPoints, EntryPointType, EntryPointAccess};\n\nuse casper_contract::{\n contract_api::{runtime, storage},\n unwrap_or_revert::UnwrapOrRevert,\n};\n\n#[no_mangle]\npub extern "C" fn update_msg() {\n\n let value: String = runtime::get_named_arg("message");\n // Get the uref of the message stored in global state\n let uref = runtime::get_key("message").unwrap_or_revert().into_uref().unwrap_or_revert();\n // Write the message to global state\n storage::write(uref, String::from(value));\n}\n\n\n#[no_mangle]\npub extern "C" fn call() {\n // Get the value of a passed parameter with the key "message"\n let value: String = runtime::get_named_arg("message");\n // The value will be wraped in a URef\n let value_ref = storage::new_uref(value);\n // Creating the new set of named keys\n // The keys are a Map of Key/Value\n let mut named_keys: BTreeMap = BTreeMap::new();\n // Insert the new value into the named keys\n named_keys.insert(String::from("message"),value_ref.into()); // use into to wrap the value to the key\n // Create a new vector\n let mut vec = Vec::new();\n vec.push(Parameter::new("message", CLType::String));\n // Create an Entry Point Object\n let mut entry_points = EntryPoints::new();\n\n // Define the metadata for the entry point `update_msg`\n entry_points.add_entry_point(EntryPoint::new(\n "update_msg",\n vec,\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract\n ));\n\n // The contract is stored in the global state\n let (stored_contract_hash, _contract_version) = storage::new_contract(\n entry_points, // entry points metadata\n Some(named_keys), // named keys\n Some("Hello_world_package_name".to_string()), // package name\n Some("Hello_world_access_uref".to_string()) // access uref\n );\n\n // To access from the account - named keys of the account\n runtime::put_key("hello_world_contract", stored_contract_hash.into());\n}\n')),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"There is a distinction between storing data in a contract\u2019s ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys")," and using a dictionary. ",(0,o.kt)("a",{parentName:"p",href:"/concepts/dictionaries"},"Dictionaries")," can be used to store dApp-centric data, but they are not a SQL database and should only be used for data that needs to be stored in global state. Objects referenced in a contract should only be used as links within a bigger application.")),(0,o.kt)("h2",{id:"deploying-contract"},"Deploying the Contract"),(0,o.kt)("p",null,"There are many tools available to send a deploy to a Casper network. The simplest method is to use the Rust CLI with the subcommand ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts#installing-contract-code"},"put_deploy"),"."),(0,o.kt)("p",null,"Be sure to go through the prerequisites from the ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts"},"Installing Smart Contracts and Querying Global State")," documentation."),(0,o.kt)("p",null,"Make sure that after doing this you have:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"A valid private key for your account."),(0,o.kt)("li",{parentName:"ol"},"Funded your account with 2000 CSPR on the Testnet, which you can use for testing your smart contract.")),(0,o.kt)("p",null,"Create the ",(0,o.kt)("inlineCode",{parentName:"p"},"keys")," folder in the main folder of your project and make sure that the private key which you put into the folder is called ",(0,o.kt)("inlineCode",{parentName:"p"},"secret_key.pem"),"."),(0,o.kt)("p",null,"Compile the contract in the contract directory so you obtain the contracts ",(0,o.kt)("inlineCode",{parentName:"p"},".wasm"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd cross-contract\nmake prepare\nmake build-contract\n")),(0,o.kt)("p",null,"This should produce the following outcome:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd contract && cargo build --release --target wasm32-unknown-unknown\n Finished release [optimized] target(s) in 0.13s\nwasm-strip contract/target/wasm32-unknown-unknown/release/contract.wasm 2>/dev/null | true\n")),(0,o.kt)("p",null,"With this step everything is in place to deploy the contract."),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"When working with lengthy command strings, it may help to maintain a .txt file where you can edit the runtime arguments of the commands before sending them to the CLI. This will save you time and frustration when working with multiple contracts and commands.")),(0,o.kt)("p",null,"Since we are using a default contract structure, the command called from the ",(0,o.kt)("inlineCode",{parentName:"p"},"cross-contract")," folder should be the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n --node-address http://136.243.187.84:7777 \\\n --chain-name casper-test \\\n --secret-key ./keys/secret_key.pem \\\n --payment-amount 20000000000 \\\n --session-path ./contract/target/wasm32-unknown-unknown/release/contract.wasm \\\n --session-arg \"message:string='hello world'\"\n")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"The parameters used in this command need to be adjusted based on your use case. For details, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#acquire-node-address-from-network-peers"},"querying a node")," and ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts"},"installing contracts"),". The payment amount may also need to be adjusted based on the latest Testnet ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),".")),(0,o.kt)("p",null,"The output of this command is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -9119604526598719721,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy_hash": "af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832"\n }\n}\n')),(0,o.kt)("p",null,"To verify that the contract was successfully deployed, use the ",(0,o.kt)("inlineCode",{parentName:"p"},"get-deploy")," subcommand, providing as a parameter the ",(0,o.kt)("inlineCode",{parentName:"p"},"deploy_hash")," received from the ",(0,o.kt)("inlineCode",{parentName:"p"},"put-deploy")," above."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --node-address http://136.243.187.84:7777 af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832\n")),(0,o.kt)("p",null,"This should return a JSON output containing information such as header data, approvers and payments. You can also receive this information by using the ",(0,o.kt)("inlineCode",{parentName:"p"},"verbose")," flag with the ",(0,o.kt)("inlineCode",{parentName:"p"},"put-deploy")," subcommand. Take time to familiarize yourself with the structure of the output."),(0,o.kt)("p",null,"We can use the supplied deploy hash, ",(0,o.kt)("inlineCode",{parentName:"p"},"af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832")," to find this contract using a block explorer. When viewed through the explorer, the status of the Deploy should be marked as ",(0,o.kt)("inlineCode",{parentName:"p"},"Success"),"."),(0,o.kt)("p",null,"From your ",(0,o.kt)("inlineCode",{parentName:"p"},"cspr.live")," account, you will find a tab called ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys"),". This tab includes a list of all contracts deployed using the private key connected to your account."),(0,o.kt)("p",null,"By clicking the contract hash, you can see all entry points included in the contract, as well as the ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys")," under which your contract\u2019s name is stored. You should keep these named keys organized to avoid losing track while creating larger implementations."),(0,o.kt)("p",null,"An additional tab, ",(0,o.kt)("inlineCode",{parentName:"p"},"Deploys"),", that is currently empty. If our contract included a cross-contract call that called an entry point from another contract, it would appear here. For now, we can note the hash of the contract, which is ",(0,o.kt)("inlineCode",{parentName:"p"},"hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea"),"."),(0,o.kt)("h2",{id:"cross-contract"},"Create Another Contract for the Cross-Contract Call"),(0,o.kt)("p",null,"This section describes the process of writing an additional contract, which will use an entry point titled ",(0,o.kt)("inlineCode",{parentName:"p"},"call_contract_2")," to invoke the ",(0,o.kt)("inlineCode",{parentName:"p"},"update_msg")," entry point on the previous contract."),(0,o.kt)("p",null,"In this tutorial we will be passing the contract hash, as an argument, into the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point and use this to perform the calls to the destination contract."),(0,o.kt)("p",null,"Prepare the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point as described below:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'\n#[no_mangle]\npub extern "C" fn call() {\n\n // Create the list of required runtime arguments for the given entry point.\n let mut vec = Vec::new();\n vec.push(Parameter::new("new_message", CLType::String));\n vec.push(Parameter::new("hello_world_contract", CLType::Key));\n\n // In the named keys of the contract, add a key for the count.\n let mut named_keys = NamedKeys::new();\n\n // Create an Entry Point Object\n let mut entry_points = EntryPoints::new();\n\n // Add the entry point metadata definition.\n entry_points.add_entry_point(EntryPoint::new(\n "call_contract_2",\n vec,\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract\n ));\n\n // The contract is stored in the global state\n let (stored_contract_hash, _contract_version) = storage::new_contract(\n entry_points, // entry points\n Some(named_keys), // named keys\n Some("contract2_package_name".to_string()), // package name\n Some("contract2_access_uref".to_string()) // access uref\n );\n\n // To access from the account - named keys of the account\n runtime::put_key("cross_contract_2", stored_contract_hash.into());\n}\n\n')),(0,o.kt)("p",null,"This would be the easiest implementation of the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point. There is only one entry point which accepts the key ",(0,o.kt)("inlineCode",{parentName:"p"},"contract2")," of type ",(0,o.kt)("inlineCode",{parentName:"p"},"String")," and the key ",(0,o.kt)("inlineCode",{parentName:"p"},"hello_world_contract")," of the type ",(0,o.kt)("inlineCode",{parentName:"p"},"Key"),". There aren't any named keys which will be saved in the contract's context. The contract is then stored in global state and placed as an entry within the account's named keys."),(0,o.kt)("p",null,"Now that we have defined the metadata for the ",(0,o.kt)("inlineCode",{parentName:"p"},"call_contract_2")," entry point, we must now define the entry point itself. This entry point will take the second contract hash as an argument and call the entry point ",(0,o.kt)("inlineCode",{parentName:"p"},"update_msg"),". It will then pass a message to the second contract as a parameter, which will be stored in that contract\u2019s context."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'#[no_mangle]\npub extern "C" fn call_contract_2() {\n\n // Get the contract hash from the named arguments passed to the `call_contract_2` entry point.\n let contract_hash: ContractHash = runtime::get_named_arg::(CONTRACT_HASH)\n .into_hash()\n .map(|hash| ContractHash::new(hash))\n .unwrap();\n\n // Get the value of the message from the second parameter\n let new_value: String = runtime::get_named_arg("new_message");\n\n // Call the update_msg entry point on the other contract with the parameter values\n let _: () = runtime::call_contract(\n contract_hash,\n "update_msg",\n runtime_args! {\n "message" => new_value,\n },\n );\n\n}\n')),(0,o.kt)("p",null,"Your complete contract implementation should look as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'\n#![no_std]\n#![no_main]\n\n#[cfg(not(target_arch = "wasm32"))]\ncompile_error!("target arch should be wasm32: compile with \'--target wasm32-unknown-unknown\'");\n\n// We need to explicitly import the std alloc crate and `alloc::string::String` as we are in a\n// `no_std` environment.\nextern crate alloc;\n\n// The elementary types\nuse alloc::string::String;\nuse alloc::vec::Vec;\nuse crate::alloc::string::ToString;\nuse crate::runtime_args::RuntimeArgs;\n\n// Casper crates\nuse casper_types::{\n api_error::ApiError,\n contracts::NamedKeys, runtime_args, CLType, Key, ContractHash, Parameter, EntryPoint, EntryPoints, EntryPointType, EntryPointAccess};\n\nuse casper_contract::{\n unwrap_or_revert::UnwrapOrRevert,\n contract_api::{runtime, storage},\n};\n\n// The contract key in the account named keys\nconst CONTRACT_HASH: &str = "hello_world_contract";\n\n#[no_mangle]\npub extern "C" fn call_contract_2() {\n\n let contract_hash: ContractHash = runtime::get_named_arg::(CONTRACT_HASH)\n .into_hash()\n .map(|hash| ContractHash::new(hash))\n .unwrap();\n\n let new_value: String = runtime::get_named_arg("new_message");\n\n let _: () = runtime::call_contract(\n contract_hash,\n "update_msg",\n runtime_args! {\n // key => value\n "message" => new_value,\n },\n );\n\n}\n\n#[no_mangle]\npub extern "C" fn call() {\n\n // Create a new vector - this will be the signature of the entrypoint\n let mut vec = Vec::new();\n vec.push(Parameter::new("new_message", CLType::String));\n vec.push(Parameter::new("hello_world_contract", CLType::Key));\n\n // In the named keys of the contract, add a key for the count.\n let named_keys = NamedKeys::new();\n\n // Create an Entry Point Object\n let mut entry_points = EntryPoints::new();\n\n // Add the entry point to the entry points object\n entry_points.add_entry_point(EntryPoint::new(\n "call_contract_2",\n vec,\n CLType::Unit,\n EntryPointAccess::Public,\n EntryPointType::Contract\n ));\n\n // The contract is stored in global state\n let (stored_contract_hash, _contract_version) = storage::new_contract(\n entry_points, // entry points\n Some(named_keys), // named keys\n Some("contract2_package_name".to_string()), // package name\n Some("contract2_access_uref".to_string()) // access uref\n );\n\n // To access from the account - named keys of the account\n runtime::put_key("cross_contract_2", stored_contract_hash.into());\n\n}\n')),(0,o.kt)("p",null,"After you run ",(0,o.kt)("inlineCode",{parentName:"p"},"make build-contract")," in your second contract's directory, you should obtain the outcome:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd contract && cargo build --release --target wasm32-unknown-unknown\n Compiling contract v0.1.0 (/Users/karolmarter/Desktop/Rust_Projects/cross-contract-2/contract)\n Finished release [optimized] target(s) in 0.69s\nwasm-strip contract/target/wasm32-unknown-unknown/release/contract.wasm 2>/dev/null | true\n")),(0,o.kt)("p",null,"Create the ",(0,o.kt)("inlineCode",{parentName:"p"},"keys")," subfolder and copy the keys from the ",(0,o.kt)("inlineCode",{parentName:"p"},"keys")," subfolder in the first contract into this subfolder. The call from the terminal will look as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n --node-address http://136.243.187.84:7777 \\\n --chain-name casper-test \\\n --secret-key ./keys/secret_key.pem \\\n --payment-amount 20000000000 \\\n --session-path ./contract/target/wasm32-unknown-unknown/release/contract.wasm\n")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"You may have noticed that the contract.wasm is always output to the same filename for each new ",(0,o.kt)("inlineCode",{parentName:"p"},"cargo casper")," project. You can change this by editing the ",(0,o.kt)("inlineCode",{parentName:"p"},"Makefile")," in the main directory. You can then observe the result by recompiling your contract with these commands;"),(0,o.kt)("pre",{parentName:"admonition"},(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"make prepare\nmake build-contract\n"))),(0,o.kt)("p",null,"After the deploy we can check if it was successful and inspect the runtime arguments of the deployed entry points."),(0,o.kt)("p",null,"The result of invoking the ",(0,o.kt)("inlineCode",{parentName:"p"},"put-deploy")," subcommand is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -7557689417621513622,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy_hash": "faeb7e4f010c20c88d2dd126da545933c26fd8ce370282b8cd49f7f6fe7304b9"\n }\n}\n')),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"If the contract name doesn't change during concurrent deploys, the urefs/hashes will be overwritten in the account's named keys.")),(0,o.kt)("p",null,"Observing the deploy, we can see that it succeeded:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --node-address http://136.243.187.84:7777 af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832\n")),(0,o.kt)("p",null,"In the ",(0,o.kt)("inlineCode",{parentName:"p"},"execution_results"),' JSON element we should see "Success".'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'\n "execution_results": [\n {\n "block_hash": "bc3040214e46fe0eaa9d98150a8a67a1033b931619dbc3e5f1a841d3a2d6f869",\n "result": {\n "Success": {\n "cost": "16580565260",\n "effect": { ...\n\n }\n }\n }\n }\n ]\n\n')),(0,o.kt)("p",null,"Get the state root hash of the current network state:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address http://136.243.187.84:7777\n")),(0,o.kt)("p",null,"The result of invoking the",(0,o.kt)("inlineCode",{parentName:"p"},"get-state-root-hash")," command is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -3631326529646611302,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "state_root_hash": "2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb"\n }\n}\n')),(0,o.kt)("p",null,"Query the state of Casper network using the account hash:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"}," casper-client query-global-state \\\n --node-address http://136.243.187.84:7777 \\\n --state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \\\n --key account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9\n")),(0,o.kt)("p",null,"If we check the account's named keys, we can see all of the account's deployed contracts:"),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Account's named keys"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -6842818667609668962,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[30424 hex chars]",\n "stored_value": {\n "Account": {\n "account_hash": "account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9",\n "weight": 1\n }\n ],\n "main_purse": "uref-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5-007",\n "named_keys": [\n {\n "key": "uref-94c54f24273f1fb874eff33f3d4211a254622edfd1b980d5e758bd719b46fd0d-007",\n "name": "Hello_world_access_uref"\n },\n {\n "key": "hash-7a581d353665b74779dc8d446d33a5086bb367a29a558490d1e524f9c12002d3",\n "name": "Hello_world_package_name"\n },\n {\n "key": "uref-ae2f94bf959ec06a80b2035f31d7e4c65c01bf24bbbf794a473bc743c4b2f655-007",\n "name": "contract2_access_uref"\n },\n {\n "key": "hash-a7810282c275d525f083a756aba6912513a4a494ae317503cf6018c0fbaf9c4d",\n "name": "contract2_package_name"\n },\n {\n "key": "hash-32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92",\n "name": "cross_contract_2"\n },\n {\n "key": "hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea",\n "name": "hello_world_contract"\n }\n ]\n }\n }\n }\n}\n'))),(0,o.kt)("br",null),(0,o.kt)("p",null,"As we have now managed to deploy two contracts, we can call the entry point of this contract, passing appropriate arguments to the function."),(0,o.kt)("p",null,"The Uref of the message variable is stored under the Named Keys in the contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n --node-address http://136.243.187.84:7777 \\\n --state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \\\n --key hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 2434670480361972874,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[25224 hex chars]",\n "stored_value": {\n "Contract": {\n "contract_package_hash": "contract-package-wasm7a581d353665b74779dc8d446d33a5086bb367a29a558490d1e524f9c12002d3",\n "contract_wasm_hash": "contract-wasm-c0384d4041950780bd3b167b4516a306e308e2d4729d08f6d2b10dfa1dbdaad6",\n "entry_points": [\n {\n "access": "Public",\n "args": [\n {\n "cl_type": "String",\n "name": "message"\n }\n ],\n "entry_point_type": "Contract",\n "name": "update_msg",\n "ret": "Unit"\n }\n ],\n "named_keys": [\n {\n "key": "uref-aa758090d9bc1364754180f9f6bfc8821275038fd5d794a5dfb60bd2838a8670-007",\n "name": "message"\n }\n ],\n "protocol_version": "1.4.13"\n }\n }\n }\n}\n')),(0,o.kt)("p",null,"Checking the state of the message in the first contract, we observe the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://136.243.187.84:7777 \\\n --state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \\\n --key hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea -q "message"\n')),(0,o.kt)("p",null,"This is a simple ",(0,o.kt)("inlineCode",{parentName:"p"},"hello world")," string. After invoking the entry point using the command below this value should change."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"--session-hash")," - is the contract hash, which is returned from the put-deploy."),(0,o.kt)("p",{parentName:"admonition"},(0,o.kt)("inlineCode",{parentName:"p"},"--session-arg"),' "hello world_contract:Key= ..." - the hash of the contract which we want to call from within the contract identified by the session-hash.')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address http://136.243.187.84:7777 \\\n --chain-name casper-test \\\n --secret-key ./keys/secret_key.pem \\\n --payment-amount 20000000000 \\\n --session-hash hash-32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92 \\\n --session-entry-point "call_contract_2" \\\n --session-arg "new_message:string=\'Hello new message!\'" \\\n --session-arg "hello_world_contract:Key=\'hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea\'"\n')),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"The contract hash has to be of type ",(0,o.kt)("inlineCode",{parentName:"p"},"ContractHash")," in the contract itself. We can pass the hash as a ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," argument and change it to ",(0,o.kt)("inlineCode",{parentName:"p"},"ContractHash")," in the smart contract.")),(0,o.kt)("p",null,"The output of the above command is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -6419793201665396463,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy_hash": "15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537"\n }\n}\n')),(0,o.kt)("p",null,"Check the deploy with:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --node-address http://136.243.187.84:7777 15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537\n")),(0,o.kt)("p",null,"After the deploy finishes successfully, you should see a similar outcome to the following:"),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Deploy details"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 3968762702269106998,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy": {\n "approvals": [\n {\n "signature": "01319eee9bcfde6963e5b47164dd2c8044f0c20dd59f0c2993db55bec6bd3802fec2c9c6cae6ca8993c8aee0440be43f6c38bdc4bbdce501837ff5ca66fbd7c902",\n "signer": "010e732fe2fbbcf62f2e46500d4cd8ff58a3bfd8dcb44c8b6f9a87dc5d573556af"\n }\n ],\n "hash": "15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537",\n "header": {\n "account": "010e732fe2fbbcf62f2e46500d4cd8ff58a3bfd8dcb44c8b6f9a87dc5d573556af",\n "body_hash": "26282fa50b8e7c240025d683f197661ca846f2c1a3521a5dd604e6066d89d6d7",\n "chain_name": "casper-test",\n "dependencies": [],\n "gas_price": 1,\n "timestamp": "2023-03-09T14:39:24.974Z",\n "ttl": "30m"\n },\n "payment": {\n "ModuleBytes": {\n "args": [\n [\n "amount",\n {\n "bytes": "0500c817a804",\n "cl_type": "U512",\n "parsed": "20000000000"\n }\n ]\n ],\n "module_bytes": ""\n }\n },\n "session": {\n "StoredContractByHash": {\n "args": [\n [\n "new_message",\n {\n "bytes": "1200000048656c6c6f206e6577206d65737361676521",\n "cl_type": "String",\n "parsed": "Hello new message!"\n }\n ],\n [\n "hello_world_contract",\n {\n "bytes": "01b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea",\n "cl_type": "Key",\n "parsed": {\n "Hash": "hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea"\n }\n }\n ]\n ],\n "entry_point": "call_contract_2",\n "hash": "32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92"\n }\n }\n },\n "execution_results": [\n {\n "block_hash": "9c81259ac5ef7b953656a9327a479ae771a15c5ef131c91216e9e697dfdb09eb",\n "result": {\n "Success": {\n "cost": "462273650",\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5",\n "transform": {\n "WriteCLValue": {\n "bytes": "0600876bf27301",\n "cl_type": "U512",\n "parsed": "1597500000000"\n }\n }\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "AddUInt512": "20000000000"\n }\n },\n {\n "key": "hash-32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92",\n "transform": "Identity"\n },\n {\n "key": "hash-a7810282c275d525f083a756aba6912513a4a494ae317503cf6018c0fbaf9c4d",\n "transform": "Identity"\n },\n {\n "key": "hash-b48ccc725ba948405d01205e64acff09ac24c899aed8d649f7bc1572216266c2",\n "transform": "Identity"\n },\n {\n "key": "hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea",\n "transform": "Identity"\n },\n {\n "key": "hash-7a581d353665b74779dc8d446d33a5086bb367a29a558490d1e524f9c12002d3",\n "transform": "Identity"\n },\n {\n "key": "hash-c0384d4041950780bd3b167b4516a306e308e2d4729d08f6d2b10dfa1dbdaad6",\n "transform": "Identity"\n },\n {\n "key": "uref-aa758090d9bc1364754180f9f6bfc8821275038fd5d794a5dfb60bd2838a8670-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "1200000048656c6c6f206e6577206d65737361676521",\n "cl_type": "String",\n "parsed": "Hello new message!"\n }\n }\n },\n {\n "key": "deploy-15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537",\n "from": "account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9",\n "gas": "462273650",\n "source": "uref-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5-007",\n "transfers": []\n }\n }\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-bb9f47c30ddbe192438fad10b7db8200247529d6592af7159d92c5f3aa7716a1",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "WriteCLValue": {\n "bytes": "00",\n "cl_type": "U512",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-bb9f47c30ddbe192438fad10b7db8200247529d6592af7159d92c5f3aa7716a1",\n "transform": {\n "AddUInt512": "20000000000"\n }\n }\n ]\n },\n "transfers": []\n }\n }\n }\n ]\n }\n}\n'))),(0,o.kt)("br",null),(0,o.kt)("p",null,"We would expect that the value of the message reference in the other contract would have changed, which we can check:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n --node-address http://136.243.187.84:7777 \\\n --state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \\\n --key hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea -q "message"\n')),(0,o.kt)("p",null,"The output of the above command is:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -5477027327608594231,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "block_header": null,\n "merkle_proof": "[61444 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "1200000048656c6c6f206e6577206d65737361676521",\n "cl_type": "String",\n "parsed": "Hello new message!"\n }\n }\n }\n}\n')),(0,o.kt)("p",null,"With this we have succeeded in cross-contract communication between two contracts."),(0,o.kt)("h2",{id:"summary"},"Summary"),(0,o.kt)("p",null,"In this tutorial, we:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Developed two Rust contracts on a Casper network, where one smart contract is calling an entry point of the second smart contract"),(0,o.kt)("li",{parentName:"ul"},"Called an entry point on one contract from the other contract, passing a value as an argument to this entry point.")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/725b7e74.58efa18c.js b/assets/js/725b7e74.58efa18c.js deleted file mode 100644 index 54a3a7ab5b..0000000000 --- a/assets/js/725b7e74.58efa18c.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6958],{3905:function(e,n,t){t.d(n,{Zo:function(){return l},kt:function(){return h}});var a=t(7294);function s(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function r(e){for(var n=1;n=0||(s[t]=e[t]);return s}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(s[t]=e[t])}return s}var i=a.createContext({}),u=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},l=function(e){var n=u(e.components);return a.createElement(i.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,s=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=u(t),m=s,h=d["".concat(i,".").concat(m)]||d[m]||p[m]||o;return t?a.createElement(h,r(r({ref:n},l),{},{components:t})):a.createElement(h,r({ref:n},l))}));function h(e,n){var t=arguments,s=n&&n.mdxType;if("string"==typeof e||s){var o=t.length,r=new Array(o);r[0]=m;var c={};for(var i in n)hasOwnProperty.call(n,i)&&(c[i]=n[i]);c.originalType=e,c[d]="string"==typeof e?e:s,r[1]=c;for(var u=2;u=0||(s[t]=e[t]);return s}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(s[t]=e[t])}return s}var i=a.createContext({}),u=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},l=function(e){var n=u(e.components);return a.createElement(i.Provider,{value:n},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,s=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=u(t),m=s,h=d["".concat(i,".").concat(m)]||d[m]||p[m]||o;return t?a.createElement(h,r(r({ref:n},l),{},{components:t})):a.createElement(h,r({ref:n},l))}));function h(e,n){var t=arguments,s=n&&n.mdxType;if("string"==typeof e||s){var o=t.length,r=new Array(o);r[0]=m;var c={};for(var i in n)hasOwnProperty.call(n,i)&&(c[i]=n[i]);c.originalType=e,c[d]="string"==typeof e?e:s,r[1]=c;for(var u=2;u=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),i=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=i(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=i(n),f=r,h=p["".concat(c,".").concat(f)]||p[f]||u[f]||s;return n?a.createElement(h,o(o({ref:t},d),{},{components:n})):a.createElement(h,o({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,o=new Array(s);o[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var i=2;i=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),i=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=i(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=i(n),f=r,h=p["".concat(c,".").concat(f)]||p[f]||u[f]||s;return n?a.createElement(h,o(o({ref:t},d),{},{components:n})):a.createElement(h,o({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,o=new Array(s);o[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var i=2;i=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(n),m=r,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||l;return n?a.createElement(h,o(o({ref:t},c),{},{components:n})):a.createElement(h,o({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:r,o[1]=i;for(var u=2;u child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:p(n);return function(e){var t=(0,u.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function h(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,l=(0,i.k6)(),o=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,s._X)(o),(0,r.useCallback)((function(e){if(o){var t=new URLSearchParams(l.location.search);t.set(o,e),l.replace(Object.assign({},l.location,{search:t.toString()}))}}),[o,l])]}function k(e){var t,n,a,l,o=e.defaultValue,i=e.queryString,s=void 0!==i&&i,u=e.groupId,p=d(e),k=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:o,tabValues:p})})),g=k[0],f=k[1],v=h({queryString:s,groupId:u}),b=v[0],y=v[1],N=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:u}.groupId),n=(0,c.Nk)(t),a=n[0],l=n[1],[a,(0,r.useCallback)((function(e){t&&l.set(e)}),[t,l])]),w=N[0],C=N[1],I=function(){var e=null!=b?b:w;return m({value:e,tabValues:p})?e:null}();return(0,r.useLayoutEffect)((function(){I&&f(I)}),[I]),{selectedValue:g,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:p}))throw new Error("Can't select invalid tab value="+e);f(e),y(e),C(e)}),[y,C,p]),tabValues:p}}var g=n(2389),f={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function v(e){var t=e.className,n=e.block,i=e.selectedValue,s=e.selectValue,u=e.tabValues,c=[],p=(0,o.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,n=c.indexOf(t),a=u[n].value;a!==i&&(p(t),s(a))},m=function(e){var t,n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var a,r=c.indexOf(e.currentTarget)+1;n=null!=(a=c[r])?a:c[0];break;case"ArrowLeft":var l,o=c.indexOf(e.currentTarget)-1;n=null!=(l=c[o])?l:c[c.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,l.Z)("tabs",{"tabs--block":n},t)},u.map((function(e){var t=e.value,n=e.label,o=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:i===t?0:-1,"aria-selected":i===t,key:t,ref:function(e){return c.push(e)},onKeyDown:m,onClick:d},o,{className:(0,l.Z)("tabs__item",f.tabItem,null==o?void 0:o.className,{"tabs__item--active":i===t})}),null!=n?n:t)})))}function b(e){var t=e.lazy,n=e.children,a=e.selectedValue,l=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var o=l.find((function(e){return e.props.value===a}));return o?(0,r.cloneElement)(o,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},l.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function y(e){var t=k(e);return r.createElement("div",{className:(0,l.Z)("tabs-container",f.tabList)},r.createElement(v,(0,a.Z)({},e,t)),r.createElement(b,(0,a.Z)({},e,t)))}function N(e){var t=(0,g.Z)();return r.createElement(y,(0,a.Z)({key:String(t)},e))}},3235:function(e,t,n){n.r(t),n.d(t,{assets:function(){return d},contentTitle:function(){return c},default:function(){return g},frontMatter:function(){return u},metadata:function(){return p},toc:function(){return m}});var a=n(7462),r=n(3366),l=(n(7294),n(3905)),o=(n(4996),n(4866)),i=n(5162),s=["components"],u={},c="Development Prerequisites",p={unversionedId:"developers/prerequisites",id:"developers/prerequisites",title:"Development Prerequisites",description:"This page covers the necessary software for your Casper development environment. To develop comfortably, you should use Linux Ubuntu 20.04 or macOS. Developing on Windows is not advised.",source:"@site/source/docs/casper/developers/prerequisites.md",sourceDirName:"developers",slug:"/developers/prerequisites",permalink:"/developers/prerequisites",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/prerequisites.md",tags:[],version:"current",lastUpdatedAt:1707229568,formattedLastUpdatedAt:"Feb 6, 2024",frontMatter:{},sidebar:"developers",previous:{title:"Overview",permalink:"/developers"},next:{title:"Essential Rust Crates",permalink:"/developers/essential-crates"}},d={},m=[{value:"Preparing your Development Environment",id:"preparing-your-development-environment",level:2},{value:"Installing curl",id:"install-curl",level:3},{value:"Installing essential Linux packages",id:"install-essential",level:3},{value:"Installing packages required for Casper tools",id:"install-adds",level:3},{value:"Installing cargo on Linux",id:"install-linux-cargo",level:3},{value:"Installing Xcode developer tools for macOS",id:"install-xcode",level:3},{value:"Installing brew",id:"install-brew",level:3},{value:"Installing packages required for Casper tools",id:"install-adds-macos",level:3},{value:"Installing Rust",id:"install-rust",level:2},{value:"Installing the Casper Crates",id:"installing-the-casper-crates",level:2},{value:"Installing the Casper Client",id:"install-casper-client",level:2},{value:"Accessing the Casper client source code",id:"building-client-from-source",level:3},{value:"Installing CMake",id:"install-cmake",level:2},{value:"Installing an IDE",id:"installing-an-ide",level:2},{value:"Setting up a Casper Account",id:"setting-up-an-account",level:2},{value:"Creating an account",id:"creating-an-account",level:3},{value:"Generating the account hash",id:"generating-the-account-hash",level:3},{value:"Funding an Account",id:"fund-your-account",level:2},{value:"Acquiring a Node Address from the Network",id:"acquire-node-address-from-network-peers",level:2}],h={toc:m},k="wrapper";function g(e){var t=e.components,n=(0,r.Z)(e,s);return(0,l.kt)(k,(0,a.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"development-prerequisites"},"Development Prerequisites"),(0,l.kt)("p",null,"This page covers the necessary software for your Casper development environment. To develop comfortably, you should use ",(0,l.kt)("inlineCode",{parentName:"p"},"Linux Ubuntu 20.04")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"macOS"),". Developing on Windows is not advised."),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"Casper does not officially support ",(0,l.kt)("inlineCode",{parentName:"p"},"macOS"),". If you encounter any problems, reach out to the community on ",(0,l.kt)("a",{parentName:"p",href:"https://t.me/casperblockchain"},"Telegram")," or ",(0,l.kt)("a",{parentName:"p",href:"https://discord.com/invite/casperblockchain"},"Discord"),".")),(0,l.kt)("h2",{id:"preparing-your-development-environment"},"Preparing your Development Environment"),(0,l.kt)(o.Z,{mdxType:"Tabs"},(0,l.kt)(i.Z,{value:"Linux",label:"Linux",mdxType:"TabItem"},(0,l.kt)("h3",{id:"install-curl"},"Installing ",(0,l.kt)("inlineCode",{parentName:"h3"},"curl")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install curl\n")),(0,l.kt)("h3",{id:"install-essential"},"Installing essential Linux packages"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install build-essential\n")),(0,l.kt)("h3",{id:"install-adds"},"Installing packages required for Casper tools"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get install pkg-config\nsudo apt-get install openssl\nsudo apt-get install libssl-dev\n")),(0,l.kt)("h3",{id:"install-linux-cargo"},"Installing ",(0,l.kt)("inlineCode",{parentName:"h3"},"cargo")," on Linux"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install cargo\n"))),(0,l.kt)(i.Z,{value:"macOS",label:"macOS",mdxType:"TabItem"},(0,l.kt)("h3",{id:"install-xcode"},"Installing Xcode developer tools for macOS"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"xcode-select --install\n")),(0,l.kt)("p",null,"Verify the installation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"xcode-select -p\n")),(0,l.kt)("h3",{id:"install-brew"},"Installing ",(0,l.kt)("inlineCode",{parentName:"h3"},"brew")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"\n')),(0,l.kt)("h3",{id:"install-adds-macos"},"Installing packages required for Casper tools"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"brew install pkg-config\nbrew install openssl\n")))),(0,l.kt)("h2",{id:"install-rust"},"Installing Rust"),(0,l.kt)("p",null,"Install the ",(0,l.kt)("a",{parentName:"p",href:"https://www.rust-lang.org"},"Rust programming language")," if you don't already have it on your computer."),(0,l.kt)("p",null,"The ",(0,l.kt)("a",{parentName:"p",href:"https://www.rust-lang.org/tools/install"},"official Rust guide")," recommends installing Rust by using ",(0,l.kt)("inlineCode",{parentName:"p"},"curl"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n")),(0,l.kt)("p",null,"After your next login, the installation script automatically adds Rust to your system PATH. To start using Rust immediately, run the following command in your shell instead of restarting your terminal. The command will add Rust to your system PATH."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"source $HOME/.cargo/env\n")),(0,l.kt)("p",null,"Verify the installation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"rustup --version\n")),(0,l.kt)("p",null,"Note: You can also use ",(0,l.kt)("inlineCode",{parentName:"p"},"brew")," on MacOS or ",(0,l.kt)("inlineCode",{parentName:"p"},"apt")," on Linux to install Rust."),(0,l.kt)("h2",{id:"installing-the-casper-crates"},"Installing the Casper Crates"),(0,l.kt)("p",null,"The best and fastest way to set up a Casper Rust project is to use ",(0,l.kt)("a",{parentName:"p",href:"https://crates.io/crates/cargo-casper"},"cargo casper"),", which is the command line tool for creating a Wasm smart contract and tests for use on a Casper network. This tool will create a simple contract, a runtime environment, and a testing framework with a simple test. ",(0,l.kt)("em",{parentName:"p"},"Cargo")," is a build system and package manager for Rust (much like ",(0,l.kt)("em",{parentName:"p"},"pip")," if you are familiar with Python, or ",(0,l.kt)("em",{parentName:"p"},"npm")," and ",(0,l.kt)("em",{parentName:"p"},"yarn")," for those familiar with Javascript). It is also possible to use this configuration in your CI/CD pipeline."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cargo install cargo-casper\n")),(0,l.kt)("p",null,"If you run into any issues with this command and you have not recently installed Rust from scratch, please make sure to update your Rust version with this command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"rustup update\n")),(0,l.kt)("p",null,"Verify the installation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cargo-casper --version\n")),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("p",{parentName:"admonition"},"Familiarize yourself with the essential Casper crates described ",(0,l.kt)("a",{parentName:"p",href:"/developers/essential-crates"},"here"),".")),(0,l.kt)("h2",{id:"install-casper-client"},"Installing the Casper Client"),(0,l.kt)("p",null,"The default Casper client is on ",(0,l.kt)("a",{parentName:"p",href:"https://crates.io/crates/casper-client"},"crates.io"),". This client can transmit your deploys to a Casper network."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cargo install casper-client\n")),(0,l.kt)("p",null,"Verify the installation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client --version\n")),(0,l.kt)("p",null,"The Casper client can print out help information, which provides an up-to-date list of supported commands. To do so, use the following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client --help\n")),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"help")," for each command to get the most up-to-date arguments and descriptions."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client --help\n")),(0,l.kt)("h3",{id:"building-client-from-source"},"Accessing the Casper client source code"),(0,l.kt)("p",null,"You can access the Casper client source code ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/casper-client-rs"},"here"),". The ",(0,l.kt)("inlineCode",{parentName:"p"},"lib")," directory contains the source for the client library, which may be called directly rather than through the CLI binary. The CLI app ",(0,l.kt)("inlineCode",{parentName:"p"},"casper-client")," uses this library to implement its functionality."),(0,l.kt)("p",null,"If you wish to compile it, you will need to first install the nightly Rust toolchain with this command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"rustup toolchain install nightly\n")),(0,l.kt)("p",null,"Then, compile the source code:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cargo build --release\n")),(0,l.kt)("p",null,"You will find the ",(0,l.kt)("inlineCode",{parentName:"p"},"casper-client")," executable in the ",(0,l.kt)("inlineCode",{parentName:"p"},"target/release")," directory."),(0,l.kt)("h2",{id:"install-cmake"},"Installing CMake"),(0,l.kt)("p",null,"If you plan to compile contracts from the source code, including those provided in the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository, install ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," with the commands below."),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://cmake.org/"},"CMake")," is a popular build tool that we will use, and you may have it installed. If you do, make sure that you have the latest version. If you need to install or upgrade it, follow the steps below or on the ",(0,l.kt)("a",{parentName:"p",href:"https://cmake.org/install/"},"CMake website"),". Once installed, check your version as shown below."),(0,l.kt)(o.Z,{mdxType:"Tabs"},(0,l.kt)(i.Z,{value:"Linux",label:"Linux",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get -y install cmake\n"))),(0,l.kt)(i.Z,{value:"macOS",label:"macOS",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"brew install cmake\n")))),(0,l.kt)("p",null,"Check your version:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cmake --version\n")),(0,l.kt)("p",null,"Sample output:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cmake version 3.20.0 (or above)\n\nCMake suite maintained and supported by Kitware (kitware.com/cmake).\n")),(0,l.kt)("h2",{id:"installing-an-ide"},"Installing an IDE"),(0,l.kt)("p",null,"We advise using an integrated development environment such as Visual Studio Code (VSC) for development. There are many IDEs available for Rust development. The most popular IDEs for Rust are the following:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://code.visualstudio.com"},"Visual Studio Code")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.jetbrains.com/clion/"},"CLion")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.jetbrains.com/idea/"},"IntelliJ Idea")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.vim.org/"},"Vim"))),(0,l.kt)("p",null,"You can use any IDE you wish. Most of our documentation and examples use Visual Studio Code (VSC), a popular IDE with many extensions that might be helpful during development."),(0,l.kt)("p",null,"If you are using VSC, you might find the following extensions useful:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"CodeLLDB")," \u2013 An important extension for debugging Rust code"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"rust-analyzer")," \u2013 The official Rust language extension"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Better TOML")," \u2013 Support for formatting TOML files"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"crates")," \u2013 An extension to help manage crates"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Error Lens")," \u2013 Enhances the programming experience by highlighting syntax errors")),(0,l.kt)("h2",{id:"setting-up-an-account"},"Setting up a Casper Account"),(0,l.kt)("p",null,"The ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Account")," creation process consists of two steps:"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"Creating an Account"),(0,l.kt)("li",{parentName:"ol"},"Funding the Account")),(0,l.kt)("p",null,"The following video complements the instructions below, showing you the expected output."),(0,l.kt)("p",{align:"center"},(0,l.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed?v=sA1HTPjV_bc&list=PL8oWxbJ-csEqi5FP87EJZViE2aLz6X1Mj&index=3",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,l.kt)("h3",{id:"creating-an-account"},"Creating an account"),(0,l.kt)("p",null,"The Casper blockchain uses an on-chain account-based model, uniquely identified by an ",(0,l.kt)("inlineCode",{parentName:"p"},"AccountHash")," derived from a specific ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey"),"."),(0,l.kt)("p",null,"By default, a transactional interaction with the blockchain takes the form of a ",(0,l.kt)("inlineCode",{parentName:"p"},"Deploy")," cryptographically signed by the key-pair corresponding to the ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey")," used to create the account."),(0,l.kt)("p",null,"Users can create accounts using the ",(0,l.kt)("a",{parentName:"p",href:"/concepts/accounts-and-keys#option-1-generating-keys-using-the-casper-client-option-1-key-generation-using-the-casper-client"},"Casper command-line client"),"."),(0,l.kt)("p",null,"Alternatively, some Casper networks, such as the official Testnet and Mainnet, provide a browser-based block explorer that allows account creation as outlined ",(0,l.kt)("a",{parentName:"p",href:"/concepts/accounts-and-keys#option-2-generating-keys-using-a-block-explorer-option-2-key-generation-using-a-block-explorer"},"here"),"."),(0,l.kt)("p",null,"Use either method to generate an account and its corresponding cryptographic key-pair."),(0,l.kt)("h3",{id:"generating-the-account-hash"},"Generating the account hash"),(0,l.kt)("p",null,"As a developer, you will often use an account hash, which is a 32-byte hash of the public key. This is because responses from the node contain ",(0,l.kt)("inlineCode",{parentName:"p"},"AccountHashes")," instead of the direct hexadecimal-encoded public key. To view the account hash for a public key, use the ",(0,l.kt)("inlineCode",{parentName:"p"},"account-address")," option of the Casper CLI client:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client account-address --public-key \n")),(0,l.kt)("h2",{id:"fund-your-account"},"Funding an Account"),(0,l.kt)("p",null,"After generating the cryptographic key-pair for an Account, you must fund the account's main purse to create it on-chain."),(0,l.kt)("p",null,"On Testnet, you can fund an account by requesting test tokens according to ",(0,l.kt)("a",{parentName:"p",href:"/users/testnet-faucet"},"this guide"),". You can request test tokens ",(0,l.kt)("strong",{parentName:"p"},"only once")," for each account."),(0,l.kt)("p",null,"On Mainnet, a pre-existing account must transfer CSPR tokens to the newly created account's main purse to finalize the setup. The source account needs to transfer CSPR tokens to the hexadecimal-encoded public key of the target account. This transfer will automatically create the target account if it does not exist. Currently, this is the only way to create an account on Mainnet."),(0,l.kt)("h2",{id:"acquire-node-address-from-network-peers"},"Acquiring a Node Address from the Network"),(0,l.kt)("p",null,"Clients can interact with a node on the blockchain via requests sent to that node's JSON-RPC endpoint, ",(0,l.kt)("inlineCode",{parentName:"p"},"http://:7777")," by default."),(0,l.kt)("p",null,"The node address is the IP of a peer node."),(0,l.kt)("p",null,"Both the official Testnet and Mainnet provide block explorers that list the IP addresses of nodes on their respective networks."),(0,l.kt)("p",null,"You can get the ",(0,l.kt)("inlineCode",{parentName:"p"},"node-ip-address")," of a node on the network by visiting the following block explorers:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://testnet.cspr.live/tools/peers"},"Peers")," on Testnet"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://cspr.live/tools/peers"},"Peers")," on Mainnet")),(0,l.kt)("p",null,"You will see a list of peers, and you can select the IP of any peer on the list."),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Note"),": If the selected peer is unresponsive, pick a different peer and try again."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/74bbf90e.b7a90c5c.js b/assets/js/74bbf90e.b7a90c5c.js new file mode 100644 index 0000000000..1005a649b8 --- /dev/null +++ b/assets/js/74bbf90e.b7a90c5c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5390],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(n),m=r,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||l;return n?a.createElement(h,o(o({ref:t},c),{},{components:n})):a.createElement(h,o({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:r,o[1]=i;for(var u=2;u child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:p(n);return function(e){var t=(0,u.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function h(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,l=(0,i.k6)(),o=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,s._X)(o),(0,r.useCallback)((function(e){if(o){var t=new URLSearchParams(l.location.search);t.set(o,e),l.replace(Object.assign({},l.location,{search:t.toString()}))}}),[o,l])]}function k(e){var t,n,a,l,o=e.defaultValue,i=e.queryString,s=void 0!==i&&i,u=e.groupId,p=d(e),k=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:o,tabValues:p})})),g=k[0],f=k[1],v=h({queryString:s,groupId:u}),b=v[0],y=v[1],N=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:u}.groupId),n=(0,c.Nk)(t),a=n[0],l=n[1],[a,(0,r.useCallback)((function(e){t&&l.set(e)}),[t,l])]),w=N[0],C=N[1],I=function(){var e=null!=b?b:w;return m({value:e,tabValues:p})?e:null}();return(0,r.useLayoutEffect)((function(){I&&f(I)}),[I]),{selectedValue:g,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:p}))throw new Error("Can't select invalid tab value="+e);f(e),y(e),C(e)}),[y,C,p]),tabValues:p}}var g=n(2389),f={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function v(e){var t=e.className,n=e.block,i=e.selectedValue,s=e.selectValue,u=e.tabValues,c=[],p=(0,o.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,n=c.indexOf(t),a=u[n].value;a!==i&&(p(t),s(a))},m=function(e){var t,n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var a,r=c.indexOf(e.currentTarget)+1;n=null!=(a=c[r])?a:c[0];break;case"ArrowLeft":var l,o=c.indexOf(e.currentTarget)-1;n=null!=(l=c[o])?l:c[c.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,l.Z)("tabs",{"tabs--block":n},t)},u.map((function(e){var t=e.value,n=e.label,o=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:i===t?0:-1,"aria-selected":i===t,key:t,ref:function(e){return c.push(e)},onKeyDown:m,onClick:d},o,{className:(0,l.Z)("tabs__item",f.tabItem,null==o?void 0:o.className,{"tabs__item--active":i===t})}),null!=n?n:t)})))}function b(e){var t=e.lazy,n=e.children,a=e.selectedValue,l=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var o=l.find((function(e){return e.props.value===a}));return o?(0,r.cloneElement)(o,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},l.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function y(e){var t=k(e);return r.createElement("div",{className:(0,l.Z)("tabs-container",f.tabList)},r.createElement(v,(0,a.Z)({},e,t)),r.createElement(b,(0,a.Z)({},e,t)))}function N(e){var t=(0,g.Z)();return r.createElement(y,(0,a.Z)({key:String(t)},e))}},3235:function(e,t,n){n.r(t),n.d(t,{assets:function(){return d},contentTitle:function(){return c},default:function(){return g},frontMatter:function(){return u},metadata:function(){return p},toc:function(){return m}});var a=n(7462),r=n(3366),l=(n(7294),n(3905)),o=(n(4996),n(4866)),i=n(5162),s=["components"],u={},c="Development Prerequisites",p={unversionedId:"developers/prerequisites",id:"developers/prerequisites",title:"Development Prerequisites",description:"This page covers the necessary software for your Casper development environment. To develop comfortably, you should use Linux Ubuntu 20.04 or macOS. Developing on Windows is not advised.",source:"@site/source/docs/casper/developers/prerequisites.md",sourceDirName:"developers",slug:"/developers/prerequisites",permalink:"/developers/prerequisites",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/prerequisites.md",tags:[],version:"current",lastUpdatedAt:1707837031,formattedLastUpdatedAt:"Feb 13, 2024",frontMatter:{},sidebar:"developers",previous:{title:"Overview",permalink:"/developers"},next:{title:"Essential Rust Crates",permalink:"/developers/essential-crates"}},d={},m=[{value:"Preparing your Development Environment",id:"preparing-your-development-environment",level:2},{value:"Installing curl",id:"install-curl",level:3},{value:"Installing essential Linux packages",id:"install-essential",level:3},{value:"Installing packages required for Casper tools",id:"install-adds",level:3},{value:"Installing cargo on Linux",id:"install-linux-cargo",level:3},{value:"Installing Xcode developer tools for macOS",id:"install-xcode",level:3},{value:"Installing brew",id:"install-brew",level:3},{value:"Installing packages required for Casper tools",id:"install-adds-macos",level:3},{value:"Installing Rust",id:"install-rust",level:2},{value:"Installing the Casper Crates",id:"installing-the-casper-crates",level:2},{value:"Installing the Casper Client",id:"install-casper-client",level:2},{value:"Accessing the Casper client source code",id:"building-client-from-source",level:3},{value:"Installing CMake",id:"install-cmake",level:2},{value:"Installing an IDE",id:"installing-an-ide",level:2},{value:"Setting up a Casper Account",id:"setting-up-an-account",level:2},{value:"Creating an account",id:"creating-an-account",level:3},{value:"Generating the account hash",id:"generating-the-account-hash",level:3},{value:"Funding an Account",id:"fund-your-account",level:2},{value:"Acquiring a Node Address from the Network",id:"acquire-node-address-from-network-peers",level:2}],h={toc:m},k="wrapper";function g(e){var t=e.components,n=(0,r.Z)(e,s);return(0,l.kt)(k,(0,a.Z)({},h,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"development-prerequisites"},"Development Prerequisites"),(0,l.kt)("p",null,"This page covers the necessary software for your Casper development environment. To develop comfortably, you should use ",(0,l.kt)("inlineCode",{parentName:"p"},"Linux Ubuntu 20.04")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"macOS"),". Developing on Windows is not advised."),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"Casper does not officially support ",(0,l.kt)("inlineCode",{parentName:"p"},"macOS"),". If you encounter any problems, reach out to the community on ",(0,l.kt)("a",{parentName:"p",href:"https://t.me/casperblockchain"},"Telegram")," or ",(0,l.kt)("a",{parentName:"p",href:"https://discord.com/invite/casperblockchain"},"Discord"),".")),(0,l.kt)("h2",{id:"preparing-your-development-environment"},"Preparing your Development Environment"),(0,l.kt)(o.Z,{mdxType:"Tabs"},(0,l.kt)(i.Z,{value:"Linux",label:"Linux",mdxType:"TabItem"},(0,l.kt)("h3",{id:"install-curl"},"Installing ",(0,l.kt)("inlineCode",{parentName:"h3"},"curl")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install curl\n")),(0,l.kt)("h3",{id:"install-essential"},"Installing essential Linux packages"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install build-essential\n")),(0,l.kt)("h3",{id:"install-adds"},"Installing packages required for Casper tools"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get install pkg-config\nsudo apt-get install openssl\nsudo apt-get install libssl-dev\n")),(0,l.kt)("h3",{id:"install-linux-cargo"},"Installing ",(0,l.kt)("inlineCode",{parentName:"h3"},"cargo")," on Linux"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install cargo\n"))),(0,l.kt)(i.Z,{value:"macOS",label:"macOS",mdxType:"TabItem"},(0,l.kt)("h3",{id:"install-xcode"},"Installing Xcode developer tools for macOS"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"xcode-select --install\n")),(0,l.kt)("p",null,"Verify the installation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"xcode-select -p\n")),(0,l.kt)("h3",{id:"install-brew"},"Installing ",(0,l.kt)("inlineCode",{parentName:"h3"},"brew")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"\n')),(0,l.kt)("h3",{id:"install-adds-macos"},"Installing packages required for Casper tools"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"brew install pkg-config\nbrew install openssl\n")))),(0,l.kt)("h2",{id:"install-rust"},"Installing Rust"),(0,l.kt)("p",null,"Install the ",(0,l.kt)("a",{parentName:"p",href:"https://www.rust-lang.org"},"Rust programming language")," if you don't already have it on your computer."),(0,l.kt)("p",null,"The ",(0,l.kt)("a",{parentName:"p",href:"https://www.rust-lang.org/tools/install"},"official Rust guide")," recommends installing Rust by using ",(0,l.kt)("inlineCode",{parentName:"p"},"curl"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n")),(0,l.kt)("p",null,"After your next login, the installation script automatically adds Rust to your system PATH. To start using Rust immediately, run the following command in your shell instead of restarting your terminal. The command will add Rust to your system PATH."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"source $HOME/.cargo/env\n")),(0,l.kt)("p",null,"Verify the installation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"rustup --version\n")),(0,l.kt)("p",null,"Note: You can also use ",(0,l.kt)("inlineCode",{parentName:"p"},"brew")," on MacOS or ",(0,l.kt)("inlineCode",{parentName:"p"},"apt")," on Linux to install Rust."),(0,l.kt)("h2",{id:"installing-the-casper-crates"},"Installing the Casper Crates"),(0,l.kt)("p",null,"The best and fastest way to set up a Casper Rust project is to use ",(0,l.kt)("a",{parentName:"p",href:"https://crates.io/crates/cargo-casper"},"cargo casper"),", which is the command line tool for creating a Wasm smart contract and tests for use on a Casper network. This tool will create a simple contract, a runtime environment, and a testing framework with a simple test. ",(0,l.kt)("em",{parentName:"p"},"Cargo")," is a build system and package manager for Rust (much like ",(0,l.kt)("em",{parentName:"p"},"pip")," if you are familiar with Python, or ",(0,l.kt)("em",{parentName:"p"},"npm")," and ",(0,l.kt)("em",{parentName:"p"},"yarn")," for those familiar with Javascript). It is also possible to use this configuration in your CI/CD pipeline."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cargo install cargo-casper\n")),(0,l.kt)("p",null,"If you run into any issues with this command and you have not recently installed Rust from scratch, please make sure to update your Rust version with this command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"rustup update\n")),(0,l.kt)("p",null,"Verify the installation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cargo-casper --version\n")),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("p",{parentName:"admonition"},"Familiarize yourself with the essential Casper crates described ",(0,l.kt)("a",{parentName:"p",href:"/developers/essential-crates"},"here"),".")),(0,l.kt)("h2",{id:"install-casper-client"},"Installing the Casper Client"),(0,l.kt)("p",null,"The default Casper client is on ",(0,l.kt)("a",{parentName:"p",href:"https://crates.io/crates/casper-client"},"crates.io"),". This client can transmit your deploys to a Casper network."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cargo install casper-client\n")),(0,l.kt)("p",null,"Verify the installation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client --version\n")),(0,l.kt)("p",null,"The Casper client can print out help information, which provides an up-to-date list of supported commands. To do so, use the following command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client --help\n")),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"help")," for each command to get the most up-to-date arguments and descriptions."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client --help\n")),(0,l.kt)("h3",{id:"building-client-from-source"},"Accessing the Casper client source code"),(0,l.kt)("p",null,"You can access the Casper client source code ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/casper-client-rs"},"here"),". The ",(0,l.kt)("inlineCode",{parentName:"p"},"lib")," directory contains the source for the client library, which may be called directly rather than through the CLI binary. The CLI app ",(0,l.kt)("inlineCode",{parentName:"p"},"casper-client")," uses this library to implement its functionality."),(0,l.kt)("p",null,"If you wish to compile it, you will need to first install the nightly Rust toolchain with this command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"rustup toolchain install nightly\n")),(0,l.kt)("p",null,"Then, compile the source code:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cargo build --release\n")),(0,l.kt)("p",null,"You will find the ",(0,l.kt)("inlineCode",{parentName:"p"},"casper-client")," executable in the ",(0,l.kt)("inlineCode",{parentName:"p"},"target/release")," directory."),(0,l.kt)("h2",{id:"install-cmake"},"Installing CMake"),(0,l.kt)("p",null,"If you plan to compile contracts from the source code, including those provided in the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository, install ",(0,l.kt)("inlineCode",{parentName:"p"},"CMake")," with the commands below."),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://cmake.org/"},"CMake")," is a popular build tool that we will use, and you may have it installed. If you do, make sure that you have the latest version. If you need to install or upgrade it, follow the steps below or on the ",(0,l.kt)("a",{parentName:"p",href:"https://cmake.org/install/"},"CMake website"),". Once installed, check your version as shown below."),(0,l.kt)(o.Z,{mdxType:"Tabs"},(0,l.kt)(i.Z,{value:"Linux",label:"Linux",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt-get -y install cmake\n"))),(0,l.kt)(i.Z,{value:"macOS",label:"macOS",mdxType:"TabItem"},(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"brew install cmake\n")))),(0,l.kt)("p",null,"Check your version:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cmake --version\n")),(0,l.kt)("p",null,"Sample output:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cmake version 3.20.0 (or above)\n\nCMake suite maintained and supported by Kitware (kitware.com/cmake).\n")),(0,l.kt)("h2",{id:"installing-an-ide"},"Installing an IDE"),(0,l.kt)("p",null,"We advise using an integrated development environment such as Visual Studio Code (VSC) for development. There are many IDEs available for Rust development. The most popular IDEs for Rust are the following:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://code.visualstudio.com"},"Visual Studio Code")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.jetbrains.com/clion/"},"CLion")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.jetbrains.com/idea/"},"IntelliJ Idea")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.vim.org/"},"Vim"))),(0,l.kt)("p",null,"You can use any IDE you wish. Most of our documentation and examples use Visual Studio Code (VSC), a popular IDE with many extensions that might be helpful during development."),(0,l.kt)("p",null,"If you are using VSC, you might find the following extensions useful:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"CodeLLDB")," \u2013 An important extension for debugging Rust code"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"rust-analyzer")," \u2013 The official Rust language extension"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Better TOML")," \u2013 Support for formatting TOML files"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"crates")," \u2013 An extension to help manage crates"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"Error Lens")," \u2013 Enhances the programming experience by highlighting syntax errors")),(0,l.kt)("h2",{id:"setting-up-an-account"},"Setting up a Casper Account"),(0,l.kt)("p",null,"The ",(0,l.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Account")," creation process consists of two steps:"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"Creating an Account"),(0,l.kt)("li",{parentName:"ol"},"Funding the Account")),(0,l.kt)("p",null,"The following video complements the instructions below, showing you the expected output."),(0,l.kt)("p",{align:"center"},(0,l.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed?v=sA1HTPjV_bc&list=PL8oWxbJ-csEqi5FP87EJZViE2aLz6X1Mj&index=3",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,l.kt)("h3",{id:"creating-an-account"},"Creating an account"),(0,l.kt)("p",null,"The Casper blockchain uses an on-chain account-based model, uniquely identified by an ",(0,l.kt)("inlineCode",{parentName:"p"},"AccountHash")," derived from a specific ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey"),"."),(0,l.kt)("p",null,"By default, a transactional interaction with the blockchain takes the form of a ",(0,l.kt)("inlineCode",{parentName:"p"},"Deploy")," cryptographically signed by the key-pair corresponding to the ",(0,l.kt)("inlineCode",{parentName:"p"},"PublicKey")," used to create the account."),(0,l.kt)("p",null,"Users can create accounts using the ",(0,l.kt)("a",{parentName:"p",href:"/concepts/accounts-and-keys#option-1-generating-keys-using-the-casper-client-option-1-key-generation-using-the-casper-client"},"Casper command-line client"),"."),(0,l.kt)("p",null,"Alternatively, some Casper networks, such as the official Testnet and Mainnet, provide a browser-based block explorer that allows account creation as outlined ",(0,l.kt)("a",{parentName:"p",href:"/concepts/accounts-and-keys#option-2-generating-keys-using-a-block-explorer-option-2-key-generation-using-a-block-explorer"},"here"),"."),(0,l.kt)("p",null,"Use either method to generate an account and its corresponding cryptographic key-pair."),(0,l.kt)("h3",{id:"generating-the-account-hash"},"Generating the account hash"),(0,l.kt)("p",null,"As a developer, you will often use an account hash, which is a 32-byte hash of the public key. This is because responses from the node contain ",(0,l.kt)("inlineCode",{parentName:"p"},"AccountHashes")," instead of the direct hexadecimal-encoded public key. To view the account hash for a public key, use the ",(0,l.kt)("inlineCode",{parentName:"p"},"account-address")," option of the Casper CLI client:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client account-address --public-key \n")),(0,l.kt)("h2",{id:"fund-your-account"},"Funding an Account"),(0,l.kt)("p",null,"After generating the cryptographic key-pair for an Account, you must fund the account's main purse to create it on-chain."),(0,l.kt)("p",null,"On Testnet, you can fund an account by requesting test tokens according to ",(0,l.kt)("a",{parentName:"p",href:"/users/testnet-faucet"},"this guide"),". You can request test tokens ",(0,l.kt)("strong",{parentName:"p"},"only once")," for each account."),(0,l.kt)("p",null,"On Mainnet, a pre-existing account must transfer CSPR tokens to the newly created account's main purse to finalize the setup. The source account needs to transfer CSPR tokens to the hexadecimal-encoded public key of the target account. This transfer will automatically create the target account if it does not exist. Currently, this is the only way to create an account on Mainnet."),(0,l.kt)("h2",{id:"acquire-node-address-from-network-peers"},"Acquiring a Node Address from the Network"),(0,l.kt)("p",null,"Clients can interact with a node on the blockchain via requests sent to that node's JSON-RPC endpoint, ",(0,l.kt)("inlineCode",{parentName:"p"},"http://:7777")," by default."),(0,l.kt)("p",null,"The node address is the IP of a peer node."),(0,l.kt)("p",null,"Both the official Testnet and Mainnet provide block explorers that list the IP addresses of nodes on their respective networks."),(0,l.kt)("p",null,"You can get the ",(0,l.kt)("inlineCode",{parentName:"p"},"node-ip-address")," of a node on the network by visiting the following block explorers:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://testnet.cspr.live/tools/peers"},"Peers")," on Testnet"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://cspr.live/tools/peers"},"Peers")," on Mainnet")),(0,l.kt)("p",null,"You will see a list of peers, and you can select the IP of any peer on the list."),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Note"),": If the selected peer is unresponsive, pick a different peer and try again."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/74ff8362.809c279a.js b/assets/js/74ff8362.809c279a.js deleted file mode 100644 index aaa3a30cc6..0000000000 --- a/assets/js/74ff8362.809c279a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1132],{3905:function(e,t,a){a.d(t,{Zo:function(){return p},kt:function(){return d}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(a),h=r,d=u["".concat(l,".").concat(h)]||u[h]||m[h]||o;return a?n.createElement(d,i(i({ref:t},p),{},{components:a})):n.createElement(d,i({ref:t},p))}));function d(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var c=2;c=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},p=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(a),h=r,d=u["".concat(l,".").concat(h)]||u[h]||m[h]||o;return a?n.createElement(d,i(i({ref:t},p),{},{components:a})):n.createElement(d,i({ref:t},p))}));function d(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var c=2;c=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=n.createContext({}),p=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},l=function(e){var t=p(e.components);return n.createElement(u.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),c=p(r),m=o,k=c["".concat(u,".").concat(m)]||c[m]||d[m]||a;return r?n.createElement(k,s(s({ref:t},l),{},{components:r})):n.createElement(k,s({ref:t},l))}));function k(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=m;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i[c]="string"==typeof e?e:o,s[1]=i;for(var p=2;p")," in the instructions below with your username."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Use ",(0,a.kt)("a",{parentName:"p",href:"https://www.ssh.com/academy/ssh/keygen"},"ssh-keygen")," to generate a new SSH key.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Create the user with no password, as the key is your password."))),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"sudo adduser --disabled-password\n")),(0,a.kt)("ol",{start:3},(0,a.kt)("li",{parentName:"ol"},"Create authorized_keys with your key to log in.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"sudo su - \nmkdir .ssh\nchmod 700 .ssh\ntouch .ssh/authorized_keys\n")),(0,a.kt)("ol",{start:4},(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Use the editor of your choice and paste your .ssh public key i the ",(0,a.kt)("inlineCode",{parentName:"p"},".ssh/authorized_keys")," file.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Exit out of the ",(0,a.kt)("inlineCode",{parentName:"p"},"")," account and log into the root or previous sudo-er account."))),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"exit\n")),(0,a.kt)("ol",{start:6},(0,a.kt)("li",{parentName:"ol"},"Add your user to sudo-ers under the root account or your previous sudo-er account.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"sudo visudo\n")),(0,a.kt)("ol",{start:7},(0,a.kt)("li",{parentName:"ol"},"Type ",(0,a.kt)("inlineCode",{parentName:"li"}," ALL=(ALL:ALL) NOPASSWD:ALL")," below the row containing ",(0,a.kt)("inlineCode",{parentName:"li"},"root ALL=(ALL:ALL) ALL"),".")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"# User privilege specification\nroot ALL=(ALL:ALL) ALL\n ALL=(ALL:ALL) NOPASSWD:ALL\n")),(0,a.kt)("ol",{start:8},(0,a.kt)("li",{parentName:"ol"},"You should be able to log in with the key and not use the root user.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ssh -i @\n")),(0,a.kt)("p",null,"Here is an example command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ssh -i ~/.ssh/id_rsa casper@10.21.10.200\n")))}k.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5863],{3905:function(e,t,r){r.d(t,{Zo:function(){return l},kt:function(){return k}});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=n.createContext({}),p=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},l=function(e){var t=p(e.components);return n.createElement(u.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),c=p(r),m=o,k=c["".concat(u,".").concat(m)]||c[m]||d[m]||a;return r?n.createElement(k,s(s({ref:t},l),{},{components:r})):n.createElement(k,s({ref:t},l))}));function k(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=m;var i={};for(var u in t)hasOwnProperty.call(t,u)&&(i[u]=t[u]);i.originalType=e,i[c]="string"==typeof e?e:o,s[1]=i;for(var p=2;p")," in the instructions below with your username."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Use ",(0,a.kt)("a",{parentName:"p",href:"https://www.ssh.com/academy/ssh/keygen"},"ssh-keygen")," to generate a new SSH key.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Create the user with no password, as the key is your password."))),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"sudo adduser --disabled-password\n")),(0,a.kt)("ol",{start:3},(0,a.kt)("li",{parentName:"ol"},"Create authorized_keys with your key to log in.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"sudo su - \nmkdir .ssh\nchmod 700 .ssh\ntouch .ssh/authorized_keys\n")),(0,a.kt)("ol",{start:4},(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Use the editor of your choice and paste your .ssh public key i the ",(0,a.kt)("inlineCode",{parentName:"p"},".ssh/authorized_keys")," file.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Exit out of the ",(0,a.kt)("inlineCode",{parentName:"p"},"")," account and log into the root or previous sudo-er account."))),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"exit\n")),(0,a.kt)("ol",{start:6},(0,a.kt)("li",{parentName:"ol"},"Add your user to sudo-ers under the root account or your previous sudo-er account.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"sudo visudo\n")),(0,a.kt)("ol",{start:7},(0,a.kt)("li",{parentName:"ol"},"Type ",(0,a.kt)("inlineCode",{parentName:"li"}," ALL=(ALL:ALL) NOPASSWD:ALL")," below the row containing ",(0,a.kt)("inlineCode",{parentName:"li"},"root ALL=(ALL:ALL) ALL"),".")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"# User privilege specification\nroot ALL=(ALL:ALL) ALL\n ALL=(ALL:ALL) NOPASSWD:ALL\n")),(0,a.kt)("ol",{start:8},(0,a.kt)("li",{parentName:"ol"},"You should be able to log in with the key and not use the root user.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ssh -i @\n")),(0,a.kt)("p",null,"Here is an example command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"ssh -i ~/.ssh/id_rsa casper@10.21.10.200\n")))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/78143ba1.0d0f02a1.js b/assets/js/78143ba1.0d0f02a1.js new file mode 100644 index 0000000000..549620016a --- /dev/null +++ b/assets/js/78143ba1.0d0f02a1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[586],{3905:function(e,t,r){r.d(t,{Zo:function(){return i},kt:function(){return h}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),m=a,h=u["".concat(p,".").concat(m)]||u[m]||f[m]||o;return r?n.createElement(h,s(s({ref:t},i),{},{components:r})):n.createElement(h,s({ref:t},i))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=m;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),m=a,h=u["".concat(p,".").concat(m)]||u[m]||f[m]||o;return r?n.createElement(h,s(s({ref:t},i),{},{components:r})):n.createElement(h,s({ref:t},i))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=m;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var d=a.createContext({}),p=function(e){var t=a.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},m=function(e){var t=p(e.components);return a.createElement(d.Provider,{value:t},e.children)},s="mdxType",k={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,d=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),s=p(n),h=i,c=s["".concat(d,".").concat(h)]||s[h]||k[h]||r;return n?a.createElement(c,l(l({ref:t},m),{},{components:n})):a.createElement(c,l({ref:t},m))}));function c(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=h;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[s]="string"==typeof e?e:i,l[1]=o;for(var p=2;p")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"cep78_contract_package_access_"),"."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"V_1_0_standard"),": This modality will signal the contract to attempt to upgrade from version 1.0 to version 1.1.1. In this scenario, the contract will retrieve the package hash and the access URef from the ",(0,r.kt)("inlineCode",{parentName:"li"},"NamedKey")," entries originally created during the 1.0 installation."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"V_1_0_custom"),": This modality will signal the contract to attempt to upgrade from version 1.0 to version 1.1.1. In this scenario, the calling account must provide the ",(0,r.kt)("inlineCode",{parentName:"li"},"NamedKey")," entries under which the package hash and the access URef are saved. Additionally, this requires the passing of the runtime arguments ",(0,r.kt)("inlineCode",{parentName:"li"},"access_key_name")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"hash_key_name")," for the access URef and package hash, respectively. In this modality, these arguments are required and must be passed in.")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"NamedKeyConvention"),(0,r.kt)("th",{parentName:"tr",align:null},"u8"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"DerivedFromCollectionName"),(0,r.kt)("td",{parentName:"tr",align:null},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"V_1_0_standard"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"V_1_0_custom"),(0,r.kt)("td",{parentName:"tr",align:null},"2")))),(0,r.kt)("h2",{id:"eventsmode"},"EventsMode"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"EventsMode")," modality determines how the installed instance of CEP-78 will handle the recording of events that occur from interacting with the contract."),(0,r.kt)("p",null,"The modality provides three options:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"NoEvents"),": This modality will signal the contract to not record events at all. This is the default mode."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"CEP47"),": This modality will signal the contract to record events using the CEP47 event schema. Further information can be found ",(0,r.kt)("a",{parentName:"li",href:"#cep47-mode"},"below"),"."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"CES"),": This modality will signal the contract to record events using the ",(0,r.kt)("a",{parentName:"li",href:"#casper-event-standard"},"Casper Event Standard"),".")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"EventsMode"),(0,r.kt)("th",{parentName:"tr",align:null},"u8"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"NoEvents"),(0,r.kt)("td",{parentName:"tr",align:null},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"CEP47"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"CES"),(0,r.kt)("td",{parentName:"tr",align:null},"2")))),(0,r.kt)("h3",{id:"transfer-filter-hook"},"Transfer Filter Hook"),(0,r.kt)("p",null,"The transfer filter modality, if enabled, specifies a contract package hash pointing to a contract that will be called when the ",(0,r.kt)("inlineCode",{parentName:"p"},"transfer")," method is invoked on the contract. CEP-78 will call the ",(0,r.kt)("inlineCode",{parentName:"p"},"can_transfer")," method on the specified callback contract, which is expected to return a value of ",(0,r.kt)("inlineCode",{parentName:"p"},"TransferFilterContractResult"),", represented as a u8."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferFilterContractResult::DenyTransfer")," will block the transfer regardless of the outcome of other checks"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferFilterContractResult::ProceedTransfer")," will allow the transfer to proceed if other checks also pass")),(0,r.kt)("p",null,"The transfer filter can be enabled by passing a ",(0,r.kt)("inlineCode",{parentName:"p"},"ARG_TRANSFER_FILTER_CONTRACT")," argument to the install method, with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Option")),(0,r.kt)("h3",{id:"cep47-mode"},"CEP47 Mode"),(0,r.kt)("p",null,"The CEP47 ",(0,r.kt)("inlineCode",{parentName:"p"},"EventsMode")," modality mimics the event schema previously used in the CEP47 NFT standard. Events are stored as a ",(0,r.kt)("inlineCode",{parentName:"p"},"BTreeMap")," within a dictionary (",(0,r.kt)("inlineCode",{parentName:"p"},"EVENTS"),") in the contract's context. Entries consist of the ",(0,r.kt)("inlineCode",{parentName:"p"},"PREFIX_HASH_KEY_NAME"),", followed by the ",(0,r.kt)("inlineCode",{parentName:"p"},"EVENT_TYPE")," and then variable data as listed in the table below. The events can be retrieved directly via their dictionary entry using the JSON-RPC, with more information on this process available ",(0,r.kt)("a",{parentName:"p",href:"./concepts/dictionaries"},"here"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Event name"),(0,r.kt)("th",{parentName:"tr",align:null},"Included values and type"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Mint"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"recipient (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Transfer"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Option)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"recipient (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Burn"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalGranted"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"spender (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalRevoked"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalForAll"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Key)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"RevokedForAll"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Key)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"MetadataUpdate"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Migration"),(0,r.kt)("td",{parentName:"tr",align:null},"-")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"VariablesSet"),(0,r.kt)("td",{parentName:"tr",align:null},"-")))),(0,r.kt)("h3",{id:"casper-event-standard"},"Casper Event Standard"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"CES")," is an option within the ",(0,r.kt)("inlineCode",{parentName:"p"},"EventsMode")," modality that determines how changes to tokens issued by the contract instance will be recorded. Any changes are recorded in the ",(0,r.kt)("inlineCode",{parentName:"p"},"__events")," dictionary and can be observed via a node's Server Side Events stream. They may also be viewed by querying the dictionary at any time using the JSON-RPC interface."),(0,r.kt)("p",null,"The emitted events are encoded according to the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/make-software/casper-event-standard"},"Casper Event Standard"),", and the schema is visible to an observer reading the ",(0,r.kt)("inlineCode",{parentName:"p"},"__events_schema")," contract named key."),(0,r.kt)("p",null,"For this CEP-78 reference implementation, the events schema is as follows:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Event name"),(0,r.kt)("th",{parentName:"tr",align:null},"Included values and type"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Mint"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"recipient (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"data (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Transfer"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Option)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"recipient (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Burn"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Approval"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"spender (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalRevoked"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalForAll"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Key)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"RevokedForAll"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Key)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"MetadataUpdated"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"data (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Migration"),(0,r.kt)("td",{parentName:"tr",align:null},"-")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"VariablesSet"),(0,r.kt)("td",{parentName:"tr",align:null},"-")))),(0,r.kt)("h2",{id:"modality-conflicts"},"Modality Conflicts"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"MetadataMutability")," option set to ",(0,r.kt)("inlineCode",{parentName:"p"},"Mutable")," cannot be used in conjunction with the ",(0,r.kt)("inlineCode",{parentName:"p"},"NFTIdentifierMode")," modality set to ",(0,r.kt)("inlineCode",{parentName:"p"},"Hash"),"."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/796e8b5d.b35a5fde.js b/assets/js/796e8b5d.b35a5fde.js new file mode 100644 index 0000000000..c9afe749bb --- /dev/null +++ b/assets/js/796e8b5d.b35a5fde.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3013],{3905:function(e,t,n){n.d(t,{Zo:function(){return m},kt:function(){return c}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var d=a.createContext({}),p=function(e){var t=a.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},m=function(e){var t=p(e.components);return a.createElement(d.Provider,{value:t},e.children)},s="mdxType",k={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,d=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),s=p(n),h=i,c=s["".concat(d,".").concat(h)]||s[h]||k[h]||r;return n?a.createElement(c,l(l({ref:t},m),{},{components:n})):a.createElement(c,l({ref:t},m))}));function c(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=h;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[s]="string"==typeof e?e:i,l[1]=o;for(var p=2;p")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"cep78_contract_package_access_"),"."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"V_1_0_standard"),": This modality will signal the contract to attempt to upgrade from version 1.0 to version 1.1.1. In this scenario, the contract will retrieve the package hash and the access URef from the ",(0,r.kt)("inlineCode",{parentName:"li"},"NamedKey")," entries originally created during the 1.0 installation."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"V_1_0_custom"),": This modality will signal the contract to attempt to upgrade from version 1.0 to version 1.1.1. In this scenario, the calling account must provide the ",(0,r.kt)("inlineCode",{parentName:"li"},"NamedKey")," entries under which the package hash and the access URef are saved. Additionally, this requires the passing of the runtime arguments ",(0,r.kt)("inlineCode",{parentName:"li"},"access_key_name")," and ",(0,r.kt)("inlineCode",{parentName:"li"},"hash_key_name")," for the access URef and package hash, respectively. In this modality, these arguments are required and must be passed in.")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"NamedKeyConvention"),(0,r.kt)("th",{parentName:"tr",align:null},"u8"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"DerivedFromCollectionName"),(0,r.kt)("td",{parentName:"tr",align:null},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"V_1_0_standard"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"V_1_0_custom"),(0,r.kt)("td",{parentName:"tr",align:null},"2")))),(0,r.kt)("h2",{id:"eventsmode"},"EventsMode"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"EventsMode")," modality determines how the installed instance of CEP-78 will handle the recording of events that occur from interacting with the contract."),(0,r.kt)("p",null,"The modality provides three options:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"NoEvents"),": This modality will signal the contract to not record events at all. This is the default mode."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"CEP47"),": This modality will signal the contract to record events using the CEP47 event schema. Further information can be found ",(0,r.kt)("a",{parentName:"li",href:"#cep47-mode"},"below"),"."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"CES"),": This modality will signal the contract to record events using the ",(0,r.kt)("a",{parentName:"li",href:"#casper-event-standard"},"Casper Event Standard"),".")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"EventsMode"),(0,r.kt)("th",{parentName:"tr",align:null},"u8"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"NoEvents"),(0,r.kt)("td",{parentName:"tr",align:null},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"CEP47"),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"CES"),(0,r.kt)("td",{parentName:"tr",align:null},"2")))),(0,r.kt)("h3",{id:"transfer-filter-hook"},"Transfer Filter Hook"),(0,r.kt)("p",null,"The transfer filter modality, if enabled, specifies a contract package hash pointing to a contract that will be called when the ",(0,r.kt)("inlineCode",{parentName:"p"},"transfer")," method is invoked on the contract. CEP-78 will call the ",(0,r.kt)("inlineCode",{parentName:"p"},"can_transfer")," method on the specified callback contract, which is expected to return a value of ",(0,r.kt)("inlineCode",{parentName:"p"},"TransferFilterContractResult"),", represented as a u8."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferFilterContractResult::DenyTransfer")," will block the transfer regardless of the outcome of other checks"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"TransferFilterContractResult::ProceedTransfer")," will allow the transfer to proceed if other checks also pass")),(0,r.kt)("p",null,"The transfer filter can be enabled by passing a ",(0,r.kt)("inlineCode",{parentName:"p"},"ARG_TRANSFER_FILTER_CONTRACT")," argument to the install method, with a value of type ",(0,r.kt)("inlineCode",{parentName:"p"},"Option")),(0,r.kt)("h3",{id:"cep47-mode"},"CEP47 Mode"),(0,r.kt)("p",null,"The CEP47 ",(0,r.kt)("inlineCode",{parentName:"p"},"EventsMode")," modality mimics the event schema previously used in the CEP47 NFT standard. Events are stored as a ",(0,r.kt)("inlineCode",{parentName:"p"},"BTreeMap")," within a dictionary (",(0,r.kt)("inlineCode",{parentName:"p"},"EVENTS"),") in the contract's context. Entries consist of the ",(0,r.kt)("inlineCode",{parentName:"p"},"PREFIX_HASH_KEY_NAME"),", followed by the ",(0,r.kt)("inlineCode",{parentName:"p"},"EVENT_TYPE")," and then variable data as listed in the table below. The events can be retrieved directly via their dictionary entry using the JSON-RPC, with more information on this process available ",(0,r.kt)("a",{parentName:"p",href:"./concepts/dictionaries"},"here"),"."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Event name"),(0,r.kt)("th",{parentName:"tr",align:null},"Included values and type"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Mint"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"recipient (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Transfer"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Option)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"recipient (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Burn"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalGranted"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"spender (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalRevoked"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalForAll"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Key)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"RevokedForAll"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Key)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"MetadataUpdate"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Migration"),(0,r.kt)("td",{parentName:"tr",align:null},"-")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"VariablesSet"),(0,r.kt)("td",{parentName:"tr",align:null},"-")))),(0,r.kt)("h3",{id:"casper-event-standard"},"Casper Event Standard"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"CES")," is an option within the ",(0,r.kt)("inlineCode",{parentName:"p"},"EventsMode")," modality that determines how changes to tokens issued by the contract instance will be recorded. Any changes are recorded in the ",(0,r.kt)("inlineCode",{parentName:"p"},"__events")," dictionary and can be observed via a node's Server Side Events stream. They may also be viewed by querying the dictionary at any time using the JSON-RPC interface."),(0,r.kt)("p",null,"The emitted events are encoded according to the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/make-software/casper-event-standard"},"Casper Event Standard"),", and the schema is visible to an observer reading the ",(0,r.kt)("inlineCode",{parentName:"p"},"__events_schema")," contract named key."),(0,r.kt)("p",null,"For this CEP-78 reference implementation, the events schema is as follows:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Event name"),(0,r.kt)("th",{parentName:"tr",align:null},"Included values and type"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Mint"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"recipient (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"data (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Transfer"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Option)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"recipient (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Burn"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Approval"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"spender (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalRevoked"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"ApprovalForAll"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Key)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"RevokedForAll"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"owner (Key)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"operator (Key)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"MetadataUpdated"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"token_id (String)"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"data (String)"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Migration"),(0,r.kt)("td",{parentName:"tr",align:null},"-")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"VariablesSet"),(0,r.kt)("td",{parentName:"tr",align:null},"-")))),(0,r.kt)("h2",{id:"modality-conflicts"},"Modality Conflicts"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"MetadataMutability")," option set to ",(0,r.kt)("inlineCode",{parentName:"p"},"Mutable")," cannot be used in conjunction with the ",(0,r.kt)("inlineCode",{parentName:"p"},"NFTIdentifierMode")," modality set to ",(0,r.kt)("inlineCode",{parentName:"p"},"Hash"),"."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7adc1d42.2f67eb3e.js b/assets/js/7adc1d42.2f67eb3e.js new file mode 100644 index 0000000000..477e60b67d --- /dev/null +++ b/assets/js/7adc1d42.2f67eb3e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9889],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var s=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,s)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(s=0;s=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=s.createContext({}),l=function(e){var t=s.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return s.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return s.createElement(s.Fragment,{},t)}},h=s.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||a;return n?s.createElement(m,i(i({ref:t},p),{},{components:n})):s.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=h;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[u]="string"==typeof e?e:r,i[1]=o;for(var l=2;l{\n // Test function implementation\n}\n")),(0,a.kt)("p",null,"This ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/blob/236bb18b9e98da7f9d8706f5e4825494845cfec2/tests/src/integration_tests.rs#L15-L55"},"unit test")," is a good example of testing session code. At a high level, the test follows this process:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Initialize an instance of the execution engine and the ",(0,a.kt)("inlineCode",{parentName:"li"},"InMemoryWasmTestBuilder"),".")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," let mut builder = InMemoryWasmTestBuilder::default();\n")),(0,a.kt)("ol",{start:2},(0,a.kt)("li",{parentName:"ol"},"Execute the genesis process.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," builder.run_genesis(&*DEFAULT_RUN_GENESIS_REQUEST).commit();\n")),(0,a.kt)("ol",{start:3},(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Execute the test-specific logic. In this example, retrieve information about the account running the session code and its associated keys. For full details, visit ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/blob/236bb18b9e98da7f9d8706f5e4825494845cfec2/tests/src/integration_tests.rs#L15-L55"},"GitHub"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Retrieve runtime arguments, which should be the same as defined in the contract.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Create the execution request that sets up the session code to be processed. In this example, the ",(0,a.kt)("inlineCode",{parentName:"p"},"CONTRACT_WASM")," is the session code."))),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," let execute_request =\n ExecuteRequestBuilder::standard(*DEFAULT_ACCOUNT_ADDR, CONTRACT_WASM, runtime_args)\n .build();\n")),(0,a.kt)("ol",{start:6},(0,a.kt)("li",{parentName:"ol"},"Invoke the execution engine to process the session code.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," builder.exec(execute_request).expect_success().commit();\n")),(0,a.kt)("ol",{start:7},(0,a.kt)("li",{parentName:"ol"},"Verify that the results match the expected output. This example checks the associated keys.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," assert!(associated_keys.contains_key(&ASSOCIATED_ACCOUNT_HASH));\n")),(0,a.kt)("h3",{id:"running-the-test"},"Running the Test"),(0,a.kt)("p",null,"This example uses a ",(0,a.kt)("inlineCode",{parentName:"p"},"Makefile")," to run the tests."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"make test\n")),(0,a.kt)("p",null,"Under the hood, the ",(0,a.kt)("inlineCode",{parentName:"p"},"Makefile")," generates a ",(0,a.kt)("inlineCode",{parentName:"p"},"tests/wasm")," folder, copies the Wasm to the folder, and runs the tests with ",(0,a.kt)("inlineCode",{parentName:"p"},"cargo test"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir -p tests/wasm\ncp contract/target/wasm32-unknown-unknown/release/contract.wasm tests/wasm\ncd tests && cargo test\n")),(0,a.kt)("h3",{id:"other-examples"},"Other Examples"),(0,a.kt)("p",null,"In the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/tests/src/integration_tests.rs"},"counter unit tests"),", we use session code to call the contract. The code loads the account that pays for the session code, the session code Wasm, and the runtime arguments. Then, the code invokes the execution engine to process the session code."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," // Use session code to increment the counter.\n let session_code_request = ExecuteRequestBuilder::standard(\n *DEFAULT_ACCOUNT_ADDR,\n COUNTER_CALL_WASM,\n runtime_args! {\n CONTRACT_KEY => contract_v1_hash\n },\n )\n .build();\n\n builder.exec(session_code_request)\n .expect_success()\n .commit();\n")),(0,a.kt)("p",null,"The verification step looks like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"},'\n let incremented_count = builder\n .query(None, count_key, &[])\n .expect("should be stored value.")\n .as_cl_value()\n .expect("should be cl value.")\n .clone()\n .into_t::()\n .expect("should be i32.");\n\n assert_eq!(incremented_count, 1);\n')),(0,a.kt)("p",null,"For many more examples, visit the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/test"},"casper-node")," GitHub repository."),(0,a.kt)("h2",{id:"video-walkthrough"},"Video Walkthrough"),(0,a.kt)("p",null,"The following brief video describes testing the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/"},"sample session code")," for configuring an account."),(0,a.kt)("p",{align:"center"},(0,a.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed?v=sUg0nh3K3iQ&list=PL8oWxbJ-csEqi5FP87EJZViE2aLz6X1Mj&index=5",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,a.kt)("h2",{id:"whats-next"},"What's Next?"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Learn to ",(0,a.kt)("a",{parentName:"li",href:"/developers/cli/installing-contracts"},"install a contract and query global state"),".")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7adc1d42.a69324a3.js b/assets/js/7adc1d42.a69324a3.js deleted file mode 100644 index 7bd515f35f..0000000000 --- a/assets/js/7adc1d42.a69324a3.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9889],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var s=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);t&&(s=s.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,s)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(s=0;s=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=s.createContext({}),l=function(e){var t=s.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return s.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return s.createElement(s.Fragment,{},t)}},h=s.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=l(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||a;return n?s.createElement(m,i(i({ref:t},p),{},{components:n})):s.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=h;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[u]="string"==typeof e?e:r,i[1]=o;for(var l=2;l{\n // Test function implementation\n}\n")),(0,a.kt)("p",null,"This ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/blob/236bb18b9e98da7f9d8706f5e4825494845cfec2/tests/src/integration_tests.rs#L15-L55"},"unit test")," is a good example of testing session code. At a high level, the test follows this process:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Initialize an instance of the execution engine and the ",(0,a.kt)("inlineCode",{parentName:"li"},"InMemoryWasmTestBuilder"),".")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," let mut builder = InMemoryWasmTestBuilder::default();\n")),(0,a.kt)("ol",{start:2},(0,a.kt)("li",{parentName:"ol"},"Execute the genesis process.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," builder.run_genesis(&*DEFAULT_RUN_GENESIS_REQUEST).commit();\n")),(0,a.kt)("ol",{start:3},(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Execute the test-specific logic. In this example, retrieve information about the account running the session code and its associated keys. For full details, visit ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/blob/236bb18b9e98da7f9d8706f5e4825494845cfec2/tests/src/integration_tests.rs#L15-L55"},"GitHub"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Retrieve runtime arguments, which should be the same as defined in the contract.")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Create the execution request that sets up the session code to be processed. In this example, the ",(0,a.kt)("inlineCode",{parentName:"p"},"CONTRACT_WASM")," is the session code."))),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," let execute_request =\n ExecuteRequestBuilder::standard(*DEFAULT_ACCOUNT_ADDR, CONTRACT_WASM, runtime_args)\n .build();\n")),(0,a.kt)("ol",{start:6},(0,a.kt)("li",{parentName:"ol"},"Invoke the execution engine to process the session code.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," builder.exec(execute_request).expect_success().commit();\n")),(0,a.kt)("ol",{start:7},(0,a.kt)("li",{parentName:"ol"},"Verify that the results match the expected output. This example checks the associated keys.")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," assert!(associated_keys.contains_key(&ASSOCIATED_ACCOUNT_HASH));\n")),(0,a.kt)("h3",{id:"running-the-test"},"Running the Test"),(0,a.kt)("p",null,"This example uses a ",(0,a.kt)("inlineCode",{parentName:"p"},"Makefile")," to run the tests."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"make test\n")),(0,a.kt)("p",null,"Under the hood, the ",(0,a.kt)("inlineCode",{parentName:"p"},"Makefile")," generates a ",(0,a.kt)("inlineCode",{parentName:"p"},"tests/wasm")," folder, copies the Wasm to the folder, and runs the tests with ",(0,a.kt)("inlineCode",{parentName:"p"},"cargo test"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir -p tests/wasm\ncp contract/target/wasm32-unknown-unknown/release/contract.wasm tests/wasm\ncd tests && cargo test\n")),(0,a.kt)("h3",{id:"other-examples"},"Other Examples"),(0,a.kt)("p",null,"In the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/tests/src/integration_tests.rs"},"counter unit tests"),", we use session code to call the contract. The code loads the account that pays for the session code, the session code Wasm, and the runtime arguments. Then, the code invokes the execution engine to process the session code."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"}," // Use session code to increment the counter.\n let session_code_request = ExecuteRequestBuilder::standard(\n *DEFAULT_ACCOUNT_ADDR,\n COUNTER_CALL_WASM,\n runtime_args! {\n CONTRACT_KEY => contract_v1_hash\n },\n )\n .build();\n\n builder.exec(session_code_request)\n .expect_success()\n .commit();\n")),(0,a.kt)("p",null,"The verification step looks like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"},'\n let incremented_count = builder\n .query(None, count_key, &[])\n .expect("should be stored value.")\n .as_cl_value()\n .expect("should be cl value.")\n .clone()\n .into_t::()\n .expect("should be i32.");\n\n assert_eq!(incremented_count, 1);\n')),(0,a.kt)("p",null,"For many more examples, visit the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/test"},"casper-node")," GitHub repository."),(0,a.kt)("h2",{id:"video-walkthrough"},"Video Walkthrough"),(0,a.kt)("p",null,"The following brief video describes testing the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/"},"sample session code")," for configuring an account."),(0,a.kt)("p",{align:"center"},(0,a.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed?v=sUg0nh3K3iQ&list=PL8oWxbJ-csEqi5FP87EJZViE2aLz6X1Mj&index=5",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,a.kt)("h2",{id:"whats-next"},"What's Next?"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Learn to ",(0,a.kt)("a",{parentName:"li",href:"/developers/cli/installing-contracts"},"install a contract and query global state"),".")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7c09a624.6d653f8c.js b/assets/js/7c09a624.6d653f8c.js new file mode 100644 index 0000000000..b13746477d --- /dev/null +++ b/assets/js/7c09a624.6d653f8c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6439],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=u(n),h=a,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||o;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:a,i[1]=c;for(var u=2;u donating_account_key\n },\n );\n system::transfer_from_purse_to_purse(\n account::get_main_purse(),\n donating_purse_uref,\n donation_amount,\n None\n )\n .unwrap_or_revert()\n}\n\n')),(0,o.kt)("p",null,"This session code calls into a contract's entry point by using ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime::call_contract"),", supplying the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract_hash")," to identify the contract to be called, and the name of the entry point to be invoked, in this case ",(0,o.kt)("inlineCode",{parentName:"p"},"donate"),". It supplies the ",(0,o.kt)("inlineCode",{parentName:"p"},"donating_account_key"),", which in this case is the account key of the caller. The contract will then provide a return value, in this case ",(0,o.kt)("inlineCode",{parentName:"p"},"donating_purse_uref"),". To call an entry point, you will need to know the ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_cl"},"CLType")," of the return value and identify it within the code."),(0,o.kt)("p",null,"You can determine the type of the return value by ",(0,o.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#querying-an-account"},"querying the contract object")," in global state. To query a contract rather than an account, replace the key parameter with the formatted string representation of the contract hash."),(0,o.kt)("p",null,"This example code takes that returned value and transfers a ",(0,o.kt)("inlineCode",{parentName:"p"},"donation_amount")," from the calling account's main purse to the established donation purse. It is not necessary for the code to store, or even use, the returned value. Use of the returned value depends on the needs of the developer."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7c09a624.9fc3f656.js b/assets/js/7c09a624.9fc3f656.js deleted file mode 100644 index 8e6b6597d2..0000000000 --- a/assets/js/7c09a624.9fc3f656.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6439],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=u(n),h=a,m=d["".concat(s,".").concat(h)]||d[h]||p[h]||o;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:a,i[1]=c;for(var u=2;u donating_account_key\n },\n );\n system::transfer_from_purse_to_purse(\n account::get_main_purse(),\n donating_purse_uref,\n donation_amount,\n None\n )\n .unwrap_or_revert()\n}\n\n')),(0,o.kt)("p",null,"This session code calls into a contract's entry point by using ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime::call_contract"),", supplying the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract_hash")," to identify the contract to be called, and the name of the entry point to be invoked, in this case ",(0,o.kt)("inlineCode",{parentName:"p"},"donate"),". It supplies the ",(0,o.kt)("inlineCode",{parentName:"p"},"donating_account_key"),", which in this case is the account key of the caller. The contract will then provide a return value, in this case ",(0,o.kt)("inlineCode",{parentName:"p"},"donating_purse_uref"),". To call an entry point, you will need to know the ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_cl"},"CLType")," of the return value and identify it within the code."),(0,o.kt)("p",null,"You can determine the type of the return value by ",(0,o.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#querying-an-account"},"querying the contract object")," in global state. To query a contract rather than an account, replace the key parameter with the formatted string representation of the contract hash."),(0,o.kt)("p",null,"This example code takes that returned value and transfers a ",(0,o.kt)("inlineCode",{parentName:"p"},"donation_amount")," from the calling account's main purse to the established donation purse. It is not necessary for the code to store, or even use, the returned value. Use of the returned value depends on the needs of the developer."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7d846783.42c2fcea.js b/assets/js/7d846783.42c2fcea.js deleted file mode 100644 index 916870fed4..0000000000 --- a/assets/js/7d846783.42c2fcea.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1002],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),m=r,h=d["".concat(c,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},p),{},{components:n})):a.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:r,i[1]=s;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),m=r,h=d["".concat(c,".").concat(m)]||d[m]||u[m]||o;return n?a.createElement(h,i(i({ref:t},p),{},{components:n})):a.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:r,i[1]=s;for(var l=2;l=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),d=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},u=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",_={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=d(a),p=r,h=c["".concat(l,".").concat(p)]||c[p]||_[p]||i;return a?n.createElement(h,o(o({ref:t},u),{},{components:a})):n.createElement(h,o({ref:t},u))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,o[1]=s;for(var d=2;dadd_keys.wasm",id:"add_keyswasm",level:4},{value:"contract_call.wasm",id:"contract_callwasm",level:4},{value:"Testing this example",id:"testing-this-example",level:3},{value:"Test 1: should_allow_install_contract_with_default_account",id:"test-1-should_allow_install_contract_with_default_account",level:4},{value:"Test 2: should_disallow_install_with_non_added_authorization_key",id:"test-2-should_disallow_install_with_non_added_authorization_key",level:4},{value:"Test 3: should_allow_install_with_added_authorization_key",id:"test-3-should_allow_install_with_added_authorization_key",level:4},{value:"Test 4: should_allow_entry_point_with_installer_authorization_key",id:"test-4-should_allow_entry_point_with_installer_authorization_key",level:4},{value:"Test 5: should_allow_entry_point_with_account_authorization_key",id:"test-5-should_allow_entry_point_with_account_authorization_key",level:4},{value:"Test 6: should_disallow_entry_point_without_authorization_key",id:"test-6-should_disallow_entry_point_without_authorization_key",level:4},{value:"Test 7: should_allow_entry_point_through_contract_call_with_authorization_key",id:"test-7-should_allow_entry_point_through_contract_call_with_authorization_key",level:4},{value:"Test 8: should_disallow_entry_point_through_contract_call_without_authorization_key",id:"test-8-should_disallow_entry_point_through_contract_call_without_authorization_key",level:4}],_={toc:c},p="wrapper";function h(e){var t=e.components,a=(0,r.Z)(e,o);return(0,i.kt)(p,(0,n.Z)({},_,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"working-with-authorization-keys"},"Working with Authorization Keys"),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"These examples should not be used in a production environment. They are intended only for teaching and must be tested and adapted for production use.")),(0,i.kt)("p",null,"This tutorial demonstrates retrieving and using the authorization keys associated with a deploy using the ",(0,i.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.list_authorization_keys.html"},"list_authorization_keys")," function."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let authorization_keys = runtime::list_authorization_keys();\n")),(0,i.kt)("p",null,"Remember that authorization keys are listed under a Deploy's ",(0,i.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#serialization-standard-deploy"},"approvals")," section, which lists the signatures and the public keys of the signers, also called authorizing keys. Here is an example of a deploy's approvals:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"approvals": [\n {\n "signer": "02021a4da3d6f32ea3ebd2519e1a37a1b811671085bf4f1cf2a36b931344a99b756a",\n "signature": "02df8cdf0bff3bd93e831d24563d5acbefa0ed13814550e910d03208d5fb3c11770dd3d918784ec84342e53666eacf59aeecbf4ce0cdd60e167c4a4b20e4b8f481"\n }\n]\n')),(0,i.kt)("p",null,"The contract code in this example retrieves the set of authorization keys for a given deploy by calling the ",(0,i.kt)("inlineCode",{parentName:"p"},"runtime::list_authorization_keys")," function. In other words, ",(0,i.kt)("inlineCode",{parentName:"p"},"list_authorization_keys")," returns the set of account hashes representing the keys used to sign a deploy. Upon installation, the contract code stores the authorization keys for the installer deploy into a NamedKey. The contract also contains an entry point that returns the intersection of the caller deploy's, and installer deploy's authorization keys. The tests in this repository verify different scenarios and check the resulting intersection."),(0,i.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"You meet the ",(0,i.kt)("a",{parentName:"li",href:"/developers/prerequisites"},"development prerequisites")," and are familiar with ",(0,i.kt)("a",{parentName:"li",href:"/writing-contracts"},"writing and testing on-chain code")),(0,i.kt)("li",{parentName:"ul"},"You know how to ",(0,i.kt)("a",{parentName:"li",href:"/developers/cli/sending-deploys"},"send and verify deploys")),(0,i.kt)("li",{parentName:"ul"},"You are familiar with these concepts:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-account"},"Casper Accounts")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-deploy"},"Deploys")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#associatedkey"},"Associated Keys")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#approval"},"Approvals"),", also known as authorization keys")))),(0,i.kt)("h2",{id:"workflow"},"Workflow"),(0,i.kt)("p",null,"To start, clone the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm"},"tutorials-example-wasm")," repository. Then, open the ",(0,i.kt)("inlineCode",{parentName:"p"},"authorization-keys-example")," directory, prepare your Rust environment, and build the tests with the following commands."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-ecosystem/tutorials-example-wasm\ncd tutorials-example-wasm/authorization-keys-example\nmake prepare\nmake test\n")),(0,i.kt)("p",null,"Review the repository's structure:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/tree/dev/authorization-keys-example/client"},"client")," - A client folder containing two Wasm files",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"add_keys.wasm")," - Session code that adds an associated key to the calling account"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"contract_call.wasm")," - Session code that calls the contract's entry point and stores the result into a named key"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/tree/dev/authorization-keys-example/contract"},"contract")," - A simple contract that demonstrates the usage of authorization keys and compiles into a ",(0,i.kt)("inlineCode",{parentName:"li"},"contract.wasm")," file"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/tree/dev/authorization-keys-example/tests"},"tests")," - Tests and supporting utilities to verify and demonstrate the contract's expected behavior")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"This tutorial highlights certain lines of code found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/tree/dev/authorization-keys-example"},"GitHub"),".")),(0,i.kt)("h3",{id:"the-example-contract"},"The example contract"),(0,i.kt)("p",null,"Upon ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/contract/src/main.rs#L75"},"installation"),", the contract in this example stores the authorization keys that signed the installer deploy into a named key."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn init() {\n if runtime::get_key(AUTHORIZATION_KEYS_INSTALLER).is_none() {\n let authorization_keys: Vec =\n runtime::list_authorization_keys().iter().cloned().collect();\n\n let authorization_keys: Key = storage::new_uref(authorization_keys).into();\n runtime::put_key(AUTHORIZATION_KEYS_INSTALLER, authorization_keys);\n }\n}\n')),(0,i.kt)("p",null,"The contract contains an entry point that returns the intersection of the caller deploy's authorization keys and the installer deploy's authorization keys saved during contract installation. The following ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/contract/src/main.rs#L52"},"usage")," of ",(0,i.kt)("inlineCode",{parentName:"p"},"runtime::list_authorization_keys")," retrieves the set of account hashes representing the keys signing the caller deploy."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let authorization_keys_caller: Vec =\n runtime::list_authorization_keys().iter().cloned().collect();\n")),(0,i.kt)("h3",{id:"client-wasm-files"},"Client Wasm files"),(0,i.kt)("h4",{id:"add_keyswasm"},(0,i.kt)("inlineCode",{parentName:"h4"},"add_keys.wasm")),(0,i.kt)("p",null,"This file contains session code that adds an associated key to the calling account. For more details and a similar example, visit the ",(0,i.kt)("a",{parentName:"p",href:"/resources/tutorials/advanced/two-party-multi-sig"},"Two-Party Multi-Signature")," tutorial."),(0,i.kt)("h4",{id:"contract_callwasm"},(0,i.kt)("inlineCode",{parentName:"h4"},"contract_call.wasm")),(0,i.kt)("p",null,"This session code calls the contract's entry point, which returns the intersection between two sets of keys:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"The authorization keys that signed the deploy that installed the contract (referred to in this tutorial as the installer deploy)"),(0,i.kt)("li",{parentName:"ul"},"The authorization keys that signed the deploy calling the entry point (referred to in this tutorial as the caller deploy).")),(0,i.kt)("p",null,"The intersection result is a list stored under a named key of the account calling the ",(0,i.kt)("inlineCode",{parentName:"p"},"contract_call.wasm"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let key_name: String = runtime::get_named_arg(ARG_KEY_NAME);\nlet intersection =\n runtime::call_contract::>(contract_hash, ENTRY_POINT, runtime_args! {});\nruntime::put_key(&key_name, storage::new_uref(intersection).into());\n}\n")),(0,i.kt)("h3",{id:"testing-this-example"},"Testing this example"),(0,i.kt)("p",null,"This section highlights the tests written for this example, demonstrating the usage of authorization keys. The tests are divided into three parts:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Testing the contract installation"),(0,i.kt)("li",{parentName:"ul"},"Testing the contract's unique entry point"),(0,i.kt)("li",{parentName:"ul"},"Testing the entry point using a client contract call")),(0,i.kt)("p",null,"These tests focus on testing the contract installation."),(0,i.kt)("h4",{id:"test-1-should_allow_install_contract_with_default_account"},"Test 1: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_install_contract_with_default_account")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Expected outcome"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},"Successful contract installation")))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L28"},"test")," signs the installer deploy with an authorization key ",(0,i.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR")," that belongs to the calling accounts's associated keys. In other words, since the caller is the default account, ",(0,i.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR")," can be used to sign the deploy."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(CONTRACT_WASM);\nlet session_args = RuntimeArgs::new();\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, session_args)\n .build();\n\n")),(0,i.kt)("h4",{id:"test-2-should_disallow_install_with_non_added_authorization_key"},"Test 2: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_disallow_install_with_non_added_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Expected outcome"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1")),(0,i.kt)("td",{parentName:"tr",align:null},"Failed contract installation")))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L57"},"test")," tries to sign the installer deploy with an authorization key that is not part of the caller's associated keys. This is not allowed because the authorization keys used to sign a deploy need to be a subset of the caller's associated keys. So, the installer deploy fails as expected."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'let session_code = PathBuf::from(CONTRACT_WASM);\nlet session_args = RuntimeArgs::new();\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR, account_addr_1])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, session_args)\n .build();\n\nlet execute_request = ExecuteRequestBuilder::from_deploy_item(deploy_item).build();\nbuilder.exec(execute_request).commit().expect_failure();\nlet error = builder.get_error().expect("must have error");\nassert_eq!(error.to_string(), "Authorization failure: not authorized.");\n')),(0,i.kt)("h4",{id:"test-3-should_allow_install_with_added_authorization_key"},"Test 3: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_install_with_added_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Expected outcome"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1")),(0,i.kt)("td",{parentName:"tr",align:null},"Successful contract installation")))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L83"},"test")," demonstrates a successful installer deploy using an added authorization key. After the initial test framework setup, the test calls session code to add the associated account ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1")," to the default account's associated keys."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"// Add account_addr_1 to the default account's associated keys\nlet session_code = PathBuf::from(ADD_KEYS_WASM);\nlet session_args = runtime_args! {\n ASSOCIATED_ACCOUNT => account_addr_1\n};\n\nlet add_keys_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, session_args)\n .build();\n\nlet add_keys_execute_request =\n ExecuteRequestBuilder::from_deploy_item(add_keys_deploy_item).build();\n\nbuilder\n .exec(add_keys_execute_request)\n .commit()\n .expect_success();\n")),(0,i.kt)("p",null,"Since the deploy threshold is now 2, the installer deploy is signed with the default account hash and with ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1"),". See ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L191"},"GitHub"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(CONTRACT_WASM);\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR, account_addr_1])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, session_args)\n .build();\n\nlet execute_request = ExecuteRequestBuilder::from_deploy_item(deploy_item).build();\nbuilder.exec(execute_request).commit().expect_success();\n")),(0,i.kt)("p",null,"The next tests exercise the contract's unique entry point to calculate the intersection between the caller deploy's authorization keys and the installer deploy's authorization keys."),(0,i.kt)("h4",{id:"test-4-should_allow_entry_point_with_installer_authorization_key"},"Test 4: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_entry_point_with_installer_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"))))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L144"},"test")," builds upon the previous test, which adds an associated account to the default account's associated keys and installs the contract using these two keys. Additionally, on line 201, the test invokes the contract's entry point using a deploy that runs under ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1")," signed only with ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1"),". This is possible because the deploy action threshold for ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1")," is 1 as you can see ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L201"},"here"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'let contract_hash = builder\n .get_expected_account(*DEFAULT_ACCOUNT_ADDR)\n .named_keys()\n .get(CONTRACT_HASH)\n .expect("must have this entry in named keys")\n .into_hash()\n .map(ContractHash::new)\n .unwrap();\n\nlet entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1])\n .with_address(account_addr_1)\n .with_stored_session_hash(contract_hash, ENTRYPOINT, runtime_args! {})\n .build();\n\nlet entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\n\nbuilder.exec(entry_point_request).expect_success().commit();\n')),(0,i.kt)("p",null,"The entry point returns the intersection of the caller deploy's authorization keys and the installer deploy's authorization keys. The intersection is a list containing the key ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1"),". Thus, the caller deploy is expected to succeed and return a result."),(0,i.kt)("h4",{id:"test-5-should_allow_entry_point_with_account_authorization_key"},"Test 5: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_entry_point_with_account_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR"))))),(0,i.kt)("p",null,"This is the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L224"},"main test")," in this example repository. After installing the contract using the default account, the test adds the default account hash to ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1")," as an associated key."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(ADD_KEYS_WASM);\nlet session_args = runtime_args! {\n ASSOCIATED_ACCOUNT => *DEFAULT_ACCOUNT_ADDR\n};\n\nlet add_keys_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1])\n .with_address(account_addr_1)\n .with_session_code(session_code, session_args)\n .build();\n")),(0,i.kt)("p",null,"Then, the test creates a deploy to invoke the contract's entry point. This deploy executes under ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1")," and has two authorization keys, ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1")," and the default account hash. Note that both authorization keys must sign the deploy to meet the deploy's action threshold, which is set to 2. The deploy should be executed successfully because the resulting intersection should contain the default account hash."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1, *DEFAULT_ACCOUNT_ADDR])\n .with_address(account_addr_1)\n .with_stored_session_hash(contract_hash, ENTRYPOINT, runtime_args! {})\n .build();\n\nlet entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\n\nbuilder.exec(entry_point_request).expect_success().commit();\n")),(0,i.kt)("h4",{id:"test-6-should_disallow_entry_point_without_authorization_key"},"Test 6: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_disallow_entry_point_without_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_2")),(0,i.kt)("td",{parentName:"tr",align:null},"None")))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L304"},"test")," verifies that the entry point returns an error when there is no intersection between the caller deploy's authorization keys and the installer deploy's authorization keys."),(0,i.kt)("p",null,"The default account hash is used to sign the installer deploy."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(CONTRACT_WASM);\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, runtime_args! {})\n .build();\n")),(0,i.kt)("p",null,"In the test, a new account, ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_2"),", creates a deploy invoking the contract's entry point and signs the deploy with ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_2"),". When calling the entry point, an error is returned because the caller and the installer deploys do not have any authorization keys in common."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},' // Here ACCOUNT_USER_2 does not have DEFAULT_ACCOUNT_ADDR (from the contract installer) in its associated keys\n // The deploy will therefore revert with PermissionDenied\n let entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_2])\n .with_address(account_addr_2)\n .with_stored_session_hash(contract_hash, ENTRYPOINT, runtime_args! {})\n .build();\n\n let entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\n\n builder.exec(entry_point_request).commit().expect_failure();\n let error = builder.get_error().expect("must have User error: 0");\n assert_expected_error(\n error,\n 0,\n "should fail execution since DEFAULT_ACCOUNT_ADDR is not in ACCOUNT_USER_2 associated keys",\n );\n')),(0,i.kt)("p",null,"The following tests exercise the entry point using a ",(0,i.kt)("a",{parentName:"p",href:"#contract_callwasm"},"contract call")," and verifying the result returned."),(0,i.kt)("h4",{id:"test-7-should_allow_entry_point_through_contract_call_with_authorization_key"},"Test 7: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_entry_point_through_contract_call_with_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR"))))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L403"},"test")," validates the contract's entry point using a client contract call. The contract is installed using the default account hash in the deploy's authorization keys."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(CONTRACT_WASM);\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, runtime_args! {})\n .build();\n")),(0,i.kt)("p",null,"The caller deploy is signed by ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1, *DEFAULT_ACCOUNT_ADDR])\n .with_address(account_addr_1)\n .with_session_code(session_code, session_args)\n .build();\n\nlet entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\nbuilder.exec(entry_point_request).expect_success().commit();\n")),(0,i.kt)("p",null,"The test then verifies that the result returned was saved in the named keys for ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1"),", containing the default account hash."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'let intersection_receipt: Key = *builder\n .get_expected_account(account_addr_1)\n .named_keys()\n .get(INTERSECTION_RECEIPT)\n .expect("must have this entry in named keys");\n\nlet actual_intersection = builder\n .query(None, intersection_receipt, &[])\n .expect("must have stored_value")\n .as_cl_value()\n .map(|intersection_cl_value| {\n CLValue::into_t::>(intersection_cl_value.clone())\n })\n .unwrap()\n .unwrap();\n\nlet expected_intersection = vec![*DEFAULT_ACCOUNT_ADDR];\n\nassert_eq!(actual_intersection, expected_intersection);\n')),(0,i.kt)("h4",{id:"test-8-should_disallow_entry_point_through_contract_call_without_authorization_key"},"Test 8: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_disallow_entry_point_through_contract_call_without_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_2")),(0,i.kt)("td",{parentName:"tr",align:null},"None")))),(0,i.kt)("p",null,"The ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L509"},"final test")," in this tutorial checks that when there is no intersection between the caller deploy's authorization keys (",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_2"),") and the installer deploy's authorization keys (",(0,i.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR"),"), the entry point returns an error."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},' let session_code = PathBuf::from(CONTRACT_CALL_WASM);\n\nlet session_args = runtime_args! {\n ARG_CONTRACT_HASH => Key::from(contract_hash),\n ARG_KEY_NAME => INTERSECTION_RECEIPT\n};\n\n// account_addr_2 as an associated key is not among the default account\'s associated keys\n// The deploy will therefore revert with PermissionDenied\nlet entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1, account_addr_2])\n .with_address(account_addr_1)\n .with_session_code(session_code, session_args)\n .build();\n\nlet entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\n\nbuilder.exec(entry_point_request).commit().expect_failure();\n\nlet error = builder.get_error().expect("must have User error: 0");\nassert_expected_error(\n error,\n 0,\n "should fail execution since ACCOUNT_USER_2 as associated key is not in installer (DEFAULT_ACCOUNT_ADDR) associated keys",\n);\n')))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7dc1264b.0823d86e.js b/assets/js/7dc1264b.0823d86e.js deleted file mode 100644 index 5e461cc300..0000000000 --- a/assets/js/7dc1264b.0823d86e.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3174],{3905:function(e,t,a){a.d(t,{Zo:function(){return u},kt:function(){return h}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),d=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},u=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",_={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=d(a),p=r,h=c["".concat(l,".").concat(p)]||c[p]||_[p]||i;return a?n.createElement(h,o(o({ref:t},u),{},{components:a})):n.createElement(h,o({ref:t},u))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:r,o[1]=s;for(var d=2;dadd_keys.wasm",id:"add_keyswasm",level:4},{value:"contract_call.wasm",id:"contract_callwasm",level:4},{value:"Testing this example",id:"testing-this-example",level:3},{value:"Test 1: should_allow_install_contract_with_default_account",id:"test-1-should_allow_install_contract_with_default_account",level:4},{value:"Test 2: should_disallow_install_with_non_added_authorization_key",id:"test-2-should_disallow_install_with_non_added_authorization_key",level:4},{value:"Test 3: should_allow_install_with_added_authorization_key",id:"test-3-should_allow_install_with_added_authorization_key",level:4},{value:"Test 4: should_allow_entry_point_with_installer_authorization_key",id:"test-4-should_allow_entry_point_with_installer_authorization_key",level:4},{value:"Test 5: should_allow_entry_point_with_account_authorization_key",id:"test-5-should_allow_entry_point_with_account_authorization_key",level:4},{value:"Test 6: should_disallow_entry_point_without_authorization_key",id:"test-6-should_disallow_entry_point_without_authorization_key",level:4},{value:"Test 7: should_allow_entry_point_through_contract_call_with_authorization_key",id:"test-7-should_allow_entry_point_through_contract_call_with_authorization_key",level:4},{value:"Test 8: should_disallow_entry_point_through_contract_call_without_authorization_key",id:"test-8-should_disallow_entry_point_through_contract_call_without_authorization_key",level:4}],_={toc:c},p="wrapper";function h(e){var t=e.components,a=(0,r.Z)(e,o);return(0,i.kt)(p,(0,n.Z)({},_,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"working-with-authorization-keys"},"Working with Authorization Keys"),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"These examples should not be used in a production environment. They are intended only for teaching and must be tested and adapted for production use.")),(0,i.kt)("p",null,"This tutorial demonstrates retrieving and using the authorization keys associated with a deploy using the ",(0,i.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.list_authorization_keys.html"},"list_authorization_keys")," function."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let authorization_keys = runtime::list_authorization_keys();\n")),(0,i.kt)("p",null,"Remember that authorization keys are listed under a Deploy's ",(0,i.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#serialization-standard-deploy"},"approvals")," section, which lists the signatures and the public keys of the signers, also called authorizing keys. Here is an example of a deploy's approvals:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'"approvals": [\n {\n "signer": "02021a4da3d6f32ea3ebd2519e1a37a1b811671085bf4f1cf2a36b931344a99b756a",\n "signature": "02df8cdf0bff3bd93e831d24563d5acbefa0ed13814550e910d03208d5fb3c11770dd3d918784ec84342e53666eacf59aeecbf4ce0cdd60e167c4a4b20e4b8f481"\n }\n]\n')),(0,i.kt)("p",null,"The contract code in this example retrieves the set of authorization keys for a given deploy by calling the ",(0,i.kt)("inlineCode",{parentName:"p"},"runtime::list_authorization_keys")," function. In other words, ",(0,i.kt)("inlineCode",{parentName:"p"},"list_authorization_keys")," returns the set of account hashes representing the keys used to sign a deploy. Upon installation, the contract code stores the authorization keys for the installer deploy into a NamedKey. The contract also contains an entry point that returns the intersection of the caller deploy's, and installer deploy's authorization keys. The tests in this repository verify different scenarios and check the resulting intersection."),(0,i.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"You meet the ",(0,i.kt)("a",{parentName:"li",href:"/developers/prerequisites"},"development prerequisites")," and are familiar with ",(0,i.kt)("a",{parentName:"li",href:"/writing-contracts"},"writing and testing on-chain code")),(0,i.kt)("li",{parentName:"ul"},"You know how to ",(0,i.kt)("a",{parentName:"li",href:"/developers/cli/sending-deploys"},"send and verify deploys")),(0,i.kt)("li",{parentName:"ul"},"You are familiar with these concepts:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-account"},"Casper Accounts")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-deploy"},"Deploys")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#associatedkey"},"Associated Keys")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#approval"},"Approvals"),", also known as authorization keys")))),(0,i.kt)("h2",{id:"workflow"},"Workflow"),(0,i.kt)("p",null,"To start, clone the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm"},"tutorials-example-wasm")," repository. Then, open the ",(0,i.kt)("inlineCode",{parentName:"p"},"authorization-keys-example")," directory, prepare your Rust environment, and build the tests with the following commands."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-ecosystem/tutorials-example-wasm\ncd tutorials-example-wasm/authorization-keys-example\nmake prepare\nmake test\n")),(0,i.kt)("p",null,"Review the repository's structure:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/tree/dev/authorization-keys-example/client"},"client")," - A client folder containing two Wasm files",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"add_keys.wasm")," - Session code that adds an associated key to the calling account"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"contract_call.wasm")," - Session code that calls the contract's entry point and stores the result into a named key"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/tree/dev/authorization-keys-example/contract"},"contract")," - A simple contract that demonstrates the usage of authorization keys and compiles into a ",(0,i.kt)("inlineCode",{parentName:"li"},"contract.wasm")," file"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/tree/dev/authorization-keys-example/tests"},"tests")," - Tests and supporting utilities to verify and demonstrate the contract's expected behavior")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"This tutorial highlights certain lines of code found in ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/tree/dev/authorization-keys-example"},"GitHub"),".")),(0,i.kt)("h3",{id:"the-example-contract"},"The example contract"),(0,i.kt)("p",null,"Upon ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/contract/src/main.rs#L75"},"installation"),", the contract in this example stores the authorization keys that signed the installer deploy into a named key."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn init() {\n if runtime::get_key(AUTHORIZATION_KEYS_INSTALLER).is_none() {\n let authorization_keys: Vec =\n runtime::list_authorization_keys().iter().cloned().collect();\n\n let authorization_keys: Key = storage::new_uref(authorization_keys).into();\n runtime::put_key(AUTHORIZATION_KEYS_INSTALLER, authorization_keys);\n }\n}\n')),(0,i.kt)("p",null,"The contract contains an entry point that returns the intersection of the caller deploy's authorization keys and the installer deploy's authorization keys saved during contract installation. The following ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/contract/src/main.rs#L52"},"usage")," of ",(0,i.kt)("inlineCode",{parentName:"p"},"runtime::list_authorization_keys")," retrieves the set of account hashes representing the keys signing the caller deploy."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let authorization_keys_caller: Vec =\n runtime::list_authorization_keys().iter().cloned().collect();\n")),(0,i.kt)("h3",{id:"client-wasm-files"},"Client Wasm files"),(0,i.kt)("h4",{id:"add_keyswasm"},(0,i.kt)("inlineCode",{parentName:"h4"},"add_keys.wasm")),(0,i.kt)("p",null,"This file contains session code that adds an associated key to the calling account. For more details and a similar example, visit the ",(0,i.kt)("a",{parentName:"p",href:"/resources/tutorials/advanced/two-party-multi-sig"},"Two-Party Multi-Signature")," tutorial."),(0,i.kt)("h4",{id:"contract_callwasm"},(0,i.kt)("inlineCode",{parentName:"h4"},"contract_call.wasm")),(0,i.kt)("p",null,"This session code calls the contract's entry point, which returns the intersection between two sets of keys:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"The authorization keys that signed the deploy that installed the contract (referred to in this tutorial as the installer deploy)"),(0,i.kt)("li",{parentName:"ul"},"The authorization keys that signed the deploy calling the entry point (referred to in this tutorial as the caller deploy).")),(0,i.kt)("p",null,"The intersection result is a list stored under a named key of the account calling the ",(0,i.kt)("inlineCode",{parentName:"p"},"contract_call.wasm"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let key_name: String = runtime::get_named_arg(ARG_KEY_NAME);\nlet intersection =\n runtime::call_contract::>(contract_hash, ENTRY_POINT, runtime_args! {});\nruntime::put_key(&key_name, storage::new_uref(intersection).into());\n}\n")),(0,i.kt)("h3",{id:"testing-this-example"},"Testing this example"),(0,i.kt)("p",null,"This section highlights the tests written for this example, demonstrating the usage of authorization keys. The tests are divided into three parts:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Testing the contract installation"),(0,i.kt)("li",{parentName:"ul"},"Testing the contract's unique entry point"),(0,i.kt)("li",{parentName:"ul"},"Testing the entry point using a client contract call")),(0,i.kt)("p",null,"These tests focus on testing the contract installation."),(0,i.kt)("h4",{id:"test-1-should_allow_install_contract_with_default_account"},"Test 1: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_install_contract_with_default_account")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Expected outcome"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},"Successful contract installation")))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L28"},"test")," signs the installer deploy with an authorization key ",(0,i.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR")," that belongs to the calling accounts's associated keys. In other words, since the caller is the default account, ",(0,i.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR")," can be used to sign the deploy."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(CONTRACT_WASM);\nlet session_args = RuntimeArgs::new();\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, session_args)\n .build();\n\n")),(0,i.kt)("h4",{id:"test-2-should_disallow_install_with_non_added_authorization_key"},"Test 2: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_disallow_install_with_non_added_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Expected outcome"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1")),(0,i.kt)("td",{parentName:"tr",align:null},"Failed contract installation")))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L57"},"test")," tries to sign the installer deploy with an authorization key that is not part of the caller's associated keys. This is not allowed because the authorization keys used to sign a deploy need to be a subset of the caller's associated keys. So, the installer deploy fails as expected."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'let session_code = PathBuf::from(CONTRACT_WASM);\nlet session_args = RuntimeArgs::new();\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR, account_addr_1])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, session_args)\n .build();\n\nlet execute_request = ExecuteRequestBuilder::from_deploy_item(deploy_item).build();\nbuilder.exec(execute_request).commit().expect_failure();\nlet error = builder.get_error().expect("must have error");\nassert_eq!(error.to_string(), "Authorization failure: not authorized.");\n')),(0,i.kt)("h4",{id:"test-3-should_allow_install_with_added_authorization_key"},"Test 3: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_install_with_added_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Expected outcome"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1")),(0,i.kt)("td",{parentName:"tr",align:null},"Successful contract installation")))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L83"},"test")," demonstrates a successful installer deploy using an added authorization key. After the initial test framework setup, the test calls session code to add the associated account ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1")," to the default account's associated keys."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"// Add account_addr_1 to the default account's associated keys\nlet session_code = PathBuf::from(ADD_KEYS_WASM);\nlet session_args = runtime_args! {\n ASSOCIATED_ACCOUNT => account_addr_1\n};\n\nlet add_keys_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, session_args)\n .build();\n\nlet add_keys_execute_request =\n ExecuteRequestBuilder::from_deploy_item(add_keys_deploy_item).build();\n\nbuilder\n .exec(add_keys_execute_request)\n .commit()\n .expect_success();\n")),(0,i.kt)("p",null,"Since the deploy threshold is now 2, the installer deploy is signed with the default account hash and with ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1"),". See ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L191"},"GitHub"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(CONTRACT_WASM);\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR, account_addr_1])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, session_args)\n .build();\n\nlet execute_request = ExecuteRequestBuilder::from_deploy_item(deploy_item).build();\nbuilder.exec(execute_request).commit().expect_success();\n")),(0,i.kt)("p",null,"The next tests exercise the contract's unique entry point to calculate the intersection between the caller deploy's authorization keys and the installer deploy's authorization keys."),(0,i.kt)("h4",{id:"test-4-should_allow_entry_point_with_installer_authorization_key"},"Test 4: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_entry_point_with_installer_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"))))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L144"},"test")," builds upon the previous test, which adds an associated account to the default account's associated keys and installs the contract using these two keys. Additionally, on line 201, the test invokes the contract's entry point using a deploy that runs under ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1")," signed only with ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1"),". This is possible because the deploy action threshold for ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1")," is 1 as you can see ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L201"},"here"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'let contract_hash = builder\n .get_expected_account(*DEFAULT_ACCOUNT_ADDR)\n .named_keys()\n .get(CONTRACT_HASH)\n .expect("must have this entry in named keys")\n .into_hash()\n .map(ContractHash::new)\n .unwrap();\n\nlet entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1])\n .with_address(account_addr_1)\n .with_stored_session_hash(contract_hash, ENTRYPOINT, runtime_args! {})\n .build();\n\nlet entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\n\nbuilder.exec(entry_point_request).expect_success().commit();\n')),(0,i.kt)("p",null,"The entry point returns the intersection of the caller deploy's authorization keys and the installer deploy's authorization keys. The intersection is a list containing the key ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1"),". Thus, the caller deploy is expected to succeed and return a result."),(0,i.kt)("h4",{id:"test-5-should_allow_entry_point_with_account_authorization_key"},"Test 5: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_entry_point_with_account_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR"))))),(0,i.kt)("p",null,"This is the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L224"},"main test")," in this example repository. After installing the contract using the default account, the test adds the default account hash to ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1")," as an associated key."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(ADD_KEYS_WASM);\nlet session_args = runtime_args! {\n ASSOCIATED_ACCOUNT => *DEFAULT_ACCOUNT_ADDR\n};\n\nlet add_keys_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1])\n .with_address(account_addr_1)\n .with_session_code(session_code, session_args)\n .build();\n")),(0,i.kt)("p",null,"Then, the test creates a deploy to invoke the contract's entry point. This deploy executes under ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1")," and has two authorization keys, ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1")," and the default account hash. Note that both authorization keys must sign the deploy to meet the deploy's action threshold, which is set to 2. The deploy should be executed successfully because the resulting intersection should contain the default account hash."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1, *DEFAULT_ACCOUNT_ADDR])\n .with_address(account_addr_1)\n .with_stored_session_hash(contract_hash, ENTRYPOINT, runtime_args! {})\n .build();\n\nlet entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\n\nbuilder.exec(entry_point_request).expect_success().commit();\n")),(0,i.kt)("h4",{id:"test-6-should_disallow_entry_point_without_authorization_key"},"Test 6: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_disallow_entry_point_without_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_2")),(0,i.kt)("td",{parentName:"tr",align:null},"None")))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L304"},"test")," verifies that the entry point returns an error when there is no intersection between the caller deploy's authorization keys and the installer deploy's authorization keys."),(0,i.kt)("p",null,"The default account hash is used to sign the installer deploy."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(CONTRACT_WASM);\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, runtime_args! {})\n .build();\n")),(0,i.kt)("p",null,"In the test, a new account, ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_2"),", creates a deploy invoking the contract's entry point and signs the deploy with ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_2"),". When calling the entry point, an error is returned because the caller and the installer deploys do not have any authorization keys in common."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},' // Here ACCOUNT_USER_2 does not have DEFAULT_ACCOUNT_ADDR (from the contract installer) in its associated keys\n // The deploy will therefore revert with PermissionDenied\n let entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_2])\n .with_address(account_addr_2)\n .with_stored_session_hash(contract_hash, ENTRYPOINT, runtime_args! {})\n .build();\n\n let entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\n\n builder.exec(entry_point_request).commit().expect_failure();\n let error = builder.get_error().expect("must have User error: 0");\n assert_expected_error(\n error,\n 0,\n "should fail execution since DEFAULT_ACCOUNT_ADDR is not in ACCOUNT_USER_2 associated keys",\n );\n')),(0,i.kt)("p",null,"The following tests exercise the entry point using a ",(0,i.kt)("a",{parentName:"p",href:"#contract_callwasm"},"contract call")," and verifying the result returned."),(0,i.kt)("h4",{id:"test-7-should_allow_entry_point_through_contract_call_with_authorization_key"},"Test 7: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_allow_entry_point_through_contract_call_with_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR"))))),(0,i.kt)("p",null,"This ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L403"},"test")," validates the contract's entry point using a client contract call. The contract is installed using the default account hash in the deploy's authorization keys."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let session_code = PathBuf::from(CONTRACT_WASM);\n\nlet deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])\n .with_address(*DEFAULT_ACCOUNT_ADDR)\n .with_session_code(session_code, runtime_args! {})\n .build();\n")),(0,i.kt)("p",null,"The caller deploy is signed by ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},"let entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1, *DEFAULT_ACCOUNT_ADDR])\n .with_address(account_addr_1)\n .with_session_code(session_code, session_args)\n .build();\n\nlet entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\nbuilder.exec(entry_point_request).expect_success().commit();\n")),(0,i.kt)("p",null,"The test then verifies that the result returned was saved in the named keys for ",(0,i.kt)("inlineCode",{parentName:"p"},"ACCOUNT_USER_1"),", containing the default account hash."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},'let intersection_receipt: Key = *builder\n .get_expected_account(account_addr_1)\n .named_keys()\n .get(INTERSECTION_RECEIPT)\n .expect("must have this entry in named keys");\n\nlet actual_intersection = builder\n .query(None, intersection_receipt, &[])\n .expect("must have stored_value")\n .as_cl_value()\n .map(|intersection_cl_value| {\n CLValue::into_t::>(intersection_cl_value.clone())\n })\n .unwrap()\n .unwrap();\n\nlet expected_intersection = vec![*DEFAULT_ACCOUNT_ADDR];\n\nassert_eq!(actual_intersection, expected_intersection);\n')),(0,i.kt)("h4",{id:"test-8-should_disallow_entry_point_through_contract_call_without_authorization_key"},"Test 8: ",(0,i.kt)("inlineCode",{parentName:"h4"},"should_disallow_entry_point_through_contract_call_without_authorization_key")),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Installer deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Caller deploy authorization keys"),(0,i.kt)("th",{parentName:"tr",align:null},"Intersection returned by the entry point"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"DEFAULT_ACCOUNT_ADDR")),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"td"},"account_addr_2")),(0,i.kt)("td",{parentName:"tr",align:null},"None")))),(0,i.kt)("p",null,"The ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/tutorials-example-wasm/blob/6810ac3d6d65e252770561ddac9b33bf40aadc03/authorization-keys-example/tests/src/integration_tests.rs#L509"},"final test")," in this tutorial checks that when there is no intersection between the caller deploy's authorization keys (",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_1"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"account_addr_2"),") and the installer deploy's authorization keys (",(0,i.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR"),"), the entry point returns an error."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-rust"},' let session_code = PathBuf::from(CONTRACT_CALL_WASM);\n\nlet session_args = runtime_args! {\n ARG_CONTRACT_HASH => Key::from(contract_hash),\n ARG_KEY_NAME => INTERSECTION_RECEIPT\n};\n\n// account_addr_2 as an associated key is not among the default account\'s associated keys\n// The deploy will therefore revert with PermissionDenied\nlet entry_point_deploy_item = DeployItemBuilder::new()\n .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})\n .with_authorization_keys(&[account_addr_1, account_addr_2])\n .with_address(account_addr_1)\n .with_session_code(session_code, session_args)\n .build();\n\nlet entry_point_request =\n ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();\n\nbuilder.exec(entry_point_request).commit().expect_failure();\n\nlet error = builder.get_error().expect("must have User error: 0");\nassert_expected_error(\n error,\n 0,\n "should fail execution since ACCOUNT_USER_2 as associated key is not in installer (DEFAULT_ACCOUNT_ADDR) associated keys",\n);\n')))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/80eab72b.0a8d9c72.js b/assets/js/80eab72b.0a8d9c72.js deleted file mode 100644 index 66500985cf..0000000000 --- a/assets/js/80eab72b.0a8d9c72.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7562],{3905:function(e,n,a){a.d(n,{Zo:function(){return i},kt:function(){return u}});var t=a(7294);function r(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function c(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function f(e){for(var n=1;n=0||(r[a]=e[a]);return r}(e,n);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var d=t.createContext({}),o=function(e){var n=t.useContext(d),a=n;return e&&(a="function"==typeof e?e(n):f(f({},n),e)),a},i=function(e){var n=o(e.components);return t.createElement(d.Provider,{value:n},e.children)},l="mdxType",b={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},p=t.forwardRef((function(e,n){var a=e.components,r=e.mdxType,c=e.originalType,d=e.parentName,i=s(e,["components","mdxType","originalType","parentName"]),l=o(a),p=r,u=l["".concat(d,".").concat(p)]||l[p]||b[p]||c;return a?t.createElement(u,f(f({ref:n},i),{},{components:a})):t.createElement(u,f({ref:n},i))}));function u(e,n){var a=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var c=a.length,f=new Array(c);f[0]=p;var s={};for(var d in n)hasOwnProperty.call(n,d)&&(s[d]=n[d]);s.originalType=e,s[l]="string"==typeof e?e:r,f[1]=s;for(var o=2;o \\\n--transfer-id \\\n--node-address [NODE_SERVER_ADDRESS] \\\n--amount [AMOUNT_TO_TRANSFER] \\\n--secret-key [KEY_PATH]/secret_key.pem \\\n--chain-name [CHAIN_NAME] \\\n--target-account [TARGET_PUBLIC_KEY_HEX] \\\n--payment-amount [PAYMENT_AMOUNT_IN_MOTES]\n")),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Request fields:")),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"id")," - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"transfer-id")," -<64-BIT INTEGER> The ",(0,c.kt)("inlineCode",{parentName:"p"},"transfer-id")," is a memo field, providing additional information about the recipient, which is necessary when transferring tokens to some recipients. For example, if depositing tokens into an account's purse where off-chain management keeps track of individual sub-balances, it is necessary to provide a memo ID uniquely identifying the actual recipient. If this is not necessary for a given recipient, you may pass ",(0,c.kt)("inlineCode",{parentName:"p"},"0")," or some ",(0,c.kt)("inlineCode",{parentName:"p"},"u64")," value that is meaningful to you")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"node-address")," - Hostname or IP and port of a node on a network bound to a JSON-RPC endpoint ","[","default:",(0,c.kt)("a",{parentName:"p",href:"http://localhost:7777"},"http://localhost:7777"),"]")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"amount")," -<512-BIT INTEGER> The number of motes to transfer (1 CSPR = 1,000,000,000 ",(0,c.kt)("inlineCode",{parentName:"p"},"Motes"),")")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"secret-key")," - Path to secret key file")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"chain-name")," - Name of the chain, to avoid the deploy from being accidentally or maliciously included in a different chain"),(0,c.kt)("ul",{parentName:"li"},(0,c.kt)("li",{parentName:"ul"},"The ",(0,c.kt)("em",{parentName:"li"},"chain-name")," for Testnet is ",(0,c.kt)("strong",{parentName:"li"},"casper-test")),(0,c.kt)("li",{parentName:"ul"},"The ",(0,c.kt)("em",{parentName:"li"},"chain-name")," for Mainnet is ",(0,c.kt)("strong",{parentName:"li"},"casper")))),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"target-account")," - Hex-encoded public key of the account that will receive the funds in its main purse")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"payment-amount")," - The payment for the transfer in motes. The payment amount varies based on each deploy and network ",(0,c.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". For Testnet node version ",(0,c.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1"),", you can specify 10^8 motes"))),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Important response fields:")),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("inlineCode",{parentName:"li"},'"result"."deploy_hash"')," - The address of the deploy, needed to look up additional information about the transfer")),(0,c.kt)("admonition",{type:"note"},(0,c.kt)("p",{parentName:"admonition"},"Save the returned ",(0,c.kt)("em",{parentName:"p"},"deploy_hash")," from the output to query information about the transfer deploy later.")),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Example Transfer:")),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client transfer -v \\\n--id 3 \\\n--transfer-id 11102023 \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--amount 5000000000 \\\n--secret-key ~/KEYS/secret_key.pem \\\n--chain-name casper-test \\\n--target-account 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986 \\\n--payment-amount 100000000\n")),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "account_put_deploy",\n "params": {\n "deploy": {\n "hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "header": {\n "account": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",\n "timestamp": "2023-10-12T14:59:40.760Z",\n "ttl": "30m",\n "gas_price": 1,\n "body_hash": "ea7e6a6cbdd4d761827cb627e162896bee3e771beda000550615c9b4fafa3a2d",\n "dependencies": [],\n "chain_name": "casper-test"\n },\n "payment": {\n "ModuleBytes": {\n "module_bytes": "",\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400e1f505",\n "parsed": "100000000"\n }\n ]\n ]\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0500f2052a01",\n "parsed": "5000000000"\n }\n ],\n [\n "target",\n {\n "cl_type": "PublicKey",\n "bytes": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",\n "parsed": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986"\n }\n ],\n [\n "id",\n {\n "cl_type": {\n "Option": "U64"\n },\n "bytes": "014767a90000000000",\n "parsed": 11102023\n }\n ]\n ]\n }\n },\n "approvals": [\n {\n "signer": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",\n "signature": "01e53cb742ed13ff4f0584a3da0f22f5942a33e010965adf640c91204ae4bc7436f1e5534d338ffa117d193295214816445439781229d24a372085c316eac5e305"\n }\n ]\n }\n },\n "id": 3\n}\n')),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "id": 3,\n "result": {\n "api_version": "1.5.3",\n "deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c"\n }\n}\n'))),(0,c.kt)("h2",{id:"verify-deploy"},"Verifying the Deploy"),(0,c.kt)("p",null,"A transfer on a Casper network is only executed after it has been included in a finalized block."),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy\n--node-address [NODE_SERVER_ADDRESS] [DEPLOY_HASH]\n")),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Important response fields:")),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("inlineCode",{parentName:"li"},'"result"."execution_results"[0]."transfers[0]"')," - the address of the executed transfer that the source account initiated. We will use it to look up additional information about the transfer"),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("inlineCode",{parentName:"li"},'"result"."execution_results"[0]."block_hash"')," - contains the block hash of the block that included the transfer. We will require the ",(0,c.kt)("em",{parentName:"li"},"state_root_hash")," of this block to look up information about the accounts and their purse balances")),(0,c.kt)("admonition",{type:"note"},(0,c.kt)("p",{parentName:"admonition"},"Transfer addresses use a ",(0,c.kt)("inlineCode",{parentName:"p"},"transfer-")," string prefix.")),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Example Query:")),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy\n--node-address https://rpc.testnet.casperlabs.io\n1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c\n")),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "info_get_deploy",\n "params": {\n "deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "finalized_approvals": false\n },\n "id": -3447643973713335073\n}\n')),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.5.3",\n "deploy": {\n "hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "header": {\n "account": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",\n "timestamp": "2023-10-12T14:59:40.760Z",\n "ttl": "30m",\n "gas_price": 1,\n "body_hash": "ea7e6a6cbdd4d761827cb627e162896bee3e771beda000550615c9b4fafa3a2d",\n "dependencies": [],\n "chain_name": "casper-test"\n },\n "payment": {\n "ModuleBytes": {\n "module_bytes": "",\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400e1f505",\n "parsed": "100000000"\n }\n ]\n ]\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0500f2052a01",\n "parsed": "5000000000"\n }\n ],\n [\n "target",\n {\n "cl_type": "PublicKey",\n "bytes": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",\n "parsed": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986"\n }\n ],\n [\n "id",\n {\n "cl_type": {\n "Option": "U64"\n },\n "bytes": "014767a90000000000",\n "parsed": 11102023\n }\n ]\n ]\n }\n },\n "approvals": [\n {\n "signer": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",\n "signature": "01e53cb742ed13ff4f0584a3da0f22f5942a33e010965adf640c91204ae4bc7436f1e5534d338ffa117d193295214816445439781229d24a372085c316eac5e305"\n }\n ]\n },\n "execution_results": [\n {\n "block_hash": "aac51dad028ba8b3d6fec86a39252bbc4285d513fd57a8af4696ab5390ac5c2b",\n "result": {\n "Success": {\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "transform": "Identity"\n },\n {\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "06621c3e660301",\n "parsed": "1114111876194"\n }\n }\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "AddUInt512": "100000000"\n }\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "transform": "Identity"\n },\n {\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "06621c3e660301",\n "parsed": "1114111876194"\n }\n }\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "AddUInt512": "100000000"\n }\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": "Identity"\n },\n {\n "key": "balance-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "06622a383c0201",\n "parsed": "1109111876194"\n }\n }\n },\n {\n "key": "balance-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c",\n "transform": {\n "AddUInt512": "5000000000"\n }\n },\n {\n "key": "transfer-0de7250864e67aa76626a844dcc931e615284a13a110df3f97cec9e3e97af405",\n "transform": {\n "WriteTransfer": {\n "deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "from": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",\n "to": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "source": "uref-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1-007",\n "target": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-004",\n "amount": "5000000000",\n "gas": "0",\n "id": 11102023\n }\n }\n },\n {\n "key": "deploy-1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "transfers": ["transfer-0de7250864e67aa76626a844dcc931e615284a13a110df3f97cec9e3e97af405"],\n "from": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",\n "source": "uref-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1-007",\n "gas": "100000000"\n }\n }\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-da632bfba17f4a7882581de2a37219be71628600ccd0df83f1d42465bd018537",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "00",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-da632bfba17f4a7882581de2a37219be71628600ccd0df83f1d42465bd018537",\n "transform": {\n "AddUInt512": "100000000"\n }\n }\n ]\n },\n "transfers": ["transfer-0de7250864e67aa76626a844dcc931e615284a13a110df3f97cec9e3e97af405"],\n "cost": "100000000"\n }\n }\n }\n ]\n },\n "id": -3447643973713335073\n}\n'))),(0,c.kt)("p",null,"Refer to the Section on ",(0,c.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#querying-deploys"},"querying deploys")," for more information."),(0,c.kt)("h2",{id:"verifying-the-transfer"},"Verifying the Transfer"),(0,c.kt)("p",null,"In addition to verifying the deploy, you also need to ",(0,c.kt)("a",{parentName:"p",href:"/developers/cli/transfers/verify-transfer"},"verify the transfer details"),". The deploy may have been successful, but you also need to ensure the source and target accounts were updated correctly."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/80eab72b.d3aee779.js b/assets/js/80eab72b.d3aee779.js new file mode 100644 index 0000000000..e0ea608282 --- /dev/null +++ b/assets/js/80eab72b.d3aee779.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7562],{3905:function(e,n,a){a.d(n,{Zo:function(){return i},kt:function(){return u}});var t=a(7294);function r(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function c(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function f(e){for(var n=1;n=0||(r[a]=e[a]);return r}(e,n);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var d=t.createContext({}),o=function(e){var n=t.useContext(d),a=n;return e&&(a="function"==typeof e?e(n):f(f({},n),e)),a},i=function(e){var n=o(e.components);return t.createElement(d.Provider,{value:n},e.children)},l="mdxType",b={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},p=t.forwardRef((function(e,n){var a=e.components,r=e.mdxType,c=e.originalType,d=e.parentName,i=s(e,["components","mdxType","originalType","parentName"]),l=o(a),p=r,u=l["".concat(d,".").concat(p)]||l[p]||b[p]||c;return a?t.createElement(u,f(f({ref:n},i),{},{components:a})):t.createElement(u,f({ref:n},i))}));function u(e,n){var a=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var c=a.length,f=new Array(c);f[0]=p;var s={};for(var d in n)hasOwnProperty.call(n,d)&&(s[d]=n[d]);s.originalType=e,s[l]="string"==typeof e?e:r,f[1]=s;for(var o=2;o \\\n--transfer-id \\\n--node-address [NODE_SERVER_ADDRESS] \\\n--amount [AMOUNT_TO_TRANSFER] \\\n--secret-key [KEY_PATH]/secret_key.pem \\\n--chain-name [CHAIN_NAME] \\\n--target-account [TARGET_PUBLIC_KEY_HEX] \\\n--payment-amount [PAYMENT_AMOUNT_IN_MOTES]\n")),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Request fields:")),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"id")," - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"transfer-id")," -<64-BIT INTEGER> The ",(0,c.kt)("inlineCode",{parentName:"p"},"transfer-id")," is a memo field, providing additional information about the recipient, which is necessary when transferring tokens to some recipients. For example, if depositing tokens into an account's purse where off-chain management keeps track of individual sub-balances, it is necessary to provide a memo ID uniquely identifying the actual recipient. If this is not necessary for a given recipient, you may pass ",(0,c.kt)("inlineCode",{parentName:"p"},"0")," or some ",(0,c.kt)("inlineCode",{parentName:"p"},"u64")," value that is meaningful to you")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"node-address")," - Hostname or IP and port of a node on a network bound to a JSON-RPC endpoint ","[","default:",(0,c.kt)("a",{parentName:"p",href:"http://localhost:7777"},"http://localhost:7777"),"]")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"amount")," -<512-BIT INTEGER> The number of motes to transfer (1 CSPR = 1,000,000,000 ",(0,c.kt)("inlineCode",{parentName:"p"},"Motes"),")")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"secret-key")," - Path to secret key file")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"chain-name")," - Name of the chain, to avoid the deploy from being accidentally or maliciously included in a different chain"),(0,c.kt)("ul",{parentName:"li"},(0,c.kt)("li",{parentName:"ul"},"The ",(0,c.kt)("em",{parentName:"li"},"chain-name")," for Testnet is ",(0,c.kt)("strong",{parentName:"li"},"casper-test")),(0,c.kt)("li",{parentName:"ul"},"The ",(0,c.kt)("em",{parentName:"li"},"chain-name")," for Mainnet is ",(0,c.kt)("strong",{parentName:"li"},"casper")))),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"target-account")," - Hex-encoded public key of the account that will receive the funds in its main purse")),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("p",{parentName:"li"},(0,c.kt)("inlineCode",{parentName:"p"},"payment-amount")," - The payment for the transfer in motes. The payment amount varies based on each deploy and network ",(0,c.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". For Testnet node version ",(0,c.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1"),", you can specify 10^8 motes"))),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Important response fields:")),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("inlineCode",{parentName:"li"},'"result"."deploy_hash"')," - The address of the deploy, needed to look up additional information about the transfer")),(0,c.kt)("admonition",{type:"note"},(0,c.kt)("p",{parentName:"admonition"},"Save the returned ",(0,c.kt)("em",{parentName:"p"},"deploy_hash")," from the output to query information about the transfer deploy later.")),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Example Transfer:")),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client transfer -v \\\n--id 3 \\\n--transfer-id 11102023 \\\n--node-address https://rpc.testnet.casperlabs.io/ \\\n--amount 5000000000 \\\n--secret-key ~/KEYS/secret_key.pem \\\n--chain-name casper-test \\\n--target-account 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986 \\\n--payment-amount 100000000\n")),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "account_put_deploy",\n "params": {\n "deploy": {\n "hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "header": {\n "account": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",\n "timestamp": "2023-10-12T14:59:40.760Z",\n "ttl": "30m",\n "gas_price": 1,\n "body_hash": "ea7e6a6cbdd4d761827cb627e162896bee3e771beda000550615c9b4fafa3a2d",\n "dependencies": [],\n "chain_name": "casper-test"\n },\n "payment": {\n "ModuleBytes": {\n "module_bytes": "",\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400e1f505",\n "parsed": "100000000"\n }\n ]\n ]\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0500f2052a01",\n "parsed": "5000000000"\n }\n ],\n [\n "target",\n {\n "cl_type": "PublicKey",\n "bytes": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",\n "parsed": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986"\n }\n ],\n [\n "id",\n {\n "cl_type": {\n "Option": "U64"\n },\n "bytes": "014767a90000000000",\n "parsed": 11102023\n }\n ]\n ]\n }\n },\n "approvals": [\n {\n "signer": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",\n "signature": "01e53cb742ed13ff4f0584a3da0f22f5942a33e010965adf640c91204ae4bc7436f1e5534d338ffa117d193295214816445439781229d24a372085c316eac5e305"\n }\n ]\n }\n },\n "id": 3\n}\n')),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "id": 3,\n "result": {\n "api_version": "1.5.3",\n "deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c"\n }\n}\n'))),(0,c.kt)("h2",{id:"verify-deploy"},"Verifying the Deploy"),(0,c.kt)("p",null,"A transfer on a Casper network is only executed after it has been included in a finalized block."),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy\n--node-address [NODE_SERVER_ADDRESS] [DEPLOY_HASH]\n")),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Important response fields:")),(0,c.kt)("ul",null,(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("inlineCode",{parentName:"li"},'"result"."execution_results"[0]."transfers[0]"')," - the address of the executed transfer that the source account initiated. We will use it to look up additional information about the transfer"),(0,c.kt)("li",{parentName:"ul"},(0,c.kt)("inlineCode",{parentName:"li"},'"result"."execution_results"[0]."block_hash"')," - contains the block hash of the block that included the transfer. We will require the ",(0,c.kt)("em",{parentName:"li"},"state_root_hash")," of this block to look up information about the accounts and their purse balances")),(0,c.kt)("admonition",{type:"note"},(0,c.kt)("p",{parentName:"admonition"},"Transfer addresses use a ",(0,c.kt)("inlineCode",{parentName:"p"},"transfer-")," string prefix.")),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"Example Query:")),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy\n--node-address https://rpc.testnet.casperlabs.io\n1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c\n")),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "info_get_deploy",\n "params": {\n "deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "finalized_approvals": false\n },\n "id": -3447643973713335073\n}\n')),(0,c.kt)("p",null,(0,c.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.5.3",\n "deploy": {\n "hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "header": {\n "account": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",\n "timestamp": "2023-10-12T14:59:40.760Z",\n "ttl": "30m",\n "gas_price": 1,\n "body_hash": "ea7e6a6cbdd4d761827cb627e162896bee3e771beda000550615c9b4fafa3a2d",\n "dependencies": [],\n "chain_name": "casper-test"\n },\n "payment": {\n "ModuleBytes": {\n "module_bytes": "",\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400e1f505",\n "parsed": "100000000"\n }\n ]\n ]\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0500f2052a01",\n "parsed": "5000000000"\n }\n ],\n [\n "target",\n {\n "cl_type": "PublicKey",\n "bytes": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",\n "parsed": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986"\n }\n ],\n [\n "id",\n {\n "cl_type": {\n "Option": "U64"\n },\n "bytes": "014767a90000000000",\n "parsed": 11102023\n }\n ]\n ]\n }\n },\n "approvals": [\n {\n "signer": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",\n "signature": "01e53cb742ed13ff4f0584a3da0f22f5942a33e010965adf640c91204ae4bc7436f1e5534d338ffa117d193295214816445439781229d24a372085c316eac5e305"\n }\n ]\n },\n "execution_results": [\n {\n "block_hash": "aac51dad028ba8b3d6fec86a39252bbc4285d513fd57a8af4696ab5390ac5c2b",\n "result": {\n "Success": {\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "transform": "Identity"\n },\n {\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "06621c3e660301",\n "parsed": "1114111876194"\n }\n }\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "AddUInt512": "100000000"\n }\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "transform": "Identity"\n },\n {\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "06621c3e660301",\n "parsed": "1114111876194"\n }\n }\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "AddUInt512": "100000000"\n }\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": "Identity"\n },\n {\n "key": "balance-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c",\n "transform": "Identity"\n },\n {\n "key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "06622a383c0201",\n "parsed": "1109111876194"\n }\n }\n },\n {\n "key": "balance-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c",\n "transform": {\n "AddUInt512": "5000000000"\n }\n },\n {\n "key": "transfer-0de7250864e67aa76626a844dcc931e615284a13a110df3f97cec9e3e97af405",\n "transform": {\n "WriteTransfer": {\n "deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "from": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",\n "to": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "source": "uref-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1-007",\n "target": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-004",\n "amount": "5000000000",\n "gas": "0",\n "id": 11102023\n }\n }\n },\n {\n "key": "deploy-1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",\n "transfers": ["transfer-0de7250864e67aa76626a844dcc931e615284a13a110df3f97cec9e3e97af405"],\n "from": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",\n "source": "uref-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1-007",\n "gas": "100000000"\n }\n }\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-da632bfba17f4a7882581de2a37219be71628600ccd0df83f1d42465bd018537",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "00",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-da632bfba17f4a7882581de2a37219be71628600ccd0df83f1d42465bd018537",\n "transform": {\n "AddUInt512": "100000000"\n }\n }\n ]\n },\n "transfers": ["transfer-0de7250864e67aa76626a844dcc931e615284a13a110df3f97cec9e3e97af405"],\n "cost": "100000000"\n }\n }\n }\n ]\n },\n "id": -3447643973713335073\n}\n'))),(0,c.kt)("p",null,"Refer to the Section on ",(0,c.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#querying-deploys"},"querying deploys")," for more information."),(0,c.kt)("h2",{id:"verifying-the-transfer"},"Verifying the Transfer"),(0,c.kt)("p",null,"In addition to verifying the deploy, you also need to ",(0,c.kt)("a",{parentName:"p",href:"/developers/cli/transfers/verify-transfer"},"verify the transfer details"),". The deploy may have been successful, but you also need to ensure the source and target accounts were updated correctly."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/81637ed9.698309df.js b/assets/js/81637ed9.637b21ae.js similarity index 59% rename from assets/js/81637ed9.698309df.js rename to assets/js/81637ed9.637b21ae.js index 268b162932..291f9dfcfb 100644 --- a/assets/js/81637ed9.698309df.js +++ b/assets/js/81637ed9.637b21ae.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7576],{3905:function(e,r,t){t.d(r,{Zo:function(){return p},kt:function(){return g}});var n=t(7294);function a(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function s(e,r){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(e,r).enumerable}))),t.push.apply(t,n)}return t}function i(e){for(var r=1;r=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var c=n.createContext({}),l=function(e){var r=n.useContext(c),t=r;return e&&(t="function"==typeof e?e(r):i(i({},r),e)),t},p=function(e){var r=l(e.components);return n.createElement(c.Provider,{value:r},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},d=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,s=e.originalType,c=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=l(t),d=a,g=u["".concat(c,".").concat(d)]||u[d]||f[d]||s;return t?n.createElement(g,i(i({ref:r},p),{},{components:t})):n.createElement(g,i({ref:r},p))}));function g(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var s=t.length,i=new Array(s);i[0]=d;var o={};for(var c in r)hasOwnProperty.call(r,c)&&(o[c]=r[c]);o.originalType=e,o[u]="string"==typeof e?e:a,i[1]=o;for(var l=2;l=0||(a[t]=e[t]);return a}(e,r);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var c=n.createContext({}),l=function(e){var r=n.useContext(c),t=r;return e&&(t="function"==typeof e?e(r):i(i({},r),e)),t},p=function(e){var r=l(e.components);return n.createElement(c.Provider,{value:r},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},d=n.forwardRef((function(e,r){var t=e.components,a=e.mdxType,s=e.originalType,c=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=l(t),d=a,g=u["".concat(c,".").concat(d)]||u[d]||f[d]||s;return t?n.createElement(g,i(i({ref:r},p),{},{components:t})):n.createElement(g,i({ref:r},p))}));function g(e,r){var t=arguments,a=r&&r.mdxType;if("string"==typeof e||a){var s=t.length,i=new Array(s);i[0]=d;var o={};for(var c in r)hasOwnProperty.call(r,c)&&(o[c]=r[c]);o.originalType=e,o[u]="string"==typeof e?e:a,i[1]=o;for(var l=2;l=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var c=a.createContext({}),u=function(e){var t=a.useContext(c),o=t;return e&&(o="function"==typeof e?e(t):s(s({},t),e)),o},l=function(e){var t=u(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var o=e.components,n=e.mdxType,r=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),p=u(o),h=n,m=p["".concat(c,".").concat(h)]||p[h]||d[h]||r;return o?a.createElement(m,s(s({ref:t},l),{},{components:o})):a.createElement(m,s({ref:t},l))}));function m(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=o.length,s=new Array(r);s[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[p]="string"==typeof e?e:n,s[1]=i;for(var u=2;u=0||(n[o]=e[o]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,o)&&(n[o]=e[o])}return n}var c=a.createContext({}),u=function(e){var t=a.useContext(c),o=t;return e&&(o="function"==typeof e?e(t):s(s({},t),e)),o},l=function(e){var t=u(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var o=e.components,n=e.mdxType,r=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),p=u(o),h=n,m=p["".concat(c,".").concat(h)]||p[h]||d[h]||r;return o?a.createElement(m,s(s({ref:t},l),{},{components:o})):a.createElement(m,s({ref:t},l))}));function m(e,t){var o=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=o.length,s=new Array(r);s[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[p]="string"==typeof e?e:n,s[1]=i;for(var u=2;u=0||(c[n]=t[n]);return c}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(c[n]=t[n])}return c}var s=a.createContext({}),l=function(t){var e=a.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},p=function(t){var e=l(t.components);return a.createElement(s.Provider,{value:e},t.children)},h="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},d=a.forwardRef((function(t,e){var n=t.components,c=t.mdxType,r=t.originalType,s=t.parentName,p=i(t,["components","mdxType","originalType","parentName"]),h=l(n),d=c,m=h["".concat(s,".").concat(d)]||h[d]||u[d]||r;return n?a.createElement(m,o(o({ref:e},p),{},{components:n})):a.createElement(m,o({ref:e},p))}));function m(t,e){var n=arguments,c=e&&e.mdxType;if("string"==typeof t||c){var r=n.length,o=new Array(r);o[0]=d;var i={};for(var s in e)hasOwnProperty.call(e,s)&&(i[s]=e[s]);i.originalType=t,i[h]="string"==typeof t?t:c,o[1]=i;for(var l=2;l=0||(c[n]=t[n]);return c}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(c[n]=t[n])}return c}var s=a.createContext({}),l=function(t){var e=a.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},p=function(t){var e=l(t.components);return a.createElement(s.Provider,{value:e},t.children)},h="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},d=a.forwardRef((function(t,e){var n=t.components,c=t.mdxType,r=t.originalType,s=t.parentName,p=i(t,["components","mdxType","originalType","parentName"]),h=l(n),d=c,m=h["".concat(s,".").concat(d)]||h[d]||u[d]||r;return n?a.createElement(m,o(o({ref:e},p),{},{components:n})):a.createElement(m,o({ref:e},p))}));function m(t,e){var n=arguments,c=e&&e.mdxType;if("string"==typeof t||c){var r=n.length,o=new Array(r);o[0]=d;var i={};for(var s in e)hasOwnProperty.call(e,s)&&(i[s]=e[s]);i.originalType=t,i[h]="string"==typeof t?t:c,o[1]=i;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),i=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=i(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=i(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||s;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,o=new Array(s);o[0]=h;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:r,o[1]=l;for(var i=2;i\n")),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Getting the account hash")),(0,s.kt)("p",null,"Run the following command and supply the path to your public key in hexadecimal format to get the account hash."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client account-address --public-key "[PATH_TO_YOUR_KEY]/public_key_hex"\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Querying global state")),(0,s.kt)("p",null,"Use the command template below to query the network status with regard to your account."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n--node-address http:// \\\n--state-root-hash [STATE_ROOT_HASH] \\\n--key [ACCOUNT_HASH]\n")),(0,s.kt)("h3",{id:"deploying-the-contract"},"Installing the Contract"),(0,s.kt)("p",null,"Now you can install the contract to the network and check how it behaves."),(0,s.kt)("p",null,"If you are sending the deploy on Mainnet, try several put deploys on the Testnet to understand the exact gas amount required for that deploy. Refer to the ",(0,s.kt)("a",{parentName:"p",href:"/developers/cli/sending-deploys/#a-note-about-gas-price"},"note about gas price")," to understand more about payment amounts and gas price adjustments."),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"The Casper platform currently does not refund any tokens as part of sending a deploy.")," For example, if you spend 10 CSPR for the deployment and it only costs 1 CSPR, you will not receive the remaining 9 CSPR. Refer to the ",(0,s.kt)("a",{parentName:"p",href:"/concepts/economics/gas-concepts/"},"Gas and the Casper Blockchain")," documentation for further details."),(0,s.kt)("p",null,"Use the following command template to deploy the contract:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address http:// \\\n --chain-name [NETWORK_NAME]] \\\n --secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \\\n --payment-amount [AMOUNT] \\\n --session-path [WASM_FILE_PATH]/[File_Name].wasm\n --session-arg <"NAME:TYPE=\'VALUE\'" OR "NAME:TYPE=null">\n')),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"NETWORK_NAME"),": Use the relevant network name. Here we use '",(0,s.kt)("em",{parentName:"li"},"casper-test"),"'"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"PATH_TO_YOUR_KEY"),": Replace this with the actual path of your secret key"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"PAYMENT_AMOUNT"),": Gas amount in tokens needed for contract execution. If there are no adequate tokens, the deploy will not execute and will return an error"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"WASM FILE PATH"),": The session-path argument should point to the location of your compiled Fungible Token Wasm file")),(0,s.kt)("p",null,"Here is a sample ",(0,s.kt)("em",{parentName:"p"},"put-deploy")," command:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n--node-address http://95.216.24.237:7777 \\\n--chain-name casper-test \\\n--secret-key "/home/ubuntu/secret_key.pem" \\\n--payment-amount 1000000 \\\n--session-path "/cep18/target/wasm32-unknown-unknown/release/cep18.wasm"\n--session-arg "name=\'Token test\', symbol=\'TEST\', decimals:u8=10, total_supply:u256=1000"\n')),(0,s.kt)("h3",{id:"querying-the-network-status"},"Querying the Network Status"),(0,s.kt)("p",null,"You will need the newest state root hash to view the network status, as it changed with the deploy. The account hash remains the same since you are using the same account. Follow the ",(0,s.kt)("a",{parentName:"p",href:"#viewing-the-network-status"},"viewing the network state")," section to execute this step with the new state root hash."),(0,s.kt)("h3",{id:"verifying-the-deploy"},"Verifying the Deploy"),(0,s.kt)("p",null,"Now you can verify the sent deploy using the ",(0,s.kt)("inlineCode",{parentName:"p"},"get-deploy")," command. This will output the details of the sent deploy."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n--node-address http:// [DEPLOY_HASH]\n")),(0,s.kt)("h3",{id:"querying-with-arguments"},"Querying with Arguments"),(0,s.kt)("p",null,"This step will narrow down the context and check the status of a specific entry point. You will use the details inside the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/blob/master/cep18/src/main.rs"},"Fungible Token contract")," to derive arguments."),(0,s.kt)("p",null,"Use the command template below to query the network state with arguments:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n--node-address http:// \\\n--state-root-hash [STATE_ROOT_HASH] \\\n--key [ACCOUNT_HASH] \\\n-q "[CONTRACT_NAME/ARGUMENT]"\n')),(0,s.kt)("h3",{id:"sample-deploy-testnet"},"Example Deploy on Testnet"),(0,s.kt)("p",null,"The following steps will guide you through the process with sample values and results."),(0,s.kt)("h4",{id:"cloning-the-fungible-token-contract"},"Cloning the Fungible Token Contract"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-ecosystem/cep18.git\n")),(0,s.kt)("h3",{id:"getting-an-ip-address-from-a-testnet-peer"},"Getting an IP Address from a Testnet Peer"),(0,s.kt)("p",null,"Use ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"peers")," to get the node IP address."),(0,s.kt)("h4",{id:"viewing-the-network-status"},"Viewing the Network Status"),(0,s.kt)("p",null,"Here is the command to query the state of the network:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n--key account-hash- \\\n--node-address http:// \\\n--state-root-hash E5B679BD1562fE6257257F5f969A79482E8DCEBBD501501BfA6d5844b61cBE3f\n")),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Result"),":"),(0,s.kt)("p",null,"This result contains the network state before the deploy. You can see the ",(0,s.kt)("inlineCode",{parentName:"p"},"named-key")," field is empty since we haven't sent the deploy to the network yet."),(0,s.kt)("details",null,(0,s.kt)("summary",null,"Result from querying the network status"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 401803927542812599,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.3",\n "merkle_proof": "[25564 hex chars]",\n "stored_value": {\n "Account": {\n "account_hash": "account-hash- ",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash- ",\n "weight": 1\n }\n ],\n "main_purse": "uref-",\n "named_keys": []\n }\n }\n }\n}\n'))),(0,s.kt)("br",null),(0,s.kt)("h4",{id:"sending-the-deploy"},"Sending the Deploy"),(0,s.kt)("p",null,"Send the Deploy containing your contract with this command:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n--node-address http:// \\\n--chain-name casper-test \\\n--secret-key "/home/ubuntu/secret_key.pem" \\\n--payment-amount 1000000 \\\n--session-path "/cep18/target/wasm32-unknown-unknown/release/cep18.wasm"\n--session-arg "name=\'Token test\', symbol=\'TEST\', decimals:u8=10, total_supply:u256=1000"\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Result"),":"),(0,s.kt)("p",null,"This command execution will output the ",(0,s.kt)("inlineCode",{parentName:"p"},"deploy_hash")," of the applied deploy. We can use the deploy_hash to get the details of the deploy."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 931694842944790108,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.3",\n "deploy_hash": "b00E59f8aBA5c7aB9...."\n }\n}\n')),(0,s.kt)("h4",{id:"viewing-the-deploy-details"},"Viewing the Deploy Details"),(0,s.kt)("p",null,"You can view the details of the sent deploy using the command below:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n--node-address http:// \\\nb00E59f8aBA5c7aB9.....\n")),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Result"),":"),(0,s.kt)("p",null,"This contains the header, payment, and session details along with the execution results."),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"If the execution result field appears as ",(0,s.kt)("inlineCode",{parentName:"li"},'"execution_results":[]'),", it means that the deploy hasn't been executed yet. The time to load the execution result may vary depending on the network.")),(0,s.kt)("details",null,(0,s.kt)("summary",null,"Result from querying the deploy"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n {\n "id": -870982079597140956,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.3",\n "deploy": {\n "approvals": [\n {\n "signature": "[130 hex chars]",\n "signer": "017B8CE645c728......................."\n }\n ],\n "hash": "F9D4C649Fa78Da07E.......................",\n "header": {\n "account": "017B8CE645c7285.......................",\n "body_hash": "8eAEd6B7bCBB493d75d.......................",\n "chain_name": "casper-test",\n "dependencies": [],\n "gas_price": 1,\n "timestamp": "2022-01-04T15:14:29.203Z",\n "ttl": "30m"\n },\n "payment": {\n "ModuleBytes": {\n "args": [\n [\n "amount",\n {\n "bytes": "0500e8764817",\n "cl_type": "U512",\n "parsed": "100000000000"\n }\n ]\n ],\n "module_bytes": ""\n }\n },\n "session": {\n "ModuleBytes": {\n "args": [],\n "module_bytes": "[417800 hex chars]"\n }\n }\n },\n "execution_results": [\n {\n "block_hash": "d3644f0306F20fa6.......................",\n "result": {\n "Success": {\n "cost": "45040980830",\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-8cf5E4aCF51f54Eb5.......................",\n "transform": "Identity"\n },\n {\n "key": "hash-624dBE2395b9D9503FB.......................",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3Fe81B7b862E50C77.......................",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dC3A5c44A20b.......................",\n "transform": "Identity"\n },\n {\n "key": "balance-C051e7EC16e08De.......................",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324F865243.......................",\n "transform": "Identity"\n },\n {\n "key": "balance-C051e7EC16e08Def8b556",\n "transform": {\n "WriteCLValue": {\n "bytes": "06E07f3abEa001",\n "cl_type": "U512",\n "parsed": "1789897900000"\n }\n }\n },\n {\n "key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",\n "transform": {\n "AddUInt512": "100000000000"\n }\n },\n {\n "key": "uref-d29a34C29769D4BaC250CF9efD3c6372d8e6a89B62fAD122b3BF009990Ae61CD-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "",\n "cl_type": "Unit",\n "parsed": null\n }\n }\n },\n {\n "key": "account-hash-7f4bf39A3...................................................",\n "transform": {\n "AddKeys": [\n {\n "key": "uref-d29a34C29769D4BaC250CF9efD3c6372d8e6a89B62fAD122b3BF009990Ae61CD-007",\n "name": "balances"\n }\n ]\n }\n },\n {\n "key": "uref-075874B98e3CF57Ea6326746336A0Aa908e770D3ADe0cf953f7E146f8B64F837-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "",\n "cl_type": "Unit",\n "parsed": null\n }\n }\n },\n {\n "key": "account-hash-7f4bf39A311...................................................",\n "transform": {\n "AddKeys": [\n {\n "key": "uref-075874B98e3CF57Ea6326746336A0Aa908e770D3ADe0cf953f7E146f8B64F837-007",\n "name": "allowances"\n }\n ]\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "0400ca9A3B",\n "cl_type": "U256",\n "parsed": "1000000000"\n }\n }\n },\n {\n "key": "uref-4EB0a2A42afBb1d3D5ae9BD4781dc96E528C7AD3f0eEC240Cf1DbDaDF4f3D486-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "0A00000043617370657254657374",\n "cl_type": "String",\n "parsed": "CasperTest"\n }\n }\n },\n {\n "key": "uref-6e87fd661D5a65aF95f02baDfEb64f8E0F44C006661d4903A68E9dF8dEAa413d-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "050000004353505254",\n "cl_type": "String",\n "parsed": "CSPRT"\n }\n }\n },\n {\n "key": "uref-aCA2425C80584391fB883603460578B1472d13a429Ebbd1a18a55cE19cE8F3C6-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "08",\n "cl_type": "U8",\n "parsed": 8\n }\n }\n },\n {\n "key": "dictionary-baA61231F04B1c2Ee97025f425eaD2F70CAd9c1E8c24355246d159038AdCb2e9",\n "transform": {\n "WriteCLValue": {\n "bytes": "[188 hex chars]",\n "cl_type": "Any",\n "parsed": null\n }\n }\n },\n {\n "key": "account-hash-7f4bf39A311a7538d8C...................................................",\n "transform": "Identity"\n },\n {\n "key": "account-hash-7f4bf39A311a75...................................................",\n "transform": {\n "WriteAccount": "account-hash-7f4bf39A311a7538d8C91BB86C71DF774023e16bc4a70ab7e4e8AE77DbF2Ef53"\n }\n },\n {\n "key": "account-hash-7f4bf39A311a7538...................................................",\n "transform": "Identity"\n },\n {\n "key": "account-hash-7f4bf39A311a7538d8C...................................................",\n "transform": {\n "WriteAccount": "account-hash-7f4bf39A311a75..................................................."\n }\n },\n {\n "key": "uref-868c0e0BEB2EB3C10e893be96E6D6bE7FC6375f3f038e46c3262509245c117a0-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "",\n "cl_type": "Unit",\n "parsed": null\n }\n }\n },\n {\n "key": "hash-28f982A396052b5068383E725ab48965AB941167f53DB36a0911ba0C98bc39F0",\n "transform": "WriteContractPackage"\n },\n {\n "key": "hash-28f982A396052b5068383E725ab48965AB941167f53DB36a0911ba0C98bc39F0",\n "transform": "Identity"\n },\n {\n "key": "hash-AdF81845d77907054ACb250c196392c7DAEE5481d4EabEB76c318A307c11E5cB",\n "transform": "WriteContractWasm"\n },\n {\n "key": "hash-Faa81ED758ecE1B99E2Ce48073D13D7f6185d9dc5233E39DE5c192Bebb9483D6",\n "transform": "WriteContract"\n },\n {\n "key": "hash-28f982A396052b5068383E725ab48965AB941167f53DB36a0911ba0C98bc39F0",\n "transform": "WriteContractPackage"\n },\n {\n "key": "account-hash-7f4bf39A311a7538d8...................................................",\n "transform": {\n "AddKeys": [\n {\n "key": "hash-Faa81ED758ecE1B99E2Ce48073D13D7f6185d9dc5233E39DE5c192Bebb9483D6",\n "name": "test_contract"\n }\n ]\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": "Identity"\n },\n {\n "key": "dictionary-04932d42aff9367579770E219ce1C4Da83D1Fd42Fa0FaA4Ae98AE07914c4c1E4",\n "transform": {\n "WriteCLValue": {\n "bytes": "[186 hex chars]",\n "cl_type": "Any",\n "parsed": null\n }\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "04400cAa3b",\n "cl_type": "U256",\n "parsed": "1001000000"\n }\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": "Identity"\n },\n {\n "key": "dictionary-Ec3f20485A29255dd2c2D7b8c008207A0d139dFDCE89224DA8b63F21c157A97F",\n "transform": {\n "WriteCLValue": {\n "bytes": "[186 hex chars]",\n "cl_type": "Any",\n "parsed": null\n }\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "04C090c83b",\n "cl_type": "U256",\n "parsed": "1003000000"\n }\n }\n },\n {\n "key": "deploy-F9D4C649Fa78Da...................................................",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "F9D4C649Fa78Da07Ec6EFcFC615ff1Bd3B68347750FA0C81B6a74C3f9582d7E4",\n "from": "account-hash-7f4bf39A311a...................................................",\n "gas": "45040980830",\n "source": "uref-C051e7EC16e08Def8b556F9...................................................",\n "transfers": []\n }\n }\n },\n {\n "key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5E4aCF51f54Eb59291599187838Dc3BC234089c46fc6cA8AD17e762aE4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3Fe81B7b862E50C77EF9A958a05BfA98444F26f96f23d37A13c96244cFB7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dC3A5c44A20b9FD260a412437933835B52Fc683d8AE36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",\n "transform": "Identity"\n },\n {\n "key": "balance-c69d353A5a3b6433368A8FC2F6b308ce4Ec10291782f61BA15C96F260f91FFC0",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",\n "transform": {\n "WriteCLValue": {\n "bytes": "00",\n "cl_type": "U512",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-c69d353A5a3b6433368A8FC2F6b308ce4Ec10291782f61BA15C96F260f91FFC0",\n "transform": {\n "AddUInt512": "100000000000"\n }\n }\n ]\n },\n "transfers": []\n }\n }\n }\n ]\n }\n}\n'))),(0,s.kt)("br",null),(0,s.kt)("h4",{id:"querying-contract-entry-points"},"Querying Contract Entry Points"),(0,s.kt)("p",null,"We will query the argument 'name' in this example."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state --node-address http://95.216.24.237:7777 \\\n--state-root-hash D00dF8c35B0E9995c2911803F37A212d82c960D9bC5bA3C4F99a661e18D09411 \\\n--key account-hash-7f4bf39A311a7538d8C91BB86C71DF774023e16bc4a70ab7e4e8AE77DbF2Ef53 \\\n-q "test_contract/name"\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Result"),":"),(0,s.kt)("p",null,"You can see that the name is ",(0,s.kt)("inlineCode",{parentName:"p"},"CasperTest")," in this example."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -3650676146668320186,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.3",\n "block_header": null,\n "merkle_proof": "[80252 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "0A00000043617370657254657374",\n "cl_type": "String",\n "parsed": "CasperTest"\n }\n }\n }\n}\n\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/86a6526c.da72e427.js b/assets/js/86a6526c.da72e427.js new file mode 100644 index 0000000000..099bc9229d --- /dev/null +++ b/assets/js/86a6526c.da72e427.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4511],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),i=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=i(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=i(n),h=r,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||s;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,o=new Array(s);o[0]=h;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:r,o[1]=l;for(var i=2;i\n")),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Getting the account hash")),(0,s.kt)("p",null,"Run the following command and supply the path to your public key in hexadecimal format to get the account hash."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client account-address --public-key "[PATH_TO_YOUR_KEY]/public_key_hex"\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Querying global state")),(0,s.kt)("p",null,"Use the command template below to query the network status with regard to your account."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n--node-address http:// \\\n--state-root-hash [STATE_ROOT_HASH] \\\n--key [ACCOUNT_HASH]\n")),(0,s.kt)("h3",{id:"deploying-the-contract"},"Installing the Contract"),(0,s.kt)("p",null,"Now you can install the contract to the network and check how it behaves."),(0,s.kt)("p",null,"If you are sending the deploy on Mainnet, try several put deploys on the Testnet to understand the exact gas amount required for that deploy. Refer to the ",(0,s.kt)("a",{parentName:"p",href:"/developers/cli/sending-deploys/#a-note-about-gas-price"},"note about gas price")," to understand more about payment amounts and gas price adjustments."),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"The Casper platform currently does not refund any tokens as part of sending a deploy.")," For example, if you spend 10 CSPR for the deployment and it only costs 1 CSPR, you will not receive the remaining 9 CSPR. Refer to the ",(0,s.kt)("a",{parentName:"p",href:"/concepts/economics/gas-concepts/"},"Gas and the Casper Blockchain")," documentation for further details."),(0,s.kt)("p",null,"Use the following command template to deploy the contract:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address http:// \\\n --chain-name [NETWORK_NAME]] \\\n --secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \\\n --payment-amount [AMOUNT] \\\n --session-path [WASM_FILE_PATH]/[File_Name].wasm\n --session-arg <"NAME:TYPE=\'VALUE\'" OR "NAME:TYPE=null">\n')),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"NETWORK_NAME"),": Use the relevant network name. Here we use '",(0,s.kt)("em",{parentName:"li"},"casper-test"),"'"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"PATH_TO_YOUR_KEY"),": Replace this with the actual path of your secret key"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"PAYMENT_AMOUNT"),": Gas amount in tokens needed for contract execution. If there are no adequate tokens, the deploy will not execute and will return an error"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"WASM FILE PATH"),": The session-path argument should point to the location of your compiled Fungible Token Wasm file")),(0,s.kt)("p",null,"Here is a sample ",(0,s.kt)("em",{parentName:"p"},"put-deploy")," command:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n--node-address http://95.216.24.237:7777 \\\n--chain-name casper-test \\\n--secret-key "/home/ubuntu/secret_key.pem" \\\n--payment-amount 1000000 \\\n--session-path "/cep18/target/wasm32-unknown-unknown/release/cep18.wasm"\n--session-arg "name=\'Token test\', symbol=\'TEST\', decimals:u8=10, total_supply:u256=1000"\n')),(0,s.kt)("h3",{id:"querying-the-network-status"},"Querying the Network Status"),(0,s.kt)("p",null,"You will need the newest state root hash to view the network status, as it changed with the deploy. The account hash remains the same since you are using the same account. Follow the ",(0,s.kt)("a",{parentName:"p",href:"#viewing-the-network-status"},"viewing the network state")," section to execute this step with the new state root hash."),(0,s.kt)("h3",{id:"verifying-the-deploy"},"Verifying the Deploy"),(0,s.kt)("p",null,"Now you can verify the sent deploy using the ",(0,s.kt)("inlineCode",{parentName:"p"},"get-deploy")," command. This will output the details of the sent deploy."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n--node-address http:// [DEPLOY_HASH]\n")),(0,s.kt)("h3",{id:"querying-with-arguments"},"Querying with Arguments"),(0,s.kt)("p",null,"This step will narrow down the context and check the status of a specific entry point. You will use the details inside the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/cep18/blob/master/cep18/src/main.rs"},"Fungible Token contract")," to derive arguments."),(0,s.kt)("p",null,"Use the command template below to query the network state with arguments:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state \\\n--node-address http:// \\\n--state-root-hash [STATE_ROOT_HASH] \\\n--key [ACCOUNT_HASH] \\\n-q "[CONTRACT_NAME/ARGUMENT]"\n')),(0,s.kt)("h3",{id:"sample-deploy-testnet"},"Example Deploy on Testnet"),(0,s.kt)("p",null,"The following steps will guide you through the process with sample values and results."),(0,s.kt)("h4",{id:"cloning-the-fungible-token-contract"},"Cloning the Fungible Token Contract"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-ecosystem/cep18.git\n")),(0,s.kt)("h3",{id:"getting-an-ip-address-from-a-testnet-peer"},"Getting an IP Address from a Testnet Peer"),(0,s.kt)("p",null,"Use ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"peers")," to get the node IP address."),(0,s.kt)("h4",{id:"viewing-the-network-status"},"Viewing the Network Status"),(0,s.kt)("p",null,"Here is the command to query the state of the network:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n--key account-hash- \\\n--node-address http:// \\\n--state-root-hash E5B679BD1562fE6257257F5f969A79482E8DCEBBD501501BfA6d5844b61cBE3f\n")),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Result"),":"),(0,s.kt)("p",null,"This result contains the network state before the deploy. You can see the ",(0,s.kt)("inlineCode",{parentName:"p"},"named-key")," field is empty since we haven't sent the deploy to the network yet."),(0,s.kt)("details",null,(0,s.kt)("summary",null,"Result from querying the network status"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 401803927542812599,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.3",\n "merkle_proof": "[25564 hex chars]",\n "stored_value": {\n "Account": {\n "account_hash": "account-hash- ",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash- ",\n "weight": 1\n }\n ],\n "main_purse": "uref-",\n "named_keys": []\n }\n }\n }\n}\n'))),(0,s.kt)("br",null),(0,s.kt)("h4",{id:"sending-the-deploy"},"Sending the Deploy"),(0,s.kt)("p",null,"Send the Deploy containing your contract with this command:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n--node-address http:// \\\n--chain-name casper-test \\\n--secret-key "/home/ubuntu/secret_key.pem" \\\n--payment-amount 1000000 \\\n--session-path "/cep18/target/wasm32-unknown-unknown/release/cep18.wasm"\n--session-arg "name=\'Token test\', symbol=\'TEST\', decimals:u8=10, total_supply:u256=1000"\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Result"),":"),(0,s.kt)("p",null,"This command execution will output the ",(0,s.kt)("inlineCode",{parentName:"p"},"deploy_hash")," of the applied deploy. We can use the deploy_hash to get the details of the deploy."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 931694842944790108,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.3",\n "deploy_hash": "b00E59f8aBA5c7aB9...."\n }\n}\n')),(0,s.kt)("h4",{id:"viewing-the-deploy-details"},"Viewing the Deploy Details"),(0,s.kt)("p",null,"You can view the details of the sent deploy using the command below:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n--node-address http:// \\\nb00E59f8aBA5c7aB9.....\n")),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Result"),":"),(0,s.kt)("p",null,"This contains the header, payment, and session details along with the execution results."),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"If the execution result field appears as ",(0,s.kt)("inlineCode",{parentName:"li"},'"execution_results":[]'),", it means that the deploy hasn't been executed yet. The time to load the execution result may vary depending on the network.")),(0,s.kt)("details",null,(0,s.kt)("summary",null,"Result from querying the deploy"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n {\n "id": -870982079597140956,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.3",\n "deploy": {\n "approvals": [\n {\n "signature": "[130 hex chars]",\n "signer": "017B8CE645c728......................."\n }\n ],\n "hash": "F9D4C649Fa78Da07E.......................",\n "header": {\n "account": "017B8CE645c7285.......................",\n "body_hash": "8eAEd6B7bCBB493d75d.......................",\n "chain_name": "casper-test",\n "dependencies": [],\n "gas_price": 1,\n "timestamp": "2022-01-04T15:14:29.203Z",\n "ttl": "30m"\n },\n "payment": {\n "ModuleBytes": {\n "args": [\n [\n "amount",\n {\n "bytes": "0500e8764817",\n "cl_type": "U512",\n "parsed": "100000000000"\n }\n ]\n ],\n "module_bytes": ""\n }\n },\n "session": {\n "ModuleBytes": {\n "args": [],\n "module_bytes": "[417800 hex chars]"\n }\n }\n },\n "execution_results": [\n {\n "block_hash": "d3644f0306F20fa6.......................",\n "result": {\n "Success": {\n "cost": "45040980830",\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-8cf5E4aCF51f54Eb5.......................",\n "transform": "Identity"\n },\n {\n "key": "hash-624dBE2395b9D9503FB.......................",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3Fe81B7b862E50C77.......................",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dC3A5c44A20b.......................",\n "transform": "Identity"\n },\n {\n "key": "balance-C051e7EC16e08De.......................",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324F865243.......................",\n "transform": "Identity"\n },\n {\n "key": "balance-C051e7EC16e08Def8b556",\n "transform": {\n "WriteCLValue": {\n "bytes": "06E07f3abEa001",\n "cl_type": "U512",\n "parsed": "1789897900000"\n }\n }\n },\n {\n "key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",\n "transform": {\n "AddUInt512": "100000000000"\n }\n },\n {\n "key": "uref-d29a34C29769D4BaC250CF9efD3c6372d8e6a89B62fAD122b3BF009990Ae61CD-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "",\n "cl_type": "Unit",\n "parsed": null\n }\n }\n },\n {\n "key": "account-hash-7f4bf39A3...................................................",\n "transform": {\n "AddKeys": [\n {\n "key": "uref-d29a34C29769D4BaC250CF9efD3c6372d8e6a89B62fAD122b3BF009990Ae61CD-007",\n "name": "balances"\n }\n ]\n }\n },\n {\n "key": "uref-075874B98e3CF57Ea6326746336A0Aa908e770D3ADe0cf953f7E146f8B64F837-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "",\n "cl_type": "Unit",\n "parsed": null\n }\n }\n },\n {\n "key": "account-hash-7f4bf39A311...................................................",\n "transform": {\n "AddKeys": [\n {\n "key": "uref-075874B98e3CF57Ea6326746336A0Aa908e770D3ADe0cf953f7E146f8B64F837-007",\n "name": "allowances"\n }\n ]\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "0400ca9A3B",\n "cl_type": "U256",\n "parsed": "1000000000"\n }\n }\n },\n {\n "key": "uref-4EB0a2A42afBb1d3D5ae9BD4781dc96E528C7AD3f0eEC240Cf1DbDaDF4f3D486-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "0A00000043617370657254657374",\n "cl_type": "String",\n "parsed": "CasperTest"\n }\n }\n },\n {\n "key": "uref-6e87fd661D5a65aF95f02baDfEb64f8E0F44C006661d4903A68E9dF8dEAa413d-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "050000004353505254",\n "cl_type": "String",\n "parsed": "CSPRT"\n }\n }\n },\n {\n "key": "uref-aCA2425C80584391fB883603460578B1472d13a429Ebbd1a18a55cE19cE8F3C6-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "08",\n "cl_type": "U8",\n "parsed": 8\n }\n }\n },\n {\n "key": "dictionary-baA61231F04B1c2Ee97025f425eaD2F70CAd9c1E8c24355246d159038AdCb2e9",\n "transform": {\n "WriteCLValue": {\n "bytes": "[188 hex chars]",\n "cl_type": "Any",\n "parsed": null\n }\n }\n },\n {\n "key": "account-hash-7f4bf39A311a7538d8C...................................................",\n "transform": "Identity"\n },\n {\n "key": "account-hash-7f4bf39A311a75...................................................",\n "transform": {\n "WriteAccount": "account-hash-7f4bf39A311a7538d8C91BB86C71DF774023e16bc4a70ab7e4e8AE77DbF2Ef53"\n }\n },\n {\n "key": "account-hash-7f4bf39A311a7538...................................................",\n "transform": "Identity"\n },\n {\n "key": "account-hash-7f4bf39A311a7538d8C...................................................",\n "transform": {\n "WriteAccount": "account-hash-7f4bf39A311a75..................................................."\n }\n },\n {\n "key": "uref-868c0e0BEB2EB3C10e893be96E6D6bE7FC6375f3f038e46c3262509245c117a0-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "",\n "cl_type": "Unit",\n "parsed": null\n }\n }\n },\n {\n "key": "hash-28f982A396052b5068383E725ab48965AB941167f53DB36a0911ba0C98bc39F0",\n "transform": "WriteContractPackage"\n },\n {\n "key": "hash-28f982A396052b5068383E725ab48965AB941167f53DB36a0911ba0C98bc39F0",\n "transform": "Identity"\n },\n {\n "key": "hash-AdF81845d77907054ACb250c196392c7DAEE5481d4EabEB76c318A307c11E5cB",\n "transform": "WriteContractWasm"\n },\n {\n "key": "hash-Faa81ED758ecE1B99E2Ce48073D13D7f6185d9dc5233E39DE5c192Bebb9483D6",\n "transform": "WriteContract"\n },\n {\n "key": "hash-28f982A396052b5068383E725ab48965AB941167f53DB36a0911ba0C98bc39F0",\n "transform": "WriteContractPackage"\n },\n {\n "key": "account-hash-7f4bf39A311a7538d8...................................................",\n "transform": {\n "AddKeys": [\n {\n "key": "hash-Faa81ED758ecE1B99E2Ce48073D13D7f6185d9dc5233E39DE5c192Bebb9483D6",\n "name": "test_contract"\n }\n ]\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": "Identity"\n },\n {\n "key": "dictionary-04932d42aff9367579770E219ce1C4Da83D1Fd42Fa0FaA4Ae98AE07914c4c1E4",\n "transform": {\n "WriteCLValue": {\n "bytes": "[186 hex chars]",\n "cl_type": "Any",\n "parsed": null\n }\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "04400cAa3b",\n "cl_type": "U256",\n "parsed": "1001000000"\n }\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": "Identity"\n },\n {\n "key": "dictionary-Ec3f20485A29255dd2c2D7b8c008207A0d139dFDCE89224DA8b63F21c157A97F",\n "transform": {\n "WriteCLValue": {\n "bytes": "[186 hex chars]",\n "cl_type": "Any",\n "parsed": null\n }\n }\n },\n {\n "key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "04C090c83b",\n "cl_type": "U256",\n "parsed": "1003000000"\n }\n }\n },\n {\n "key": "deploy-F9D4C649Fa78Da...................................................",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "F9D4C649Fa78Da07Ec6EFcFC615ff1Bd3B68347750FA0C81B6a74C3f9582d7E4",\n "from": "account-hash-7f4bf39A311a...................................................",\n "gas": "45040980830",\n "source": "uref-C051e7EC16e08Def8b556F9...................................................",\n "transfers": []\n }\n }\n },\n {\n "key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5E4aCF51f54Eb59291599187838Dc3BC234089c46fc6cA8AD17e762aE4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3Fe81B7b862E50C77EF9A958a05BfA98444F26f96f23d37A13c96244cFB7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dC3A5c44A20b9FD260a412437933835B52Fc683d8AE36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",\n "transform": "Identity"\n },\n {\n "key": "balance-c69d353A5a3b6433368A8FC2F6b308ce4Ec10291782f61BA15C96F260f91FFC0",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",\n "transform": {\n "WriteCLValue": {\n "bytes": "00",\n "cl_type": "U512",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-c69d353A5a3b6433368A8FC2F6b308ce4Ec10291782f61BA15C96F260f91FFC0",\n "transform": {\n "AddUInt512": "100000000000"\n }\n }\n ]\n },\n "transfers": []\n }\n }\n }\n ]\n }\n}\n'))),(0,s.kt)("br",null),(0,s.kt)("h4",{id:"querying-contract-entry-points"},"Querying Contract Entry Points"),(0,s.kt)("p",null,"We will query the argument 'name' in this example."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state --node-address http://95.216.24.237:7777 \\\n--state-root-hash D00dF8c35B0E9995c2911803F37A212d82c960D9bC5bA3C4F99a661e18D09411 \\\n--key account-hash-7f4bf39A311a7538d8C91BB86C71DF774023e16bc4a70ab7e4e8AE77DbF2Ef53 \\\n-q "test_contract/name"\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Result"),":"),(0,s.kt)("p",null,"You can see that the name is ",(0,s.kt)("inlineCode",{parentName:"p"},"CasperTest")," in this example."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -3650676146668320186,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.3",\n "block_header": null,\n "merkle_proof": "[80252 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "0A00000043617370657254657374",\n "cl_type": "String",\n "parsed": "CasperTest"\n }\n }\n }\n}\n\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/87ec732b.108a03b1.js b/assets/js/87ec732b.108a03b1.js deleted file mode 100644 index ad37d74460..0000000000 --- a/assets/js/87ec732b.108a03b1.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5607],{3905:function(e,t,r){r.d(t,{Zo:function(){return i},kt:function(){return y}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),h=a,y=u["".concat(p,".").concat(h)]||u[h]||f[h]||o;return r?n.createElement(y,s(s({ref:t},i),{},{components:r})):n.createElement(y,s({ref:t},i))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=h;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),h=a,y=u["".concat(p,".").concat(h)]||u[h]||f[h]||o;return r?n.createElement(y,s(s({ref:t},i),{},{components:r})):n.createElement(y,s({ref:t},i))}));function y(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=h;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(f,i(i({ref:t},l),{},{components:n})):r.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:a,i[1]=c;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(f,i(i({ref:t},l),{},{components:n})):r.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:a,i[1]=c;for(var p=2;p=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},g=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,c=e.parentName,g=o(e,["components","mdxType","originalType","parentName"]),d=s(r),u=i,k=d["".concat(c,".").concat(u)]||d[u]||p[u]||a;return r?n.createElement(k,l(l({ref:t},g),{},{components:r})):n.createElement(k,l({ref:t},g))}));function k(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,l=new Array(a);l[0]=u;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[d]="string"==typeof e?e:i,l[1]=o;for(var s=2;s=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var c=n.createContext({}),s=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},g=function(e){var t=s(e.components);return n.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var r=e.components,i=e.mdxType,a=e.originalType,c=e.parentName,g=o(e,["components","mdxType","originalType","parentName"]),d=s(r),u=i,k=d["".concat(c,".").concat(u)]||d[u]||p[u]||a;return r?n.createElement(k,l(l({ref:t},g),{},{components:r})):n.createElement(k,l({ref:t},g))}));function k(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=r.length,l=new Array(a);l[0]=u;var o={};for(var c in t)hasOwnProperty.call(t,c)&&(o[c]=t[c]);o.originalType=e,o[d]="string"==typeof e?e:i,l[1]=o;for(var s=2;s=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),h=l(n),p=a,m=h["".concat(c,".").concat(p)]||h[p]||d[p]||o;return n?r.createElement(m,s(s({ref:t},u),{},{components:n})):r.createElement(m,s({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=p;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[h]="string"==typeof e?e:a,s[1]=i;for(var l=2;l new_purse\n });\n}\n\n')),(0,o.kt)("h3",{id:"scenario1-advanced"},"Scenario 1 - Advanced Variation"),(0,o.kt)("p",null,"Advanced versions of this scenario can mitigate the wastefulness inherent in the example. If the caller creates a named purse independent of their main purse, they can integrate it with the contract in question. In this way, the same purse can be used to fund a contract repeatedly."),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.4.4/smart_contracts/contracts/client/named-purse-payment/src/main.rs"},"This example")," provides a framework for the idea, but will require modification to suit developer needs."),(0,o.kt)("h2",{id:"scenario2"},"Scenario 2 - Maintaining a Reusable Purse within Contract Logic"),(0,o.kt)("p",null,"The second scenario involves more complex internal logic to allow for a purse's reuse. The contract itself keeps track of a purse associated with the caller as internal bookkeeping."),(0,o.kt)("p",null,"In ",(0,o.kt)("a",{parentName:"p",href:"#scenario1"},"Scenario 1"),", the newly created purse is a pure means of transferring tokens from the caller to the callee. In contrast, Scenario 2 maintains an internal purse associated with the caller's address. This purse serves as token storage for actions the caller wishes the contract to undertake on their behalf. It differs from ",(0,o.kt)("a",{parentName:"p",href:"#scenario1-advanced"},"Scenario 1's Advanced Variation")," in that the purse in question is under the control of the contract rather than the caller."),(0,o.kt)("p",null,"Scenario 2 offers a less wasteful means of transferring tokens to a contract but comes with the added burden of internal complexity. When choosing between the two scenarios, you must evaluate the scope and needs of your project and choose accordingly."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'// Scenario 2: with this style, the contract being called has some internal accounting\n// to keep track of a reusable purse associated to the calling account; this avoids\n// wasteful creation of one time purses but requires the smart contract being called\n// to have more sophisticated internal logic.\n#[no_mangle]\npub extern "C" fn call() {\n let amount: U512 = runtime::get_named_arg("amount");\n\n // This is demonstrating the most direct case, wherein you pass in the contract_hash and\n // the entry_point_names of the target contract as args.\n // With prior setup having been done, this can also be simplified.\n let contract_hash = runtime::get_named_arg("contract_hash");\n // the name of the entry point on the contract that returns a purse uref to receive token at\n // the actual name of the entry point is up to the smart contract authors\n let deposit_point_name = runtime::get_named_arg("deposit_point_name");\n // whatever entry point on the smart contract does the actual work if token has been transferred\n // the actual name of which is up to the smart contract authors.\n let other_entry_point_name = runtime::get_named_arg("other_entry_point_name");\n\n // The smart contract returns a purse URef of a deposit purse (with ADD access rights only)\n // for the caller to transfer to.\n let deposit_purse: URef = runtime::call_contract(contract_hash, deposit_point_name, runtime_args! {});\n\n // transfer from the caller\'s purse to the purse provided by the contract; the transfer is handled\n // safely by the host and the caller\'s purse is never exposed to the called smart contract.\n system::transfer_from_purse_to_purse(account::get_main_purse(), deposit_purse, amount, None)\n .unwrap_or_revert();\n\n // The contract being interacted with looks up the associated purse, checks its balance, etc.\n // within its logic. That side of it is entirely up to the smart contract authors to code; the caller\n // merely calls the logic. Also, the entry point might require one or more runtime arguments.\n // In all cases some discovery of the API of the contract you are calling is necessary.\n runtime::call_contract(contract_hash, other_entry_point_name, runtime_args! {});\n}\n\n')),(0,o.kt)("h3",{id:"scenario2-advanced"},"Scenario 2 - Advanced Variation"),(0,o.kt)("p",null,"In Scenario 2, the contract in question maintains a purse for each associated caller. The advanced variation establishes an internal ledger that records the balance of each caller. The contract can record the information for each caller as a dictionary item and respond accordingly. In this fashion, a single purse can store the motes of all callers accessing the contract."),(0,o.kt)("p",null,"This design streamlines the internal accounting process of the contract but does require a greater degree of complexity during the initial setup."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8c2276de.bff6feb3.js b/assets/js/8c2276de.bff6feb3.js new file mode 100644 index 0000000000..3de7c5b311 --- /dev/null +++ b/assets/js/8c2276de.bff6feb3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3608],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},h="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),h=l(n),p=a,m=h["".concat(c,".").concat(p)]||h[p]||d[p]||o;return n?r.createElement(m,s(s({ref:t},u),{},{components:n})):r.createElement(m,s({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=p;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[h]="string"==typeof e?e:a,s[1]=i;for(var l=2;l new_purse\n });\n}\n\n')),(0,o.kt)("h3",{id:"scenario1-advanced"},"Scenario 1 - Advanced Variation"),(0,o.kt)("p",null,"Advanced versions of this scenario can mitigate the wastefulness inherent in the example. If the caller creates a named purse independent of their main purse, they can integrate it with the contract in question. In this way, the same purse can be used to fund a contract repeatedly."),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.4.4/smart_contracts/contracts/client/named-purse-payment/src/main.rs"},"This example")," provides a framework for the idea, but will require modification to suit developer needs."),(0,o.kt)("h2",{id:"scenario2"},"Scenario 2 - Maintaining a Reusable Purse within Contract Logic"),(0,o.kt)("p",null,"The second scenario involves more complex internal logic to allow for a purse's reuse. The contract itself keeps track of a purse associated with the caller as internal bookkeeping."),(0,o.kt)("p",null,"In ",(0,o.kt)("a",{parentName:"p",href:"#scenario1"},"Scenario 1"),", the newly created purse is a pure means of transferring tokens from the caller to the callee. In contrast, Scenario 2 maintains an internal purse associated with the caller's address. This purse serves as token storage for actions the caller wishes the contract to undertake on their behalf. It differs from ",(0,o.kt)("a",{parentName:"p",href:"#scenario1-advanced"},"Scenario 1's Advanced Variation")," in that the purse in question is under the control of the contract rather than the caller."),(0,o.kt)("p",null,"Scenario 2 offers a less wasteful means of transferring tokens to a contract but comes with the added burden of internal complexity. When choosing between the two scenarios, you must evaluate the scope and needs of your project and choose accordingly."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'// Scenario 2: with this style, the contract being called has some internal accounting\n// to keep track of a reusable purse associated to the calling account; this avoids\n// wasteful creation of one time purses but requires the smart contract being called\n// to have more sophisticated internal logic.\n#[no_mangle]\npub extern "C" fn call() {\n let amount: U512 = runtime::get_named_arg("amount");\n\n // This is demonstrating the most direct case, wherein you pass in the contract_hash and\n // the entry_point_names of the target contract as args.\n // With prior setup having been done, this can also be simplified.\n let contract_hash = runtime::get_named_arg("contract_hash");\n // the name of the entry point on the contract that returns a purse uref to receive token at\n // the actual name of the entry point is up to the smart contract authors\n let deposit_point_name = runtime::get_named_arg("deposit_point_name");\n // whatever entry point on the smart contract does the actual work if token has been transferred\n // the actual name of which is up to the smart contract authors.\n let other_entry_point_name = runtime::get_named_arg("other_entry_point_name");\n\n // The smart contract returns a purse URef of a deposit purse (with ADD access rights only)\n // for the caller to transfer to.\n let deposit_purse: URef = runtime::call_contract(contract_hash, deposit_point_name, runtime_args! {});\n\n // transfer from the caller\'s purse to the purse provided by the contract; the transfer is handled\n // safely by the host and the caller\'s purse is never exposed to the called smart contract.\n system::transfer_from_purse_to_purse(account::get_main_purse(), deposit_purse, amount, None)\n .unwrap_or_revert();\n\n // The contract being interacted with looks up the associated purse, checks its balance, etc.\n // within its logic. That side of it is entirely up to the smart contract authors to code; the caller\n // merely calls the logic. Also, the entry point might require one or more runtime arguments.\n // In all cases some discovery of the API of the contract you are calling is necessary.\n runtime::call_contract(contract_hash, other_entry_point_name, runtime_args! {});\n}\n\n')),(0,o.kt)("h3",{id:"scenario2-advanced"},"Scenario 2 - Advanced Variation"),(0,o.kt)("p",null,"In Scenario 2, the contract in question maintains a purse for each associated caller. The advanced variation establishes an internal ledger that records the balance of each caller. The contract can record the information for each caller as a dictionary item and respond accordingly. In this fashion, a single purse can store the motes of all callers accessing the contract."),(0,o.kt)("p",null,"This design streamlines the internal accounting process of the contract but does require a greater degree of complexity during the initial setup."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8f925d60.a0b95ce7.js b/assets/js/8f925d60.a0b95ce7.js deleted file mode 100644 index 8195e9fb04..0000000000 --- a/assets/js/8f925d60.a0b95ce7.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4835],{3905:function(e,t,a){a.d(t,{Zo:function(){return s},kt:function(){return u}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),d=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},s=function(e){var t=d(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},b=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,c=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),p=d(a),b=r,u=p["".concat(c,".").concat(b)]||p[b]||f[b]||l;return a?n.createElement(u,o(o({ref:t},s),{},{components:a})):n.createElement(u,o({ref:t},s))}));function u(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,o=new Array(l);o[0]=b;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[p]="string"==typeof e?e:r,o[1]=i;for(var d=2;dstate_get_auction_info_result",id:"state_get_auction_info_result",level:3},{value:"info_get_validator_changes",id:"info-get-validator-changes",level:2},{value:"info_get_validator_changes_result",id:"info_get_validator_changes_result",level:3},{value:"chain_get_era_info_by_switch_block",id:"chain_get_era_info_by_switch_block",level:2},{value:"chain_get_era_info_by_switch_block_result",id:"chain_get_era_info_by_switch_block_result",level:3}],f={toc:p},b="wrapper";function u(e){var t=e.components,a=(0,r.Z)(e,o);return(0,l.kt)(b,(0,n.Z)({},f,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"proof-of-stake"},"Proof-of-Stake JSON-RPC Methods"),(0,l.kt)("p",null,"The following methods pertain to the Proof-of-Stake functionality of a Casper network. They return information related to auctions, bids and validators. This information is necessary for users involved with node operations and validation."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"state-get-auction-info"},"state_get_auction_info"),(0,l.kt)("p",null,"This method returns the ",(0,l.kt)("a",{parentName:"p",href:"/concepts/economics/consensus#bids"},"bids")," and ",(0,l.kt)("a",{parentName:"p",href:"/concepts/glossary/V#validator"},"validators")," as of either a specific Block (by height or hash). If you do not provide a ",(0,l.kt)("inlineCode",{parentName:"p"},"block_identifier"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"state_get_auction_info")," will return information from the most recent Block."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block identifier.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_auction_info request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "state_get_auction_info",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"state_get_auction_info_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"state_get_auction_info_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#auctionstate"},"auction_state")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The auction state.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_auction_info result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "auction_state": {\n "bids": [\n {\n "bid": {\n "bonding_purse": "uref-fafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafa-007",\n "delegation_rate": 0,\n "delegators": [],\n "inactive": false,\n "staked_amount": "10"\n },\n "public_key": "01197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61"\n }\n ],\n "block_height": 10,\n "era_validators": [\n {\n "era_id": 10,\n "validator_weights": [\n {\n "public_key": "01197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61",\n "weight": "10"\n }\n ]\n }\n ],\n "state_root_hash": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"\n }\n }\n}\n\n'))),(0,l.kt)("h2",{id:"info-get-validator-changes"},"info_get_validator_changes"),(0,l.kt)("p",null,"This method returns status changes of active validators. Listed changes occurred during the ",(0,l.kt)("inlineCode",{parentName:"p"},"EraId")," contained within the response itself. A validator may show more than one change in a single era."),(0,l.kt)("p",null,"Potential change types:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Change Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Added"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator has been added to the set.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Removed"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator has been removed from the set.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Banned"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator has been banned in the current era.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"CannotPropose"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator cannot propose a Block.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"SeenAsFaulty"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator has performed questionable activity.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_validator_changes request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "info_get_validator_changes",\n "params": []\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_validator_changes_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_validator_changes_result")),(0,l.kt)("p",null,"If no changes occurred in the current era, ",(0,l.kt)("inlineCode",{parentName:"p"},"info_get_validator_changes")," will return empty."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#jsonvalidatorchanges"},"changes")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The validators' status changes.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_validator_changes result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "changes": [\n {\n "public_key": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "status_changes": [\n {\n "era_id": 1,\n "validator_change": "Added"\n }\n ]\n }\n ]\n }\n}\n\n'))),(0,l.kt)("h2",{id:"chain_get_era_info_by_switch_block"},"chain_get_era_info_by_switch_block"),(0,l.kt)("p",null,"This method returns an EraInfo from the network. Only the last Block in an ",(0,l.kt)("inlineCode",{parentName:"p"},"era"),", known as a switch block, will contain an ",(0,l.kt)("inlineCode",{parentName:"p"},"era_summary"),"."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block identifier. If you do not supply a ",(0,l.kt)("inlineCode",{parentName:"td"},"block_identifier"),", the returned information will be the most recent Block. (Optional)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_era_info_by_switch_block request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "chain_get_era_info_by_switch_block",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_era_info_by_switch_block_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_era_info_by_switch_block_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#erasummary"},"era_summary")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The era summary (If found).")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_era_info_by_switch_block"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "era_summary": {\n "block_hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "era_id": 42,\n "merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3",\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",\n "stored_value": {\n "EraInfo": {\n "seigniorage_allocations": [\n {\n "Delegator": {\n "amount": "1000",\n "delegator_public_key": "01e1b46a25baa8a5c28beb3c9cfb79b572effa04076f00befa57eb70b016153f18",\n "validator_public_key": "012a1732addc639ea43a89e25d3ad912e40232156dcaa4b9edfc709f43d2fb0876"\n }\n },\n {\n "Validator": {\n "amount": "2000",\n "validator_public_key": "012a1732addc639ea43a89e25d3ad912e40232156dcaa4b9edfc709f43d2fb0876"\n }\n }\n ]\n }\n }\n }\n }\n}\n\n'))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8f925d60.a4d99eef.js b/assets/js/8f925d60.a4d99eef.js new file mode 100644 index 0000000000..54c0ae372f --- /dev/null +++ b/assets/js/8f925d60.a4d99eef.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4835],{3905:function(e,t,a){a.d(t,{Zo:function(){return s},kt:function(){return u}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),d=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},s=function(e){var t=d(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},b=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,c=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),p=d(a),b=r,u=p["".concat(c,".").concat(b)]||p[b]||f[b]||l;return a?n.createElement(u,o(o({ref:t},s),{},{components:a})):n.createElement(u,o({ref:t},s))}));function u(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,o=new Array(l);o[0]=b;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[p]="string"==typeof e?e:r,o[1]=i;for(var d=2;dstate_get_auction_info_result",id:"state_get_auction_info_result",level:3},{value:"info_get_validator_changes",id:"info-get-validator-changes",level:2},{value:"info_get_validator_changes_result",id:"info_get_validator_changes_result",level:3},{value:"chain_get_era_info_by_switch_block",id:"chain_get_era_info_by_switch_block",level:2},{value:"chain_get_era_info_by_switch_block_result",id:"chain_get_era_info_by_switch_block_result",level:3}],f={toc:p},b="wrapper";function u(e){var t=e.components,a=(0,r.Z)(e,o);return(0,l.kt)(b,(0,n.Z)({},f,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"proof-of-stake"},"Proof-of-Stake JSON-RPC Methods"),(0,l.kt)("p",null,"The following methods pertain to the Proof-of-Stake functionality of a Casper network. They return information related to auctions, bids and validators. This information is necessary for users involved with node operations and validation."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"state-get-auction-info"},"state_get_auction_info"),(0,l.kt)("p",null,"This method returns the ",(0,l.kt)("a",{parentName:"p",href:"/concepts/economics/consensus#bids"},"bids")," and ",(0,l.kt)("a",{parentName:"p",href:"/concepts/glossary/V#validator"},"validators")," as of either a specific Block (by height or hash). If you do not provide a ",(0,l.kt)("inlineCode",{parentName:"p"},"block_identifier"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"state_get_auction_info")," will return information from the most recent Block."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block identifier.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_auction_info request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "state_get_auction_info",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"state_get_auction_info_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"state_get_auction_info_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#auctionstate"},"auction_state")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The auction state.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example state_get_auction_info result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "auction_state": {\n "bids": [\n {\n "bid": {\n "bonding_purse": "uref-fafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafa-007",\n "delegation_rate": 0,\n "delegators": [],\n "inactive": false,\n "staked_amount": "10"\n },\n "public_key": "01197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61"\n }\n ],\n "block_height": 10,\n "era_validators": [\n {\n "era_id": 10,\n "validator_weights": [\n {\n "public_key": "01197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61",\n "weight": "10"\n }\n ]\n }\n ],\n "state_root_hash": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"\n }\n }\n}\n\n'))),(0,l.kt)("h2",{id:"info-get-validator-changes"},"info_get_validator_changes"),(0,l.kt)("p",null,"This method returns status changes of active validators. Listed changes occurred during the ",(0,l.kt)("inlineCode",{parentName:"p"},"EraId")," contained within the response itself. A validator may show more than one change in a single era."),(0,l.kt)("p",null,"Potential change types:"),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Change Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Added"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator has been added to the set.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Removed"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator has been removed from the set.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"Banned"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator has been banned in the current era.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"CannotPropose"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator cannot propose a Block.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"SeenAsFaulty"),(0,l.kt)("td",{parentName:"tr",align:null},"The validator has performed questionable activity.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_validator_changes request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "info_get_validator_changes",\n "params": []\n}\n\n'))),(0,l.kt)("h3",{id:"info_get_validator_changes_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"info_get_validator_changes_result")),(0,l.kt)("p",null,"If no changes occurred in the current era, ",(0,l.kt)("inlineCode",{parentName:"p"},"info_get_validator_changes")," will return empty."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#jsonvalidatorchanges"},"changes")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The validators' status changes.")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example info_get_validator_changes result"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "changes": [\n {\n "public_key": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",\n "status_changes": [\n {\n "era_id": 1,\n "validator_change": "Added"\n }\n ]\n }\n ]\n }\n}\n\n'))),(0,l.kt)("h2",{id:"chain_get_era_info_by_switch_block"},"chain_get_era_info_by_switch_block"),(0,l.kt)("p",null,"This method returns an EraInfo from the network. Only the last Block in an ",(0,l.kt)("inlineCode",{parentName:"p"},"era"),", known as a switch block, will contain an ",(0,l.kt)("inlineCode",{parentName:"p"},"era_summary"),"."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The Block identifier. If you do not supply a ",(0,l.kt)("inlineCode",{parentName:"td"},"block_identifier"),", the returned information will be the most recent Block. (Optional)")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_era_info_by_switch_block request"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "chain_get_era_info_by_switch_block",\n "params": [\n {\n "Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"\n }\n ]\n}\n\n'))),(0,l.kt)("h3",{id:"chain_get_era_info_by_switch_block_result"},(0,l.kt)("inlineCode",{parentName:"h3"},"chain_get_era_info_by_switch_block_result")),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,l.kt)("th",{parentName:"tr",align:null},"Type"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"api_version"),(0,l.kt)("td",{parentName:"tr",align:null},"String"),(0,l.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#erasummary"},"era_summary")),(0,l.kt)("td",{parentName:"tr",align:null},"Object"),(0,l.kt)("td",{parentName:"tr",align:null},"The era summary (If found).")))),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Example chain_get_era_info_by_switch_block"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "era_summary": {\n "block_hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",\n "era_id": 42,\n "merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3",\n "state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",\n "stored_value": {\n "EraInfo": {\n "seigniorage_allocations": [\n {\n "Delegator": {\n "amount": "1000",\n "delegator_public_key": "01e1b46a25baa8a5c28beb3c9cfb79b572effa04076f00befa57eb70b016153f18",\n "validator_public_key": "012a1732addc639ea43a89e25d3ad912e40232156dcaa4b9edfc709f43d2fb0876"\n }\n },\n {\n "Validator": {\n "amount": "2000",\n "validator_public_key": "012a1732addc639ea43a89e25d3ad912e40232156dcaa4b9edfc709f43d2fb0876"\n }\n }\n ]\n }\n }\n }\n }\n}\n\n'))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/92692c02.16df54f2.js b/assets/js/92692c02.16df54f2.js new file mode 100644 index 0000000000..28e35e2a89 --- /dev/null +++ b/assets/js/92692c02.16df54f2.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3065],{3905:function(e,t,a){a.d(t,{Zo:function(){return d},kt:function(){return h}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),c=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=c(a),p=r,h=u["".concat(s,".").concat(p)]||u[p]||g[p]||i;return a?n.createElement(h,o(o({ref:t},d),{},{components:a})):n.createElement(h,o({ref:t},d))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:r,o[1]=l;for(var c=2;cImportant Notes",id:"important-notes",level:3},{value:"Staking with a Validator",id:"2-staking",level:2},{value:"Connect and Login with Ledger",id:"connect-and-login-with-ledger",level:3},{value:"Receive Tokens from an External Source",id:"receive-tokens-from-an-external-source",level:3},{value:"Staking Tokens",id:"staking-tokens",level:3},{value:"Unstaking with a Validator",id:"3-unstaking",level:2},{value:"Initiate the Undelegation",id:"initiate-the-undelegation",level:3},{value:"Sign the Undelegation",id:"sign-the-undelegation",level:3}],p={toc:g},h="wrapper";function k(e){var t=e.components,a=(0,r.Z)(e,l);return(0,i.kt)(h,(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"delegating-with-ledger-devices"},"Delegating with Ledger Devices"),(0,i.kt)("h2",{id:"1-initialization"},"Ledger Initialization"),(0,i.kt)("p",null,"Before getting started, you need to complete two prerequisite steps:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Set up your Ledger device using the ",(0,i.kt)("a",{parentName:"li",href:"https://support.ledger.com/hc/en-us/articles/4416379141009-Casper-CSPR-?docs=true"},"official documentation"),"."),(0,i.kt)("li",{parentName:"ol"},"Connect the Ledger to your ",(0,i.kt)("a",{parentName:"li",href:"https://cspr.live/"},"cspr.live")," account by following the ",(0,i.kt)("a",{parentName:"li",href:"/workflow/ledger-setup/"},"Ledger Setup")," guide.")),(0,i.kt)("h3",{id:"important-notes"},(0,i.kt)("strong",{parentName:"h3"},"Important Notes")),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("span",{style:{color:"#ee5945"}},"CRITICAL")),": Write down and hide your recovery codes! These are necessary to be able to restore your account if you lose or damage the hardware key."),(0,i.kt)("li",{parentName:"ol"},"When logging in to ",(0,i.kt)("a",{parentName:"li",href:"https://cspr.live/"},"cspr.live"),", the UI will offer numerous public keys. Choose any of them. They are all derived from the Master Seed that is secured in the Ledger key (",(0,i.kt)("a",{parentName:"li",href:"https://www.ledger.com/academy/crypto/where-are-my-coins"},"more info here"),"). Make sure you write down whichever public key(s) you end up using so that you have no confusion when trying to log in.")),(0,i.kt)("h2",{id:"2-staking"},"Staking with a Validator"),(0,i.kt)("h3",{id:"connect-and-login-with-ledger"},"Connect and Login with Ledger"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Connect your Ledger to your computer via USB and enter your PIN to unlock it.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Open the Casper app on the Ledger (you will see the message "Casper Ready").'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger1.png"),alt:"Casper Ready",width:"400"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Sign in to ",(0,i.kt)("a",{parentName:"p",href:"https://cspr.live/"},"cspr.live"),' with your Ledger by clicking "Connect" under the Ledger option, as shown in the screenshot below.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger2.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Select the public key connected to your Ledger account."),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger3.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"View your account by clicking on your public key at the top right corner."),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger4.png"),alt:"Casper Ready",width:"800"}))),(0,i.kt)("h3",{id:"receive-tokens-from-an-external-source"},"Receive Tokens from an External Source"),(0,i.kt)("p",null,"This portion will vary slightly depending on where your funds are currently stored. However, the process will require that you send tokens to your public key as described in the ",(0,i.kt)("a",{parentName:"p",href:"/workflow/ledger-setup/#receive-tokens"},"documentation"),"."),(0,i.kt)("h3",{id:"staking-tokens"},"Staking Tokens"),(0,i.kt)("p",null,"Once you have tokens in your account, staking (delegating) with a validator is easy."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Go back to your account, but this time open the "delegate" tab located at: ',(0,i.kt)("a",{parentName:"p",href:"https://cspr.live/delegate-stake"},"https://cspr.live/delegate-stake")," (alternatively, click on ",(0,i.kt)("inlineCode",{parentName:"p"},"Wallet \u21d2 Delegate Stake")," to go there).")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"From the validator list, choose any validator you like. You will notice that validators charge different fees and have different amounts staked to them. This may inform your decision to choose the right validator for you.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Specify the amount you wish to stake or click "Delegate max" as shown below. Notes:'),(0,i.kt)("ol",{parentName:"li"},(0,i.kt)("li",{parentName:"ol"},"Remember that the total delegation amount to one validator cannot be less than 500 CSPR."),(0,i.kt)("li",{parentName:"ol"},"Both delegation and undelegation have an associated fee, so you need to leave some funds in your account to cover transaction fees. Otherwise, you may need to deposit additional funds to undelegate later."))),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Click "Next" to continue, as shown below.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger5.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'The page will update with a confirmation page asking you to verify all the details. If everything looks correct, click the "Confirm and delegate stake" button.')),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'You will be presented with a final page asking you to sign the transaction with Ledger. Click the "Sign with Ledger" button at the bottom.'),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Note"),': If you get an error showing a "Transaction rejected" message, make sure your Ledger device is active and connected to your computer. You may also need to re-enter your PIN if it locked itself due to inactivity.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger6.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'On the Ledger, you will see a message saying, "Please review". Click through the fields and verify everything matches what is being shown to you on ',(0,i.kt)("a",{parentName:"p",href:"https://cspr.live"},"cspr.live"),"."),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger7.png"),alt:"Casper Ready",width:"400"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Once you click "Approve", you will see the Delegation Completed screen verifying that your staking successfully was submitted to the blockchain.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger8.png"),alt:"Casper Ready",width:"400"})," ",(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger9.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'At this point, you can return to your account and wait until the completion of the era when the block gets included in the chain. Once the era completes, you will see that your liquid balance has decreased by your staked amount and is reflected in the "Staked As Delegator" row.'),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Note"),": If you staked your full balance, don't panic if you see a 0 CSPR balance whenever you log in! This is because it shows your liquid assets, not your total balance. You can go to your account details page, as shown below, to see your full balance and asset breakdown between liquid, staked, and undelegated tokens."),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger10.png"),alt:"Casper Ready",width:"800"}))),(0,i.kt)("h2",{id:"3-unstaking"},"Unstaking with a Validator"),(0,i.kt)("h3",{id:"initiate-the-undelegation"},"Initiate the Undelegation"),(0,i.kt)("p",null,'Now that you have funds delegated, you can liquidate them by undelegating them first. As demonstrated below, on your account\'s profile page, click "Undelegate" to get started.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger11.png"),alt:"Casper Ready",width:"800"}),(0,i.kt)("p",null,'The next page, "Undelegation details", will ask you how much you wish to undelegate. If you select "Undelegate max", it will attempt to liquidate all of your staked assets (minus the transaction fee). Once you enter a valid amount, the "Next" button will become clickable. Below you can see that I entered 313.02931 CSPR to be able to proceed.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger12.png"),alt:"Casper Ready",width:"800"}),(0,i.kt)("p",null,'You will next be shown a confirmation screen. If everything looks good, then click "Confirm and undelegate stake" to proceed.'),(0,i.kt)("h3",{id:"sign-the-undelegation"},"Sign the Undelegation"),(0,i.kt)("p",null,"You will have to sign the transaction to verify your account is initiating this action."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Connect your Ledger device to your computer.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Unlock your Ledger by entering your PIN.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Open the "Casper" app and ensure you see "Casper Ready".')),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Then back on ",(0,i.kt)("a",{parentName:"p",href:"https://cspr.live"},"cspr.live"),' click the "Sign with Ledger" button shown below.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger13.png"),alt:"Casper Ready",width:"800"}))),(0,i.kt)("p",null,'On your Ledger, you will see the transaction details. Verify all the information with what is being presented on the screen. If it looks good, then approve the transaction. If all goes according to plan, you will be presented with an "Undelegation completed!" screen.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger14.png"),alt:"Casper Ready",width:"800"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Note"),': There is a 7 era delay to undelegate. Era duration is approximately 120 minutes. While the funds go through undelegation, the balance will appear in the "Undelegation" row on your account profile page, as you can see below.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger15.png"),alt:"Casper Ready",width:"800"}),(0,i.kt)("p",null,"After the undelegation period completes, your funds will be liquid and available for you to re-stake, withdraw, or use however you wish."))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/92692c02.3a26c825.js b/assets/js/92692c02.3a26c825.js deleted file mode 100644 index 2dbccfc6db..0000000000 --- a/assets/js/92692c02.3a26c825.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3065],{3905:function(e,t,a){a.d(t,{Zo:function(){return d},kt:function(){return h}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),c=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=c(a),p=r,h=u["".concat(s,".").concat(p)]||u[p]||g[p]||i;return a?n.createElement(h,o(o({ref:t},d),{},{components:a})):n.createElement(h,o({ref:t},d))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:r,o[1]=l;for(var c=2;cImportant Notes",id:"important-notes",level:3},{value:"Staking with a Validator",id:"2-staking",level:2},{value:"Connect and Login with Ledger",id:"connect-and-login-with-ledger",level:3},{value:"Receive Tokens from an External Source",id:"receive-tokens-from-an-external-source",level:3},{value:"Staking Tokens",id:"staking-tokens",level:3},{value:"Unstaking with a Validator",id:"3-unstaking",level:2},{value:"Initiate the Undelegation",id:"initiate-the-undelegation",level:3},{value:"Sign the Undelegation",id:"sign-the-undelegation",level:3}],p={toc:g},h="wrapper";function k(e){var t=e.components,a=(0,r.Z)(e,l);return(0,i.kt)(h,(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"delegating-with-ledger-devices"},"Delegating with Ledger Devices"),(0,i.kt)("h2",{id:"1-initialization"},"Ledger Initialization"),(0,i.kt)("p",null,"Before getting started, you need to complete two prerequisite steps:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Set up your Ledger device using the ",(0,i.kt)("a",{parentName:"li",href:"https://support.ledger.com/hc/en-us/articles/4416379141009-Casper-CSPR-?docs=true"},"official documentation"),"."),(0,i.kt)("li",{parentName:"ol"},"Connect the Ledger to your ",(0,i.kt)("a",{parentName:"li",href:"https://cspr.live/"},"cspr.live")," account by following the ",(0,i.kt)("a",{parentName:"li",href:"/workflow/ledger-setup/"},"Ledger Setup")," guide.")),(0,i.kt)("h3",{id:"important-notes"},(0,i.kt)("strong",{parentName:"h3"},"Important Notes")),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("span",{style:{color:"#ee5945"}},"CRITICAL")),": Write down and hide your recovery codes! These are necessary to be able to restore your account if you lose or damage the hardware key."),(0,i.kt)("li",{parentName:"ol"},"When logging in to ",(0,i.kt)("a",{parentName:"li",href:"https://cspr.live/"},"cspr.live"),", the UI will offer numerous public keys. Choose any of them. They are all derived from the Master Seed that is secured in the Ledger key (",(0,i.kt)("a",{parentName:"li",href:"https://www.ledger.com/academy/crypto/where-are-my-coins"},"more info here"),"). Make sure you write down whichever public key(s) you end up using so that you have no confusion when trying to log in.")),(0,i.kt)("h2",{id:"2-staking"},"Staking with a Validator"),(0,i.kt)("h3",{id:"connect-and-login-with-ledger"},"Connect and Login with Ledger"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Connect your Ledger to your computer via USB and enter your PIN to unlock it.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Open the Casper app on the Ledger (you will see the message "Casper Ready").'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger1.png"),alt:"Casper Ready",width:"400"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Sign in to ",(0,i.kt)("a",{parentName:"p",href:"https://cspr.live/"},"cspr.live"),' with your Ledger by clicking "Connect" under the Ledger option, as shown in the screenshot below.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger2.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Select the public key connected to your Ledger account."),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger3.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"View your account by clicking on your public key at the top right corner."),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger4.png"),alt:"Casper Ready",width:"800"}))),(0,i.kt)("h3",{id:"receive-tokens-from-an-external-source"},"Receive Tokens from an External Source"),(0,i.kt)("p",null,"This portion will vary slightly depending on where your funds are currently stored. However, the process will require that you send tokens to your public key as described in the ",(0,i.kt)("a",{parentName:"p",href:"/workflow/ledger-setup/#receive-tokens"},"documentation"),"."),(0,i.kt)("h3",{id:"staking-tokens"},"Staking Tokens"),(0,i.kt)("p",null,"Once you have tokens in your account, staking (delegating) with a validator is easy."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Go back to your account, but this time open the "delegate" tab located at: ',(0,i.kt)("a",{parentName:"p",href:"https://cspr.live/delegate-stake"},"https://cspr.live/delegate-stake")," (alternatively, click on ",(0,i.kt)("inlineCode",{parentName:"p"},"Wallet \u21d2 Delegate Stake")," to go there).")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"From the validator list, choose any validator you like. You will notice that validators charge different fees and have different amounts staked to them. This may inform your decision to choose the right validator for you.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Specify the amount you wish to stake or click "Delegate max" as shown below. Notes:'),(0,i.kt)("ol",{parentName:"li"},(0,i.kt)("li",{parentName:"ol"},"Remember that the total delegation amount to one validator cannot be less than 500 CSPR."),(0,i.kt)("li",{parentName:"ol"},"Both delegation and undelegation have an associated fee, so you need to leave some funds in your account to cover transaction fees. Otherwise, you may need to deposit additional funds to undelegate later."))),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Click "Next" to continue, as shown below.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger5.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'The page will update with a confirmation page asking you to verify all the details. If everything looks correct, click the "Confirm and delegate stake" button.')),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'You will be presented with a final page asking you to sign the transaction with Ledger. Click the "Sign with Ledger" button at the bottom.'),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Note"),': If you get an error showing a "Transaction rejected" message, make sure your Ledger device is active and connected to your computer. You may also need to re-enter your PIN if it locked itself due to inactivity.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger6.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'On the Ledger, you will see a message saying, "Please review". Click through the fields and verify everything matches what is being shown to you on ',(0,i.kt)("a",{parentName:"p",href:"https://cspr.live"},"cspr.live"),"."),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger7.png"),alt:"Casper Ready",width:"400"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Once you click "Approve", you will see the Delegation Completed screen verifying that your staking successfully was submitted to the blockchain.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger8.png"),alt:"Casper Ready",width:"400"})," ",(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger9.png"),alt:"Casper Ready",width:"800"})),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'At this point, you can return to your account and wait until the completion of the era when the block gets included in the chain. Once the era completes, you will see that your liquid balance has decreased by your staked amount and is reflected in the "Staked As Delegator" row.'),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Note"),": If you staked your full balance, don't panic if you see a 0 CSPR balance whenever you log in! This is because it shows your liquid assets, not your total balance. You can go to your account details page, as shown below, to see your full balance and asset breakdown between liquid, staked, and undelegated tokens."),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger10.png"),alt:"Casper Ready",width:"800"}))),(0,i.kt)("h2",{id:"3-unstaking"},"Unstaking with a Validator"),(0,i.kt)("h3",{id:"initiate-the-undelegation"},"Initiate the Undelegation"),(0,i.kt)("p",null,'Now that you have funds delegated, you can liquidate them by undelegating them first. As demonstrated below, on your account\'s profile page, click "Undelegate" to get started.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger11.png"),alt:"Casper Ready",width:"800"}),(0,i.kt)("p",null,'The next page, "Undelegation details", will ask you how much you wish to undelegate. If you select "Undelegate max", it will attempt to liquidate all of your staked assets (minus the transaction fee). Once you enter a valid amount, the "Next" button will become clickable. Below you can see that I entered 313.02931 CSPR to be able to proceed.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger12.png"),alt:"Casper Ready",width:"800"}),(0,i.kt)("p",null,'You will next be shown a confirmation screen. If everything looks good, then click "Confirm and undelegate stake" to proceed.'),(0,i.kt)("h3",{id:"sign-the-undelegation"},"Sign the Undelegation"),(0,i.kt)("p",null,"You will have to sign the transaction to verify your account is initiating this action."),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Connect your Ledger device to your computer.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Unlock your Ledger by entering your PIN.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},'Open the "Casper" app and ensure you see "Casper Ready".')),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},"Then back on ",(0,i.kt)("a",{parentName:"p",href:"https://cspr.live"},"cspr.live"),' click the "Sign with Ledger" button shown below.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger13.png"),alt:"Casper Ready",width:"800"}))),(0,i.kt)("p",null,'On your Ledger, you will see the transaction details. Verify all the information with what is being presented on the screen. If it looks good, then approve the transaction. If all goes according to plan, you will be presented with an "Undelegation completed!" screen.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger14.png"),alt:"Casper Ready",width:"800"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Note"),': There is a 7 era delay to undelegate. Era duration is approximately 120 minutes. While the funds go through undelegation, the balance will appear in the "Undelegation" row on your account profile page, as you can see below.'),(0,i.kt)("img",{class:"align-center",src:(0,o.Z)("/image/tutorials/ledger/staking/ledger15.png"),alt:"Casper Ready",width:"800"}),(0,i.kt)("p",null,"After the undelegation period completes, your funds will be liquid and available for you to re-stake, withdraw, or use however you wish."))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/956d710b.8469ddd6.js b/assets/js/956d710b.8469ddd6.js deleted file mode 100644 index 37d8f24b43..0000000000 --- a/assets/js/956d710b.8469ddd6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8422],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return k}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),i=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=i(e.components);return a.createElement(p.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=i(n),d=r,k=c["".concat(p,".").concat(d)]||c[d]||m[d]||o;return n?a.createElement(k,l(l({ref:t},u),{},{components:n})):a.createElement(k,l({ref:t},u))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=d;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:r,l[1]=s;for(var i=2;i\n(env) $ git clone https://github.com/casper-network/casper-node-launcher\n")),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Assuming you have set up a small local network, you can speed up the process of creating new blocks with NCTL by reducing the ",(0,o.kt)("inlineCode",{parentName:"p"},"deploy_delay")," in your ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/resources/local/config.toml#L390"},"local config.toml")," before running ",(0,o.kt)("inlineCode",{parentName:"p"},"nctl-assets-setup"),".")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 11.")," Next, clone the ",(0,o.kt)("em",{parentName:"p"},"casper-node")," software, also in your working directory."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ git clone https://github.com/casper-network/casper-node\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 12.")," Finally, clone the ",(0,o.kt)("em",{parentName:"p"},"casper-client-rs")," software in your working directory."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ git clone https://github.com/casper-ecosystem/casper-client-rs\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 13.")," Activate the NCTL environment with the following command."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ source casper-node/utils/nctl/activate\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 14.")," Compile the NCTL binary scripts. The following command compiles both the ",(0,o.kt)("em",{parentName:"p"},"casper-node")," and the ",(0,o.kt)("em",{parentName:"p"},"casper-client")," in release mode."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ nctl-compile\n")),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"The compilation takes some time, so it might be a perfect moment to get some coffee.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 15.")," Set up all the assets required to run a local network, including binaries, chainspec, config, faucet, and keys. Also, spin up the network right after. The default network will have 10 nodes, with 5 active nodes and 5 inactive nodes."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ nctl-assets-setup && nctl-start\n")),(0,o.kt)("p",null,"Once a network is up and running, you can control each node within the network and add new nodes to the network."),(0,o.kt)("p",null,"Several other NCTL commands are available via aliases for execution from within a terminal session. All such commands are prefixed by ",(0,o.kt)("em",{parentName:"p"},"nctl-")," and allow you to perform various tasks."),(0,o.kt)("p",null,"You should see the new directory ",(0,o.kt)("em",{parentName:"p"},"utils/nctl/assets"),", with the following structure."),(0,o.kt)("img",{src:(0,l.Z)("/image/nctl/assets_setup.png"),alt:"assets_setup",width:"200"}),(0,o.kt)("p",null,"Here is the command line output you would expect."),(0,o.kt)("img",{src:(0,l.Z)("/image/nctl/nctl_output.png"),alt:"nctl_output"}),(0,o.kt)("h2",{id:"stopping-the-network"},"Stopping the Network"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 15.")," Although not necessary, you can stop and clean the NCTL setup with the following commands."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ nctl-stop\n(env) $ nctl-clean\n")),(0,o.kt)("h2",{id:"next-steps"},"Next Steps"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Explore the ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/master/utils/nctl/docs/commands.md"},"various NCTL commands"),"."),(0,o.kt)("li",{parentName:"ol"},"Explore the ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/master/utils/nctl/docs/usage.md"},"NCTL usage guide"),".")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/956d710b.ed13cd24.js b/assets/js/956d710b.ed13cd24.js new file mode 100644 index 0000000000..8fd2643349 --- /dev/null +++ b/assets/js/956d710b.ed13cd24.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8422],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return k}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),i=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=i(e.components);return a.createElement(p.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=i(n),d=r,k=c["".concat(p,".").concat(d)]||c[d]||m[d]||o;return n?a.createElement(k,l(l({ref:t},u),{},{components:n})):a.createElement(k,l({ref:t},u))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,l=new Array(o);l[0]=d;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:r,l[1]=s;for(var i=2;i\n(env) $ git clone https://github.com/casper-network/casper-node-launcher\n")),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Assuming you have set up a small local network, you can speed up the process of creating new blocks with NCTL by reducing the ",(0,o.kt)("inlineCode",{parentName:"p"},"deploy_delay")," in your ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/resources/local/config.toml#L390"},"local config.toml")," before running ",(0,o.kt)("inlineCode",{parentName:"p"},"nctl-assets-setup"),".")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 11.")," Next, clone the ",(0,o.kt)("em",{parentName:"p"},"casper-node")," software, also in your working directory."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ git clone https://github.com/casper-network/casper-node\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 12.")," Finally, clone the ",(0,o.kt)("em",{parentName:"p"},"casper-client-rs")," software in your working directory."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ git clone https://github.com/casper-ecosystem/casper-client-rs\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 13.")," Activate the NCTL environment with the following command."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ source casper-node/utils/nctl/activate\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 14.")," Compile the NCTL binary scripts. The following command compiles both the ",(0,o.kt)("em",{parentName:"p"},"casper-node")," and the ",(0,o.kt)("em",{parentName:"p"},"casper-client")," in release mode."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ nctl-compile\n")),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"The compilation takes some time, so it might be a perfect moment to get some coffee.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 15.")," Set up all the assets required to run a local network, including binaries, chainspec, config, faucet, and keys. Also, spin up the network right after. The default network will have 10 nodes, with 5 active nodes and 5 inactive nodes."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ nctl-assets-setup && nctl-start\n")),(0,o.kt)("p",null,"Once a network is up and running, you can control each node within the network and add new nodes to the network."),(0,o.kt)("p",null,"Several other NCTL commands are available via aliases for execution from within a terminal session. All such commands are prefixed by ",(0,o.kt)("em",{parentName:"p"},"nctl-")," and allow you to perform various tasks."),(0,o.kt)("p",null,"You should see the new directory ",(0,o.kt)("em",{parentName:"p"},"utils/nctl/assets"),", with the following structure."),(0,o.kt)("img",{src:(0,l.Z)("/image/nctl/assets_setup.png"),alt:"assets_setup",width:"200"}),(0,o.kt)("p",null,"Here is the command line output you would expect."),(0,o.kt)("img",{src:(0,l.Z)("/image/nctl/nctl_output.png"),alt:"nctl_output"}),(0,o.kt)("h2",{id:"stopping-the-network"},"Stopping the Network"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Step 15.")," Although not necessary, you can stop and clean the NCTL setup with the following commands."),(0,o.kt)("p",null,"Instructions for MacOS and Linux:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"(env) $ nctl-stop\n(env) $ nctl-clean\n")),(0,o.kt)("h2",{id:"next-steps"},"Next Steps"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Explore the ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/master/utils/nctl/docs/commands.md"},"various NCTL commands"),"."),(0,o.kt)("li",{parentName:"ol"},"Explore the ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/master/utils/nctl/docs/usage.md"},"NCTL usage guide"),".")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/963db545.25eb7fe6.js b/assets/js/963db545.25eb7fe6.js deleted file mode 100644 index 5569df3ab5..0000000000 --- a/assets/js/963db545.25eb7fe6.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9065],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return m}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=a.createContext({}),l=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return a.createElement(p.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=l(n),h=o,m=d["".concat(p,".").concat(h)]||d[h]||u[h]||r;return n?a.createElement(m,i(i({ref:t},c),{},{components:n})):a.createElement(m,i({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var l=2;l")," and will require you to define the path to your specific ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," Wasm.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"node address")," for a node on your NCTL network. In this example, we are using the node at ",(0,r.kt)("inlineCode",{parentName:"p"},"http://localhost:11101"),". On the Casper Mainnet or Testnet, nodes will use port ",(0,r.kt)("inlineCode",{parentName:"p"},"7777"),". This will appear in our example put-deploy as ",(0,r.kt)("inlineCode",{parentName:"p"},"--node-address http://:7777"),"."))),(0,r.kt)("p",null,"The command to send your ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," should look similar to the following code snippet:"),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Use of the ",(0,r.kt)("inlineCode",{parentName:"p"},"$(get_path_to_client)")," command assumes that you are operating in an activated NCTL envrionment.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'$(get_path_to_client) put-deploy \\\n--chain-name "casper-net-1" \\\n--secret-key /casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-path \\\n--node-address http://localhost:11101\n')),(0,r.kt)("p",null,"The response will return something similar to the following information. Note the ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n "id": 4824893960188648146,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "deploy_hash": "8e6309cc37bc58d8fedc1094ee1bd264a636d39fc0e05b5e1d72d98f7b6faf13"\n }\n}\n')),(0,r.kt)("h2",{id:"verifying-deploy-execution"},"Verifying Deploy Execution"),(0,r.kt)("p",null,"The previous command sent the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," to the NCTL network, but we recommend verifying deploy execution before continuing. The ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," received in the response allows you to query the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),"'s status."),(0,r.kt)("p",null,"To query the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),"'s status, you will pass both the ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," and the same ",(0,r.kt)("inlineCode",{parentName:"p"},"node-address")," from above using the following command. This will return either an error message in the event of failure or the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," details if it succeeds."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$(get_path_to_client) get-deploy 8e6309cc37bc58d8fedc1094ee1bd264a636d39fc0e05b5e1d72d98f7b6faf13 -n http://localhost:11101\n")),(0,r.kt)("h2",{id:"interacting-with-the-installed-contract"},"Interacting with the Installed Contract"),(0,r.kt)("p",null,"Once your NCTL network executes your ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),", you can test the functionality of the installed contract. To do so, you will first need to identify any arguments to pass to the contract, starting with the ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," itself. This hash identifies the contract and allows you to target the included entry points. As we used the pre-established node-1 account to ",(0,r.kt)("a",{parentName:"p",href:"/developers/cli/sending-deploys"},"send the ",(0,r.kt)("inlineCode",{parentName:"a"},"Deploy")),", we can retrieve the ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," from the node-1 account information. To do so, we will use the following command with a node address and the ",(0,r.kt)("inlineCode",{parentName:"p"},"PublicKey")," of the node in question."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$(get_path_to_client) get-account-info \\\n--node-address http://localhost:11101 \\\n--public-key /casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/public_key.pem\n")),(0,r.kt)("p",null,"This command will return information pertaining to the account, including the ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys"),". The ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," of the contract to be tested will appear here. The process of calling the contract is similar to that of installing it, as they are both accomplished through sending a ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),". In this instance, you will need the following information:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"node address"),", entered in this instance using ",(0,r.kt)("inlineCode",{parentName:"p"},"--node-address http://localhost:11101"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"chain name"),", entered in this instance using ",(0,r.kt)("inlineCode",{parentName:"p"},'--chain-name "casper-net-1"'))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"payment amount")," for this ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," in motes, which may need to be adjusted depending on cost and network ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". In this instance, we will use ",(0,r.kt)("inlineCode",{parentName:"p"},"--payment-amount 500000000"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"session path"),", defining the location of the Wasm bearing file for the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),". It appears in our example as ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-path ")," but you must define the path to your specific file.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Any ",(0,r.kt)("strong",{parentName:"p"},"session arguments")," specific to the contract that you are testing. Multiple instances of ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-arg")," may be used as necessary to provide values to the contract, including the ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," you acquired above. In the example below, you will see a demonstration of the ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," as a session argument as ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-arg \"contract_key:key='hash-8c13aaeef50ae7f447ee21276965c31cfa45c4ea3abb03d35d078cdd6a40e4a'\"")))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'$(get_path_to_client) put-deploy \\\n--node-address http://localhost:11101 \\\n--chain-name "casper-net-1" \\\n--payment-amount 500000000 \\\n--session-path \\\n--session-arg "contract_key:key=\'hash-8c13aaeef50ae7f447ee21276965c31cfa45c4ea3abb03d35d078cdd6a40e4a\'"\n')),(0,r.kt)("h2",{id:"verifying-correct-contract-behavior"},"Verifying Correct Contract Behavior"),(0,r.kt)("p",null,"After calling your installed contract, you can verify that the contract behaved as expected by observing the associated change in ",(0,r.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts#querying-global-state"},"global state"),". Depending on how your contract functions, this can have different meanings and results. If we use our donation contract from the ",(0,r.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract"},"basic smart contract tutorial"),", the NCTL process would have the following flow:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Send a ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),' to install the "Donation" smart contract.')),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Verify the execution of the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),".")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Interact with the installed contract using an additional ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," that calls one or several of the entry points. For example, calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"donate")," entry point to donate an amount to the fundraising purse.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Verify the associated change in global state. Namely, an increase in the balance of the fundraising purse."))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/963db545.f7c0fcf5.js b/assets/js/963db545.f7c0fcf5.js new file mode 100644 index 0000000000..a0e5b36e81 --- /dev/null +++ b/assets/js/963db545.f7c0fcf5.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9065],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return m}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=a.createContext({}),l=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return a.createElement(p.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=l(n),h=o,m=d["".concat(p,".").concat(h)]||d[h]||u[h]||r;return n?a.createElement(m,i(i({ref:t},c),{},{components:n})):a.createElement(m,i({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var l=2;l")," and will require you to define the path to your specific ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," Wasm.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"node address")," for a node on your NCTL network. In this example, we are using the node at ",(0,r.kt)("inlineCode",{parentName:"p"},"http://localhost:11101"),". On the Casper Mainnet or Testnet, nodes will use port ",(0,r.kt)("inlineCode",{parentName:"p"},"7777"),". This will appear in our example put-deploy as ",(0,r.kt)("inlineCode",{parentName:"p"},"--node-address http://:7777"),"."))),(0,r.kt)("p",null,"The command to send your ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," should look similar to the following code snippet:"),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Use of the ",(0,r.kt)("inlineCode",{parentName:"p"},"$(get_path_to_client)")," command assumes that you are operating in an activated NCTL envrionment.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'$(get_path_to_client) put-deploy \\\n--chain-name "casper-net-1" \\\n--secret-key /casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-path \\\n--node-address http://localhost:11101\n')),(0,r.kt)("p",null,"The response will return something similar to the following information. Note the ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n "id": 4824893960188648146,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "deploy_hash": "8e6309cc37bc58d8fedc1094ee1bd264a636d39fc0e05b5e1d72d98f7b6faf13"\n }\n}\n')),(0,r.kt)("h2",{id:"verifying-deploy-execution"},"Verifying Deploy Execution"),(0,r.kt)("p",null,"The previous command sent the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," to the NCTL network, but we recommend verifying deploy execution before continuing. The ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," received in the response allows you to query the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),"'s status."),(0,r.kt)("p",null,"To query the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),"'s status, you will pass both the ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," and the same ",(0,r.kt)("inlineCode",{parentName:"p"},"node-address")," from above using the following command. This will return either an error message in the event of failure or the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," details if it succeeds."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$(get_path_to_client) get-deploy 8e6309cc37bc58d8fedc1094ee1bd264a636d39fc0e05b5e1d72d98f7b6faf13 -n http://localhost:11101\n")),(0,r.kt)("h2",{id:"interacting-with-the-installed-contract"},"Interacting with the Installed Contract"),(0,r.kt)("p",null,"Once your NCTL network executes your ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),", you can test the functionality of the installed contract. To do so, you will first need to identify any arguments to pass to the contract, starting with the ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," itself. This hash identifies the contract and allows you to target the included entry points. As we used the pre-established node-1 account to ",(0,r.kt)("a",{parentName:"p",href:"/developers/cli/sending-deploys"},"send the ",(0,r.kt)("inlineCode",{parentName:"a"},"Deploy")),", we can retrieve the ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," from the node-1 account information. To do so, we will use the following command with a node address and the ",(0,r.kt)("inlineCode",{parentName:"p"},"PublicKey")," of the node in question."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"$(get_path_to_client) get-account-info \\\n--node-address http://localhost:11101 \\\n--public-key /casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/public_key.pem\n")),(0,r.kt)("p",null,"This command will return information pertaining to the account, including the ",(0,r.kt)("inlineCode",{parentName:"p"},"NamedKeys"),". The ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," of the contract to be tested will appear here. The process of calling the contract is similar to that of installing it, as they are both accomplished through sending a ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),". In this instance, you will need the following information:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"node address"),", entered in this instance using ",(0,r.kt)("inlineCode",{parentName:"p"},"--node-address http://localhost:11101"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"chain name"),", entered in this instance using ",(0,r.kt)("inlineCode",{parentName:"p"},'--chain-name "casper-net-1"'))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"payment amount")," for this ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," in motes, which may need to be adjusted depending on cost and network ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". In this instance, we will use ",(0,r.kt)("inlineCode",{parentName:"p"},"--payment-amount 500000000"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"The ",(0,r.kt)("strong",{parentName:"p"},"session path"),", defining the location of the Wasm bearing file for the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),". It appears in our example as ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-path ")," but you must define the path to your specific file.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},"Any ",(0,r.kt)("strong",{parentName:"p"},"session arguments")," specific to the contract that you are testing. Multiple instances of ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-arg")," may be used as necessary to provide values to the contract, including the ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," you acquired above. In the example below, you will see a demonstration of the ",(0,r.kt)("inlineCode",{parentName:"p"},"ContractHash")," as a session argument as ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-arg \"contract_key:key='hash-8c13aaeef50ae7f447ee21276965c31cfa45c4ea3abb03d35d078cdd6a40e4a'\"")))),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'$(get_path_to_client) put-deploy \\\n--node-address http://localhost:11101 \\\n--chain-name "casper-net-1" \\\n--payment-amount 500000000 \\\n--session-path \\\n--session-arg "contract_key:key=\'hash-8c13aaeef50ae7f447ee21276965c31cfa45c4ea3abb03d35d078cdd6a40e4a\'"\n')),(0,r.kt)("h2",{id:"verifying-correct-contract-behavior"},"Verifying Correct Contract Behavior"),(0,r.kt)("p",null,"After calling your installed contract, you can verify that the contract behaved as expected by observing the associated change in ",(0,r.kt)("a",{parentName:"p",href:"/developers/cli/installing-contracts#querying-global-state"},"global state"),". Depending on how your contract functions, this can have different meanings and results. If we use our donation contract from the ",(0,r.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract"},"basic smart contract tutorial"),", the NCTL process would have the following flow:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Send a ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),' to install the "Donation" smart contract.')),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Verify the execution of the ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy"),".")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Interact with the installed contract using an additional ",(0,r.kt)("inlineCode",{parentName:"p"},"Deploy")," that calls one or several of the entry points. For example, calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"donate")," entry point to donate an amount to the fundraising purse.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Verify the associated change in global state. Namely, an increase in the balance of the fundraising purse."))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9755a710.a7300428.js b/assets/js/9755a710.b1d3d828.js similarity index 74% rename from assets/js/9755a710.a7300428.js rename to assets/js/9755a710.b1d3d828.js index 814325664e..ef05b6206f 100644 --- a/assets/js/9755a710.a7300428.js +++ b/assets/js/9755a710.b1d3d828.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8996],{3905:function(e,t,r){r.d(t,{Zo:function(){return l},kt:function(){return f}});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=n.createContext({}),s=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=s(r),g=o,f=p["".concat(u,".").concat(g)]||p[g]||d[g]||i;return r?n.createElement(f,a(a({ref:t},l),{},{components:r})):n.createElement(f,a({ref:t},l))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=g;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var s=2;s=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=n.createContext({}),s=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=s(e.components);return n.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=s(r),g=o,f=p["".concat(u,".").concat(g)]||p[g]||d[g]||i;return r?n.createElement(f,a(a({ref:t},l),{},{components:r})):n.createElement(f,a({ref:t},l))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=g;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c[p]="string"==typeof e?e:o,a[1]=c;for(var s=2;s=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var i=a.createContext({}),l=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},p=function(e){var n=l(e.components);return a.createElement(i.Provider,{value:n},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,o=e.mdxType,s=e.originalType,i=e.parentName,p=r(e,["components","mdxType","originalType","parentName"]),u=l(t),h=o,m=u["".concat(i,".").concat(h)]||u[h]||d[h]||s;return t?a.createElement(m,c(c({ref:n},p),{},{components:t})):a.createElement(m,c({ref:n},p))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var s=t.length,c=new Array(s);c[0]=h;var r={};for(var i in n)hasOwnProperty.call(n,i)&&(r[i]=n[i]);r.originalType=e,r[u]="string"==typeof e?e:o,c[1]=r;for(var l=2;lcheck_balance_of Entry Point",id:"invoking-the-check_balance_of-entry-point",level:3},{value:"Approving an Allowance for Another Account",id:"approving-an-allowance-for-another-account",level:2},{value:"Approving an Account to Spend Tokens on Another Account's Behalf",id:"approving-an-account-to-spend-tokens-on-another-accounts-behalf",level:3},{value:"Verifying a Previously Issued Allowance",id:"verifying-a-previously-issued-allowance",level:3},{value:"Transferring Tokens from an Allowance",id:"transferring-tokens-from-an-allowance",level:3},{value:"Increasing and Decreasing an Allowance",id:"increasing-and-decreasing-an-allowance",level:3},{value:"Increasing an Allowance",id:"increasing-an-allowance",level:4},{value:"Decreasing an Allowance",id:"decreasing-an-allowance",level:4},{value:"Minting and Burning Additional CEP-18 Tokens",id:"minting-and-burning-additional-cep-18-tokens",level:3},{value:"Minting Additional Tokens",id:"minting-additional-tokens",level:4},{value:"Burning Tokens",id:"burning-tokens",level:4},{value:"Changing Account Security Permissions",id:"changing-account-security-permissions",level:3},{value:"Next Steps",id:"next-steps",level:3}],d={toc:u},h="wrapper";function m(e){var n=e.components,t=(0,o.Z)(e,c);return(0,s.kt)(h,(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"cep-18-token-transfers-and-allowances"},"CEP-18 Token Transfers and Allowances"),(0,s.kt)("p",null,"This document describes how to transfer CEP-18 tokens on a Casper network using the Casper client. The ",(0,s.kt)("a",{parentName:"p",href:"/resources/tokens/cep18/query"},"Exploring the CEP18 Contracts")," documentation contains more in depth explanations on how to find the various hashes and URefs referenced throughout this document."),(0,s.kt)("h2",{id:"transferring-cep-18-tokens-to-another-account"},"Transferring CEP-18 Tokens to Another Account"),(0,s.kt)("p",null,"The following command will invoke the ",(0,s.kt)("inlineCode",{parentName:"p"},"transfer")," entry point on your instance of CEP-18, directing it to transfer 10 of the associated CEP-18 tokens to another account."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://: \\\n// The chain name of the Casper network on which your CEP-18 instance was installed.\n--chain-name \\\n// The local path to your account\'s secret key.\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n// The contract hash of your CEP-18 contract instance.\n--session-hash hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180 \\\n// The name of the entry point you are invoking.\n--session-entry-point "transfer" \\\n// The account hash of the account that you are sending CEP-18 tokens to.\n--session-arg "recipient:key=\'account-hash-9f81014b9c7406c531ebf0477132283f4eb59143d7903a2fae54358b26cea44b" \\\n// The amount of CEP-18 tokens you are sending to the receiving account.\n--session-arg "amount:u256=\'10\'" \\\n// The gas payment you are allotting, in motes.\n--payment-amount "10000000000"\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-hash hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180 \\\n--session-entry-point "transfer" \\\n--session-arg "recipient:key=\'account-hash-9f81014b9c7406c531ebf0477132283f4eb59143d7903a2fae54358b26cea44b" \\\n--session-arg "amount:u256=\'50\'" \\\n--payment-amount "10000000000"\n'))),(0,s.kt)("p",null,"This command will return a deploy hash that you can query using ",(0,s.kt)("inlineCode",{parentName:"p"},"casper-client get-deploy"),". Querying the Deploy allows you to verify execution success, but you will need to use the ",(0,s.kt)("inlineCode",{parentName:"p"},"check_balance_of")," entry point on the utility contract to verify the account's balance."),(0,s.kt)("h3",{id:"invoking-the-check_balance_of-entry-point"},"Invoking the ",(0,s.kt)("inlineCode",{parentName:"h3"},"check_balance_of")," Entry Point"),(0,s.kt)("p",null,"The following Casper client command invokes the ",(0,s.kt)("inlineCode",{parentName:"p"},"check_balance_of")," entry point on the ",(0,s.kt)("inlineCode",{parentName:"p"},"cep18_test_contract"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://:\\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_test_contract" \\\n--session-entry-point "check_balance_of" \\\n// This is the contract hash of your CEP-18 contract instance, passed in as an `account-hash-`.\n--session-arg "token_contract:account_hash=\'account-hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180\'" \\\n// This is the account hash of the account you are checking the balance of.\n--session-arg "address:key=\'account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://:\\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_test_contract" \\\n--session-entry-point "check_balance_of" \\\n--session-arg "token_contract:account_hash=\'account-hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180\'" \\\n--session-arg "address:key=\'account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("p",null,"After sending this command, you will need to query the ",(0,s.kt)("inlineCode",{parentName:"p"},"results")," URef within the ",(0,s.kt)("inlineCode",{parentName:"p"},"NamedKeys")," of your ",(0,s.kt)("inlineCode",{parentName:"p"},"cep18_test_contract")," utility contract instance. More information on finding this URef can be found in the ",(0,s.kt)("a",{parentName:"p",href:"/resources/tokens/cep18/query#querying-the-utility-contract"},"Exploring the CEP18 Contracts")," document."),(0,s.kt)("p",null,"You can use the following command to query global state for the ",(0,s.kt)("inlineCode",{parentName:"p"},"results")," URef."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},"casper-client query-global-state -n http://: \\\n// This is the `results` URef location from your `cep18_test_contract` `NamedKeys`\n--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \\\n--state-root-hash 3aecd0e4b6ec29ee7c1eed701132eabfe6e66a1e0f1595c9c65bfed447e474f7\n")),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -n http://: \\\n--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \\\n--state-root-hash 3aecd0e4b6ec29ee7c1eed701132eabfe6e66a1e0f1595c9c65bfed447e474f7\n"))),(0,s.kt)("p",null,"This command should show something similar to the following in response, with ",(0,s.kt)("inlineCode",{parentName:"p"},"parsed")," being the amount of CEP-18 tokens that the account holds."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -8841145064950441692,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[3796 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "010a",\n "cl_type": "U256",\n "parsed": "10"\n }\n }\n }\n}\n')),(0,s.kt)("h2",{id:"approving-an-allowance-for-another-account"},"Approving an Allowance for Another Account"),(0,s.kt)("p",null,"The Casper fungible token contract features an ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," entry point that allows an account to delegate another account to spend a preset number of CEP-18 tokens from their balance."),(0,s.kt)("h3",{id:"approving-an-account-to-spend-tokens-on-another-accounts-behalf"},"Approving an Account to Spend Tokens on Another Account's Behalf"),(0,s.kt)("p",null,"The following command approves a third-party account to spend an ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," of 15 CEP-18 tokens from the balance of the account that sent the CEP-18 instance."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://:\\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n// This is the contract hash of the CEP-18 token contract.\n--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \\\n--session-entry-point "approve" \\\n// This is the account hash of the account that will receive an allowance from the balance of the account that sent the Deploy.\n--session-arg "spender:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n// This is the number of CEP-18 tokens included in the allowance.\n--session-arg "amount:u256=\'15\'" \\\n--payment-amount "10000000000"\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://:\\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \\\n--session-entry-point "approve" \\\n--session-arg "spender:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n--session-arg "amount:u256=\'15\'" \\\n--payment-amount "10000000000"\n'))),(0,s.kt)("h3",{id:"verifying-a-previously-issued-allowance"},"Verifying a Previously Issued Allowance"),(0,s.kt)("p",null,"After approving an account to spend an ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," of tokens, we can verify the allotted allowance by using the utility contract. The following command will write the ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," of the spender's account to the ",(0,s.kt)("inlineCode",{parentName:"p"},"result")," URef of in the utility contract's ",(0,s.kt)("inlineCode",{parentName:"p"},"NamedKeys"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://:\\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_test_contract" \\\n--session-entry-point "check_allowance_of" \\\n// This is the contract hash for the CEP-18 token.\n--session-arg "token_contract:account_hash=\'account-hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e\'" \\\n// This is the account hash for the account that owns the CEP-18 tokens.\n--session-arg "owner:key=\'account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2\'" \\\n// This is the account hash for the account previously authorized to spend an allowance of the owning account\'s CEP-18 tokens.\n--session-arg "spender:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n--chain-name \\\n--payment-amount 10000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://:\\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_test_contract" \\\n--session-entry-point "check_allowance_of" \\\n--session-arg "token_contract:account_hash=\'account-hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e\'" \\\n--session-arg "owner:key=\'account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2\'" \\\n--session-arg "spender:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n--chain-name \\\n--payment-amount 10000000000\n'))),(0,s.kt)("p",null,"The following command queries global state to return the value stored under the ",(0,s.kt)("inlineCode",{parentName:"p"},"result")," URef:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},"casper-client query-global-state -n http://: \\\n// This is the previously identified `result` URef from the utility contract's `NamedKeys`\n--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \\\n--state-root-hash e64f877f65df26db74300bb175c244d589bd88a23b91abf9ceb73ac5e65e90f1\n")),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -n http://: \\\n--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \\\n--state-root-hash e64f877f65df26db74300bb175c244d589bd88a23b91abf9ceb73ac5e65e90f1\n"))),(0,s.kt)("p",null,"You should get a response similar to the following:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -9142472925449984061,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[3796 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "010f",\n "cl_type": "U256",\n "parsed": "15"\n }\n }\n }\n}\n')),(0,s.kt)("h3",{id:"transferring-tokens-from-an-allowance"},"Transferring Tokens from an Allowance"),(0,s.kt)("p",null,"The following command allows an account to transfer CEP-18 tokens held by another account up to their approved ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://: \\\n--chain-name \\\n// This is the secret key for the account that is spending their `allowance` from another account\'s balance.\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n// This is the CEP-18 token contract.\n--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \\\n--session-entry-point "transfer_from" \\\n// This is the account hash of the account that holds the CEP-18 in their balance.\n--session-arg "owner:key=\'account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2\'" \\\n// This is the account hash of the account that will receive the transferred CEP-18 tokens.\n--session-arg "recipient:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n// This is the amount of tokens to be transferred. If this amount exceeds the `allowance` of the account sending the Deploy, it will fail.\n--session-arg "amount:u256=\'10\'" \\\n--payment-amount "10000000000"\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \\\n--session-entry-point "transfer_from" \\\n--session-arg "owner:key=\'account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2\'" \\\n--session-arg "recipient:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n--session-arg "amount:u256=\'10\'" \\\n--payment-amount "10000000000"\n'))),(0,s.kt)("h3",{id:"increasing-and-decreasing-an-allowance"},"Increasing and Decreasing an Allowance"),(0,s.kt)("h4",{id:"increasing-an-allowance"},"Increasing an Allowance"),(0,s.kt)("p",null,"The following command increases the designated ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," for the provided account."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "increase_allowance" \\\n// This is the account hash of the previously authorized allowance account.\n--session-arg "spender:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the additional number of CEP-18 tokens that the authorized account may spend.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "increase_allowance" \\\n--session-arg "spender:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("h4",{id:"decreasing-an-allowance"},"Decreasing an Allowance"),(0,s.kt)("p",null,"The following command decreases the designated allowance for the provided account."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "decrease_allowance" \\\n// This is the account hash of the previously authorized allowance account.\n--session-arg "spender:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the additional number of CEP-18 tokens that the authorized account may spend.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "decrease_allowance" \\\n--session-arg "spender:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("h3",{id:"minting-and-burning-additional-cep-18-tokens"},"Minting and Burning Additional CEP-18 Tokens"),(0,s.kt)("h4",{id:"minting-additional-tokens"},"Minting Additional Tokens"),(0,s.kt)("p",null,"If the contract allows for minting, the following command will mint a number of CEP-18 tokens directly to the provided account. This increases the total supply of the token in question."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "mint" \\\n// This is the account that will receive the newly minted CEP-18 tokens.\n--session-arg "owner:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the number of additional CEP-18 tokens to add to the total supply.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "mint" \\\n--session-arg "owner:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("h4",{id:"burning-tokens"},"Burning Tokens"),(0,s.kt)("p",null,"If the contract allows for burning, the following command will burn a number of CEP-18 tokens directly from the provided account. This decreases the total supply of the token in question."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "burn" \\\n// This is the account that the tokens will be burned from.\n--session-arg "owner:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the number of CEP-18 tokens to remove from the total supply.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "burn" \\\n// This is the account that the tokens will be burned from.\n--session-arg "owner:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the number of CEP-18 tokens to remove from the total supply.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("h3",{id:"changing-account-security-permissions"},"Changing Account Security Permissions"),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"change_security")," entrypoint can be used by an account with ",(0,s.kt)("inlineCode",{parentName:"p"},"admin")," access to alter the security level of other accounts."),(0,s.kt)("p",null,"There are five security levels, with the strongest level taking precedence over any other assigned levels. In order of highest strength to lowest:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"None")," - ",(0,s.kt)("inlineCode",{parentName:"p"},"None")," overrides other security levels and removes all admin, minting and burning access of an account.")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"Admin")," - Allows the account full access and control over the CEP-18 contract.")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"MintAndBurn")," - Allows the account to mint new tokens and burn existing tokens.")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"Burner")," - The account can burn tokens.")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"Minter")," - The account can mint new tokens."))),(0,s.kt)("p",null,"Here is an example of a ",(0,s.kt)("inlineCode",{parentName:"p"},"session-arg")," that provides a list of account hashes to be included on the ",(0,s.kt)("inlineCode",{parentName:"p"},"mint_and_burn_list"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"--session-arg \"mint_and_burn_list:string='account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7,account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34,account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655'\"\n")),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Be aware that removing all admin accounts will lock out all admin functionality.")),(0,s.kt)("p",null,"The following command can be supplied with any of the optional arguments above:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "change_security" \\\n/// The following arguments are all optional and each consists of a string of the account hashes to be added to the list specified, separated by commas.\n--session-arg "none_list:string:\'\'" \\\n--session-arg "admin_list:string:\'\'" \\\n--session-arg "mint_and_burn_list:string:\'\'" \\\n--session-arg "burner_list:string:\'\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("h3",{id:"next-steps"},"Next Steps"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/tests"},"Testing Framework for CEP-18"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9800de81.415f2370.js b/assets/js/9800de81.415f2370.js deleted file mode 100644 index 559aa1e863..0000000000 --- a/assets/js/9800de81.415f2370.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5477],{3905:function(e,n,t){t.d(n,{Zo:function(){return p},kt:function(){return m}});var a=t(7294);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function s(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function c(e){for(var n=1;n=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var i=a.createContext({}),l=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},p=function(e){var n=l(e.components);return a.createElement(i.Provider,{value:n},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,o=e.mdxType,s=e.originalType,i=e.parentName,p=r(e,["components","mdxType","originalType","parentName"]),u=l(t),h=o,m=u["".concat(i,".").concat(h)]||u[h]||d[h]||s;return t?a.createElement(m,c(c({ref:n},p),{},{components:t})):a.createElement(m,c({ref:n},p))}));function m(e,n){var t=arguments,o=n&&n.mdxType;if("string"==typeof e||o){var s=t.length,c=new Array(s);c[0]=h;var r={};for(var i in n)hasOwnProperty.call(n,i)&&(r[i]=n[i]);r.originalType=e,r[u]="string"==typeof e?e:o,c[1]=r;for(var l=2;lcheck_balance_of Entry Point",id:"invoking-the-check_balance_of-entry-point",level:3},{value:"Approving an Allowance for Another Account",id:"approving-an-allowance-for-another-account",level:2},{value:"Approving an Account to Spend Tokens on Another Account's Behalf",id:"approving-an-account-to-spend-tokens-on-another-accounts-behalf",level:3},{value:"Verifying a Previously Issued Allowance",id:"verifying-a-previously-issued-allowance",level:3},{value:"Transferring Tokens from an Allowance",id:"transferring-tokens-from-an-allowance",level:3},{value:"Increasing and Decreasing an Allowance",id:"increasing-and-decreasing-an-allowance",level:3},{value:"Increasing an Allowance",id:"increasing-an-allowance",level:4},{value:"Decreasing an Allowance",id:"decreasing-an-allowance",level:4},{value:"Minting and Burning Additional CEP-18 Tokens",id:"minting-and-burning-additional-cep-18-tokens",level:3},{value:"Minting Additional Tokens",id:"minting-additional-tokens",level:4},{value:"Burning Tokens",id:"burning-tokens",level:4},{value:"Changing Account Security Permissions",id:"changing-account-security-permissions",level:3},{value:"Next Steps",id:"next-steps",level:3}],d={toc:u},h="wrapper";function m(e){var n=e.components,t=(0,o.Z)(e,c);return(0,s.kt)(h,(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"cep-18-token-transfers-and-allowances"},"CEP-18 Token Transfers and Allowances"),(0,s.kt)("p",null,"This document describes how to transfer CEP-18 tokens on a Casper network using the Casper client. The ",(0,s.kt)("a",{parentName:"p",href:"/resources/tokens/cep18/query"},"Exploring the CEP18 Contracts")," documentation contains more in depth explanations on how to find the various hashes and URefs referenced throughout this document."),(0,s.kt)("h2",{id:"transferring-cep-18-tokens-to-another-account"},"Transferring CEP-18 Tokens to Another Account"),(0,s.kt)("p",null,"The following command will invoke the ",(0,s.kt)("inlineCode",{parentName:"p"},"transfer")," entry point on your instance of CEP-18, directing it to transfer 10 of the associated CEP-18 tokens to another account."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://: \\\n// The chain name of the Casper network on which your CEP-18 instance was installed.\n--chain-name \\\n// The local path to your account\'s secret key.\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n// The contract hash of your CEP-18 contract instance.\n--session-hash hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180 \\\n// The name of the entry point you are invoking.\n--session-entry-point "transfer" \\\n// The account hash of the account that you are sending CEP-18 tokens to.\n--session-arg "recipient:key=\'account-hash-9f81014b9c7406c531ebf0477132283f4eb59143d7903a2fae54358b26cea44b" \\\n// The amount of CEP-18 tokens you are sending to the receiving account.\n--session-arg "amount:u256=\'10\'" \\\n// The gas payment you are allotting, in motes.\n--payment-amount "10000000000"\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-hash hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180 \\\n--session-entry-point "transfer" \\\n--session-arg "recipient:key=\'account-hash-9f81014b9c7406c531ebf0477132283f4eb59143d7903a2fae54358b26cea44b" \\\n--session-arg "amount:u256=\'50\'" \\\n--payment-amount "10000000000"\n'))),(0,s.kt)("p",null,"This command will return a deploy hash that you can query using ",(0,s.kt)("inlineCode",{parentName:"p"},"casper-client get-deploy"),". Querying the Deploy allows you to verify execution success, but you will need to use the ",(0,s.kt)("inlineCode",{parentName:"p"},"check_balance_of")," entry point on the utility contract to verify the account's balance."),(0,s.kt)("h3",{id:"invoking-the-check_balance_of-entry-point"},"Invoking the ",(0,s.kt)("inlineCode",{parentName:"h3"},"check_balance_of")," Entry Point"),(0,s.kt)("p",null,"The following Casper client command invokes the ",(0,s.kt)("inlineCode",{parentName:"p"},"check_balance_of")," entry point on the ",(0,s.kt)("inlineCode",{parentName:"p"},"cep18_test_contract"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://:\\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_test_contract" \\\n--session-entry-point "check_balance_of" \\\n// This is the contract hash of your CEP-18 contract instance, passed in as an `account-hash-`.\n--session-arg "token_contract:account_hash=\'account-hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180\'" \\\n// This is the account hash of the account you are checking the balance of.\n--session-arg "address:key=\'account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://:\\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_test_contract" \\\n--session-entry-point "check_balance_of" \\\n--session-arg "token_contract:account_hash=\'account-hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180\'" \\\n--session-arg "address:key=\'account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("p",null,"After sending this command, you will need to query the ",(0,s.kt)("inlineCode",{parentName:"p"},"results")," URef within the ",(0,s.kt)("inlineCode",{parentName:"p"},"NamedKeys")," of your ",(0,s.kt)("inlineCode",{parentName:"p"},"cep18_test_contract")," utility contract instance. More information on finding this URef can be found in the ",(0,s.kt)("a",{parentName:"p",href:"/resources/tokens/cep18/query#querying-the-utility-contract"},"Exploring the CEP18 Contracts")," document."),(0,s.kt)("p",null,"You can use the following command to query global state for the ",(0,s.kt)("inlineCode",{parentName:"p"},"results")," URef."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},"casper-client query-global-state -n http://: \\\n// This is the `results` URef location from your `cep18_test_contract` `NamedKeys`\n--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \\\n--state-root-hash 3aecd0e4b6ec29ee7c1eed701132eabfe6e66a1e0f1595c9c65bfed447e474f7\n")),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -n http://: \\\n--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \\\n--state-root-hash 3aecd0e4b6ec29ee7c1eed701132eabfe6e66a1e0f1595c9c65bfed447e474f7\n"))),(0,s.kt)("p",null,"This command should show something similar to the following in response, with ",(0,s.kt)("inlineCode",{parentName:"p"},"parsed")," being the amount of CEP-18 tokens that the account holds."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -8841145064950441692,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[3796 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "010a",\n "cl_type": "U256",\n "parsed": "10"\n }\n }\n }\n}\n')),(0,s.kt)("h2",{id:"approving-an-allowance-for-another-account"},"Approving an Allowance for Another Account"),(0,s.kt)("p",null,"The Casper fungible token contract features an ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," entry point that allows an account to delegate another account to spend a preset number of CEP-18 tokens from their balance."),(0,s.kt)("h3",{id:"approving-an-account-to-spend-tokens-on-another-accounts-behalf"},"Approving an Account to Spend Tokens on Another Account's Behalf"),(0,s.kt)("p",null,"The following command approves a third-party account to spend an ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," of 15 CEP-18 tokens from the balance of the account that sent the CEP-18 instance."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://:\\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n// This is the contract hash of the CEP-18 token contract.\n--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \\\n--session-entry-point "approve" \\\n// This is the account hash of the account that will receive an allowance from the balance of the account that sent the Deploy.\n--session-arg "spender:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n// This is the number of CEP-18 tokens included in the allowance.\n--session-arg "amount:u256=\'15\'" \\\n--payment-amount "10000000000"\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://:\\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \\\n--session-entry-point "approve" \\\n--session-arg "spender:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n--session-arg "amount:u256=\'15\'" \\\n--payment-amount "10000000000"\n'))),(0,s.kt)("h3",{id:"verifying-a-previously-issued-allowance"},"Verifying a Previously Issued Allowance"),(0,s.kt)("p",null,"After approving an account to spend an ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," of tokens, we can verify the allotted allowance by using the utility contract. The following command will write the ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," of the spender's account to the ",(0,s.kt)("inlineCode",{parentName:"p"},"result")," URef of in the utility contract's ",(0,s.kt)("inlineCode",{parentName:"p"},"NamedKeys"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://:\\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_test_contract" \\\n--session-entry-point "check_allowance_of" \\\n// This is the contract hash for the CEP-18 token.\n--session-arg "token_contract:account_hash=\'account-hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e\'" \\\n// This is the account hash for the account that owns the CEP-18 tokens.\n--session-arg "owner:key=\'account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2\'" \\\n// This is the account hash for the account previously authorized to spend an allowance of the owning account\'s CEP-18 tokens.\n--session-arg "spender:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n--chain-name \\\n--payment-amount 10000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://:\\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_test_contract" \\\n--session-entry-point "check_allowance_of" \\\n--session-arg "token_contract:account_hash=\'account-hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e\'" \\\n--session-arg "owner:key=\'account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2\'" \\\n--session-arg "spender:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n--chain-name \\\n--payment-amount 10000000000\n'))),(0,s.kt)("p",null,"The following command queries global state to return the value stored under the ",(0,s.kt)("inlineCode",{parentName:"p"},"result")," URef:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},"casper-client query-global-state -n http://: \\\n// This is the previously identified `result` URef from the utility contract's `NamedKeys`\n--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \\\n--state-root-hash e64f877f65df26db74300bb175c244d589bd88a23b91abf9ceb73ac5e65e90f1\n")),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -n http://: \\\n--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \\\n--state-root-hash e64f877f65df26db74300bb175c244d589bd88a23b91abf9ceb73ac5e65e90f1\n"))),(0,s.kt)("p",null,"You should get a response similar to the following:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -9142472925449984061,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block_header": null,\n "merkle_proof": "[3796 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "010f",\n "cl_type": "U256",\n "parsed": "15"\n }\n }\n }\n}\n')),(0,s.kt)("h3",{id:"transferring-tokens-from-an-allowance"},"Transferring Tokens from an Allowance"),(0,s.kt)("p",null,"The following command allows an account to transfer CEP-18 tokens held by another account up to their approved ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-json"},'casper-client put-deploy -n http://: \\\n--chain-name \\\n// This is the secret key for the account that is spending their `allowance` from another account\'s balance.\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n// This is the CEP-18 token contract.\n--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \\\n--session-entry-point "transfer_from" \\\n// This is the account hash of the account that holds the CEP-18 in their balance.\n--session-arg "owner:key=\'account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2\'" \\\n// This is the account hash of the account that will receive the transferred CEP-18 tokens.\n--session-arg "recipient:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n// This is the amount of tokens to be transferred. If this amount exceeds the `allowance` of the account sending the Deploy, it will fail.\n--session-arg "amount:u256=\'10\'" \\\n--payment-amount "10000000000"\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--chain-name \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \\\n--session-entry-point "transfer_from" \\\n--session-arg "owner:key=\'account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2\'" \\\n--session-arg "recipient:key=\'account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513\'" \\\n--session-arg "amount:u256=\'10\'" \\\n--payment-amount "10000000000"\n'))),(0,s.kt)("h3",{id:"increasing-and-decreasing-an-allowance"},"Increasing and Decreasing an Allowance"),(0,s.kt)("h4",{id:"increasing-an-allowance"},"Increasing an Allowance"),(0,s.kt)("p",null,"The following command increases the designated ",(0,s.kt)("inlineCode",{parentName:"p"},"allowance")," for the provided account."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "increase_allowance" \\\n// This is the account hash of the previously authorized allowance account.\n--session-arg "spender:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the additional number of CEP-18 tokens that the authorized account may spend.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "increase_allowance" \\\n--session-arg "spender:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("h4",{id:"decreasing-an-allowance"},"Decreasing an Allowance"),(0,s.kt)("p",null,"The following command decreases the designated allowance for the provided account."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "decrease_allowance" \\\n// This is the account hash of the previously authorized allowance account.\n--session-arg "spender:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the additional number of CEP-18 tokens that the authorized account may spend.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "decrease_allowance" \\\n--session-arg "spender:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("h3",{id:"minting-and-burning-additional-cep-18-tokens"},"Minting and Burning Additional CEP-18 Tokens"),(0,s.kt)("h4",{id:"minting-additional-tokens"},"Minting Additional Tokens"),(0,s.kt)("p",null,"If the contract allows for minting, the following command will mint a number of CEP-18 tokens directly to the provided account. This increases the total supply of the token in question."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "mint" \\\n// This is the account that will receive the newly minted CEP-18 tokens.\n--session-arg "owner:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the number of additional CEP-18 tokens to add to the total supply.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "mint" \\\n--session-arg "owner:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("h4",{id:"burning-tokens"},"Burning Tokens"),(0,s.kt)("p",null,"If the contract allows for burning, the following command will burn a number of CEP-18 tokens directly from the provided account. This decreases the total supply of the token in question."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "burn" \\\n// This is the account that the tokens will be burned from.\n--session-arg "owner:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the number of CEP-18 tokens to remove from the total supply.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("details",null,(0,s.kt)("summary",null,(0,s.kt)("b",null,"Casper client command without comments")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "burn" \\\n// This is the account that the tokens will be burned from.\n--session-arg "owner:key=\'account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd\'" \\\n// This is the number of CEP-18 tokens to remove from the total supply.\n--session-arg "amount:U256=\'10\'" \\\n--chain-name \\\n--payment-amount 1000000000\n'))),(0,s.kt)("h3",{id:"changing-account-security-permissions"},"Changing Account Security Permissions"),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"change_security")," entrypoint can be used by an account with ",(0,s.kt)("inlineCode",{parentName:"p"},"admin")," access to alter the security level of other accounts."),(0,s.kt)("p",null,"There are five security levels, with the strongest level taking precedence over any other assigned levels. In order of highest strength to lowest:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"None")," - ",(0,s.kt)("inlineCode",{parentName:"p"},"None")," overrides other security levels and removes all admin, minting and burning access of an account.")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"Admin")," - Allows the account full access and control over the CEP-18 contract.")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"MintAndBurn")," - Allows the account to mint new tokens and burn existing tokens.")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"Burner")," - The account can burn tokens.")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("inlineCode",{parentName:"p"},"Minter")," - The account can mint new tokens."))),(0,s.kt)("p",null,"Here is an example of a ",(0,s.kt)("inlineCode",{parentName:"p"},"session-arg")," that provides a list of account hashes to be included on the ",(0,s.kt)("inlineCode",{parentName:"p"},"mint_and_burn_list"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"--session-arg \"mint_and_burn_list:string='account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7,account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34,account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655'\"\n")),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Be aware that removing all admin accounts will lock out all admin functionality.")),(0,s.kt)("p",null,"The following command can be supplied with any of the optional arguments above:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://: \\\n--secret-key ~/casper/demo/user_a/secret_key.pem \\\n--session-package-name "cep18_contract_package_CEP18" \\\n--session-entry-point "change_security" \\\n/// The following arguments are all optional and each consists of a string of the account hashes to be added to the list specified, separated by commas.\n--session-arg "none_list:string:\'\'" \\\n--session-arg "admin_list:string:\'\'" \\\n--session-arg "mint_and_burn_list:string:\'\'" \\\n--session-arg "burner_list:string:\'\'" \\\n--chain-name \\\n--payment-amount 1000000000\n')),(0,s.kt)("h3",{id:"next-steps"},"Next Steps"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("a",{parentName:"li",href:"/resources/tokens/cep18/tests"},"Testing Framework for CEP-18"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/99756d1f.c3953897.js b/assets/js/99756d1f.c3953897.js deleted file mode 100644 index 81fe432584..0000000000 --- a/assets/js/99756d1f.c3953897.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8669],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return f}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),d=l(n),m=a,f=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return n?r.createElement(f,i(i({ref:t},c),{},{components:n})):r.createElement(f,i({ref:t},c))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[d]="string"==typeof e?e:a,i[1]=p;for(var l=2;l/rpc-schema\n")),(0,o.kt)("p",null,"To see an example, navigate to a node's RPC schema using a browser."),(0,o.kt)("p",null,"The Casper client subcommand ",(0,o.kt)("inlineCode",{parentName:"p"},"list-rpcs")," provides all currently supported RPCs. Here is an example of running the Casper client to list RPCs:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-sh"},"casper-client list-rpcs --node-address \n")),(0,o.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Page"),(0,o.kt)("th",{parentName:"tr",align:null},"Description"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/guidance"},"Guidance for JSON-RPC SDK Compliance")),(0,o.kt)("td",{parentName:"tr",align:null},"Requirements for a compliant Casper SDK")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/minimal-compliance"},"Required JSON-RPC Methods for Minimal Compliance")),(0,o.kt)("td",{parentName:"tr",align:null},"Methods required for a minimally compliant Casper SDK")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/json-rpc-transactional"},"Transactional JSON-RPC Method")),(0,o.kt)("td",{parentName:"tr",align:null},"Methods allowing interaction with a Casper network")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/json-rpc-informational"},"Informational JSON-RPC Methods")),(0,o.kt)("td",{parentName:"tr",align:null},"Methods returning information about the network from a Casper node")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/json-rpc-pos"},"Proof-of-Stake JSON-RPC Methods")),(0,o.kt)("td",{parentName:"tr",align:null},"Methods pertaining to Proof-of-Stake functionality on a Casper network")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain"},"Types")),(0,o.kt)("td",{parentName:"tr",align:null},"Information on types used within JSON-RPC methods")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_cl"},"CL Types")),(0,o.kt)("td",{parentName:"tr",align:null},"Information related to CL Types")))))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/99756d1f.d2ce0dcd.js b/assets/js/99756d1f.d2ce0dcd.js new file mode 100644 index 0000000000..2c751ba0a9 --- /dev/null +++ b/assets/js/99756d1f.d2ce0dcd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8669],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return f}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),l=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=l(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),d=l(n),m=a,f=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return n?r.createElement(f,i(i({ref:t},c),{},{components:n})):r.createElement(f,i({ref:t},c))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[d]="string"==typeof e?e:a,i[1]=p;for(var l=2;l/rpc-schema\n")),(0,o.kt)("p",null,"To see an example, navigate to a node's RPC schema using a browser."),(0,o.kt)("p",null,"The Casper client subcommand ",(0,o.kt)("inlineCode",{parentName:"p"},"list-rpcs")," provides all currently supported RPCs. Here is an example of running the Casper client to list RPCs:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-sh"},"casper-client list-rpcs --node-address \n")),(0,o.kt)("h2",{id:"table-of-contents"},"Table of Contents"),(0,o.kt)("table",null,(0,o.kt)("thead",{parentName:"table"},(0,o.kt)("tr",{parentName:"thead"},(0,o.kt)("th",{parentName:"tr",align:null},"Page"),(0,o.kt)("th",{parentName:"tr",align:null},"Description"))),(0,o.kt)("tbody",{parentName:"table"},(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/guidance"},"Guidance for JSON-RPC SDK Compliance")),(0,o.kt)("td",{parentName:"tr",align:null},"Requirements for a compliant Casper SDK")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/minimal-compliance"},"Required JSON-RPC Methods for Minimal Compliance")),(0,o.kt)("td",{parentName:"tr",align:null},"Methods required for a minimally compliant Casper SDK")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/json-rpc-transactional"},"Transactional JSON-RPC Method")),(0,o.kt)("td",{parentName:"tr",align:null},"Methods allowing interaction with a Casper network")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/json-rpc-informational"},"Informational JSON-RPC Methods")),(0,o.kt)("td",{parentName:"tr",align:null},"Methods returning information about the network from a Casper node")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/json-rpc-pos"},"Proof-of-Stake JSON-RPC Methods")),(0,o.kt)("td",{parentName:"tr",align:null},"Methods pertaining to Proof-of-Stake functionality on a Casper network")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain"},"Types")),(0,o.kt)("td",{parentName:"tr",align:null},"Information on types used within JSON-RPC methods")),(0,o.kt)("tr",{parentName:"tbody"},(0,o.kt)("td",{parentName:"tr",align:null},(0,o.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_cl"},"CL Types")),(0,o.kt)("td",{parentName:"tr",align:null},"Information related to CL Types")))))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9ae83eb2.19122969.js b/assets/js/9ae83eb2.19122969.js new file mode 100644 index 0000000000..0ddd1faf2a --- /dev/null +++ b/assets/js/9ae83eb2.19122969.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5240],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return h}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(n),m=i,h=c["".concat(s,".").concat(m)]||c[m]||u[m]||o;return n?a.createElement(h,r(r({ref:t},d),{},{components:n})):a.createElement(h,r({ref:t},d))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,r[1]=l;for(var p=2;p/usr/bin/",id:"usrbin",level:3},{value:"/etc/casper/",id:"etccasper",level:3},{value:"/var/lib/casper/",id:"varlibcasper",level:3},{value:"Node Version Installation",id:"node-version-installation",level:2},{value:"The Node Configuration File",id:"config-file",level:2},{value:"The Trusted Hash for Synchronizing",id:"trusted-hash-for-synchronizing",level:3},{value:"Known Addresses",id:"known-addresses",level:3},{value:"Updating the config.toml file",id:"updating-config-file",level:3},{value:"Secret Keys",id:"secret-keys",level:3},{value:"Networking and Gossiping",id:"networking--gossiping",level:3},{value:"Enabling Speculative Execution",id:"enabling-speculative-execution",level:3},{value:"Example Config.toml configuration with speculative execution enabled",id:"example-configtoml-configuration-with-speculative-execution-enabled",level:4},{value:"Rust Client Installation",id:"client-installation",level:2},{value:"Creating Keys and Funding Accounts",id:"create-fund-keys",level:2}],u={toc:c},m="wrapper";function h(e){var t=e.components,n=(0,i.Z)(e,r);return(0,o.kt)(m,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"basic-node-configuration"},"Basic Node Configuration"),(0,o.kt)("p",null,"This page outlines the processes and files involved in setting up a Casper node. For step-by-step node installation instructions, follow the ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup/install-node"},"Node Setup")," guide."),(0,o.kt)("h2",{id:"casper-node-launcher"},"The Casper Node Launcher"),(0,o.kt)("p",null,"A node is usually run by executing the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher"),", which executes the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," as a child process and also handles upgrades to bring the node to the latest version released."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," can be installed via a Debian package, which also creates the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper")," user and directory structures and sets up a ",(0,o.kt)("inlineCode",{parentName:"p"},"systemd")," unit and logging."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," Debian package can be obtained from ",(0,o.kt)("a",{parentName:"p",href:"https://repo.casperlabs.io"},"https://repo.casperlabs.io"),". You only need to run the steps detailed there once."),(0,o.kt)("p",null,"Then, proceed to install the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," by running these commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt update\nsudo apt install casper-node-launcher\n")),(0,o.kt)("p",null,"You can also build ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node-launcher"},"from source"),". However, all the setup and pull of casper-node releases will be manual."),(0,o.kt)("h2",{id:"file-locations"},"File Locations"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," Debian installation creates the directories and files needed to run ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," versions and perform upgrades. A ",(0,o.kt)("inlineCode",{parentName:"p"},"casper")," user and ",(0,o.kt)("inlineCode",{parentName:"p"},"casper")," group are created during installation and used to run the software. Two main folders are relevant for our software: ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"/var/lib/casper"),"."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"The casper-node install version")),(0,o.kt)("p",null,"Each version of the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," install is located based on the semantic version with underscores. For example, version 1.0.3 is represented by a directory named ",(0,o.kt)("inlineCode",{parentName:"p"},"1_0_3"),". This convention applies to both binary and configuration file locations. Versioning with ",(0,o.kt)("inlineCode",{parentName:"p"},"[m_n_p]")," represents the major, minor, and patch of a semantic version."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Multiple versioned folders will exist on a system when upgrades are set up.")),(0,o.kt)("p",null,"The following is the filesystem's state after installing the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," Debian packages, and after running the command ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo -u casper /etc/casper/node_util.py stage_protocols casper.conf")," (Use casper-test.conf if on Testnet)."),(0,o.kt)("h3",{id:"usrbin"},(0,o.kt)("inlineCode",{parentName:"h3"},"/usr/bin/")),(0,o.kt)("p",null,"The default location for executables from the Debian package install is ",(0,o.kt)("inlineCode",{parentName:"p"},"/usr/bin"),"."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-client")," - A client for interacting with a Casper network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-node-launcher")," - The launcher application which starts the ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-node")," as a child process")),(0,o.kt)("h3",{id:"etccasper"},(0,o.kt)("inlineCode",{parentName:"h3"},"/etc/casper/")),(0,o.kt)("p",null,"This is the default location for configuration files. It can be overwritten with the ",(0,o.kt)("inlineCode",{parentName:"p"},"CASPER_CONFIG_DIR")," environment variable. The paths in this document assume the default configuration file location of ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper"),". The data is organized as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"delete_local_db.sh")," - Removes ",(0,o.kt)("inlineCode",{parentName:"li"},"*.lmdb*")," files from ",(0,o.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/casper-node")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"pull_casper_node_version.sh")," - Pulls ",(0,o.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," and ",(0,o.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," from ",(0,o.kt)("a",{parentName:"li",href:"https://genesis.casperlabs.io/"},"genesis.casperlabs.io")," for a specified protocol version and extracts them into ",(0,o.kt)("inlineCode",{parentName:"li"},"/var/lib/bin/")," and ",(0,o.kt)("inlineCode",{parentName:"li"},"/etc/casper/")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config_from_example.sh")," - Gets external IP to replace and create the ",(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," from ",(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node_util.py")," - A script that will be replacing other scripts and is the preferred method of performing the actions of ",(0,o.kt)("inlineCode",{parentName:"li"},"pull_casper_node_version.sh"),", ",(0,o.kt)("inlineCode",{parentName:"li"},"config_from_example.sh"),", and ",(0,o.kt)("inlineCode",{parentName:"li"},"delete_local_db.sh"),". Other scripts will be deprecated in future releases of ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-node-launcher"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-node-launcher-state.toml")," - The local state for the ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-node-launcher")," which is created during the first run"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"validator_keys/")," - The default folder for node keys, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"README.md")," - Instructions on how to create validator keys using the ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-client")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"secret_key.pem")," - Secret key used by the validator node to sign blocks and peer-to-peer messages"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key.pem")," - Public key associated with the secret key above, stored in PEM format"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key_hex")," - Public key associated with the secret key above, stored in hex format"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/")," - Folder for genesis configuration files, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"accounts.toml")," - Contains the genesis validators and delegators"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"chainspec.toml")," - Contains invariant network settings, with the ",(0,o.kt)("inlineCode",{parentName:"li"},"activation_point")," (network start time) as a timestamp"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml")," - Example for creating a ",(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," file"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," - Contains variable node configuration settings, created by a node operator manually or by running ",(0,o.kt)("inlineCode",{parentName:"li"},"config_from_example.sh 1_0_0")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"m_n_p/")," - Folder for each installed upgrade package's configuration files, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"chainspec.toml")," - Contains invariant network settings, with the ",(0,o.kt)("inlineCode",{parentName:"li"},"activation_point")," as an era ID (the era at which this protocol version of the node became or will become active)"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml")," - As per ",(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/config-example.toml"),", but compatible with the ",(0,o.kt)("inlineCode",{parentName:"li"},"m.n.p")," version of the node"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," - As per ",(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/config.toml"),", but compatible with the ",(0,o.kt)("inlineCode",{parentName:"li"},"m.n.p")," version of the node")))),(0,o.kt)("h3",{id:"varlibcasper"},(0,o.kt)("inlineCode",{parentName:"h3"},"/var/lib/casper/")),(0,o.kt)("p",null,"This is the location for larger and variable data for the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node"),", organized in the following folders and files:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"bin/")," - The parent folder storing the versions of ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," executables. This location can be overwritten with the ",(0,o.kt)("inlineCode",{parentName:"p"},"CASPER_BIN_DIR")," environment variable. The paths in this document assume the default of ",(0,o.kt)("inlineCode",{parentName:"p"},"/var/lib/casper/bin/"),"."),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/")," - Folder for genesis binary files, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-node")," - The node executable - defaults to the Ubuntu 20.04 compatible binary"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"README.md")," - Information about the repository location and the Git hash used for compilation to allow a rebuild on other platforms"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"m_n_p/")," - Folder for each installed upgrade package, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-node")," - As per ",(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/casper-node"),", but the ",(0,o.kt)("inlineCode",{parentName:"li"},"m.n.p")," version of the node"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"README.md")," - As per ",(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/README.md"),", but compatible with the ",(0,o.kt)("inlineCode",{parentName:"li"},"m.n.p")," version of the node"))))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"casper-node/")," - Folder containing databases and related files produced by the node binary. For Mainnet, the network name is ",(0,o.kt)("inlineCode",{parentName:"p"},"casper")," and for Testnet it is ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-test"),"."),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"data.lmdb")," - Persistent global state store of the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"data.lmbd-lock")," - Lockfile for the ",(0,o.kt)("inlineCode",{parentName:"li"},"data.lmdb")," database"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"storage.lmdb")," - Persistent store of all other network data, primarily Blocks and Deploys"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"storage.lmdb-lock")," - Lockfile for the ",(0,o.kt)("inlineCode",{parentName:"li"},"storage.lmdb")," database"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"unit_files/")," - Folder containing transient caches of consensus information")))),(0,o.kt)("h2",{id:"node-version-installation"},"Node Version Installation"),(0,o.kt)("p",null,"Included with the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," is ",(0,o.kt)("inlineCode",{parentName:"p"},"node_util.py")," for installing ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," versions. This command will stage all current ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," versions:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols \n")),(0,o.kt)("p",null,"For ",(0,o.kt)("inlineCode",{parentName:"p"},""),", we use ",(0,o.kt)("inlineCode",{parentName:"p"},"casper.conf")," for Mainnet and ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-test.conf")," for Testnet. This will install all currently released protocols in one step."),(0,o.kt)("p",null,"This command will do the following:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Create ",(0,o.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/bin/1_0_2/")," and expand the ",(0,o.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," containing at a minimum ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-node")),(0,o.kt)("li",{parentName:"ul"},"Create ",(0,o.kt)("inlineCode",{parentName:"li"},"/etc/casper/1_0_2/")," and expand the ",(0,o.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," containing ",(0,o.kt)("inlineCode",{parentName:"li"},"chainspec.toml"),", ",(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml"),", and possibly ",(0,o.kt)("inlineCode",{parentName:"li"},"accounts.csv")," and other files"),(0,o.kt)("li",{parentName:"ul"},"Remove the archive files and run ",(0,o.kt)("inlineCode",{parentName:"li"},"/etc/casper/config_from_example.sh 1_0_2")," to create a ",(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," from the ",(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml"))),(0,o.kt)("p",null,"Release versions are invoked using the underscore format, such as:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/pull_casper_node_version.sh 1_0_2\n")),(0,o.kt)("h2",{id:"config-file"},"The Node Configuration File"),(0,o.kt)("p",null,"One ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," file exists for each ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," version installed. It is located in the ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper/[m_n_p]/")," directory, where ",(0,o.kt)("inlineCode",{parentName:"p"},"m_n_p")," is the current semantic version. This can be created from the ",(0,o.kt)("inlineCode",{parentName:"p"},"config-example.toml")," by using ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper/config_from_example.sh [m_n_p]")," where ",(0,o.kt)("inlineCode",{parentName:"p"},"[m_n_p]")," is replaced with the current version, using underscores."),(0,o.kt)("p",null,"Below are some fields in the ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," that you may need to adjust."),(0,o.kt)("h3",{id:"trusted-hash-for-synchronizing"},"The Trusted Hash for Synchronizing"),(0,o.kt)("p",null,"Each Casper network is a permissionless, Proof-of-Stake network, implying that nodes can join and leave the network. As a result, some nodes may not be synchronized or as secure as bonded validators. Ideally, all nodes will join the network using a trusted source, such as a bonded validator."),(0,o.kt)("p",null,"When joining the network, the system will start from the hash of a recent block and then work backward to obtain the finalized blocks from the linear block store. Here is the process to get the trusted hash of a bonded validator:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Find a list of trusted validators"),(0,o.kt)("li",{parentName:"ul"},"Query the status endpoint of a trusted validator (",(0,o.kt)("inlineCode",{parentName:"li"},"http://:8888/status"),")"),(0,o.kt)("li",{parentName:"ul"},"Obtain the hash of a block from the status endpoint"),(0,o.kt)("li",{parentName:"ul"},"Update the ",(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," for the node to include the trusted hash. There is a field dedicated to this near the top of the file")),(0,o.kt)("p",null,"Here is an example command for obtaining a trusted hash. Replace the node address with an updated address from a node on the network."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo sed -i \"/trusted_hash =/c\\trusted_hash = '$(casper-client get-block --node-address http://3.14.161.135:7777 -b 20 | jq -r .result.block.hash | tr -d '\\n')'\" /etc/casper/1_0_0/config.toml\n")),(0,o.kt)("h3",{id:"known-addresses"},"Known Addresses"),(0,o.kt)("p",null,"For the node to connect to a network, the node needs a set of trusted peers for that network. For ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"Mainnet"),", these are listed in the ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," as ",(0,o.kt)("inlineCode",{parentName:"p"},"known_addresses"),". For other networks, locate and update the list to include at least two trusted IP addresses for peers in that network. Here is an ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-protocol-release/blob/main/config/config-example.toml"},"example configuration"),". The ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-protocol-release"},"casper-protocol-release")," repository stores configurations for various environments, which you can also use as examples."),(0,o.kt)("h3",{id:"updating-config-file"},"Updating the ",(0,o.kt)("inlineCode",{parentName:"h3"},"config.toml")," file"),(0,o.kt)("p",null,"At the top of a ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," file as shown here, enter the trusted block hash to replace the ",(0,o.kt)("inlineCode",{parentName:"p"},"'HEX-FORMATTED BLOCK HASH'")," and uncomment the line by deleting the leading '#'. See the ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup/basic-node-configuration#config-file"},"Configuration File")," for more details."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"# ================================\n# Configuration options for a node\n# ================================\n[node]\n\n# If set, use this hash as a trust anchor when joining an existing network.\n#trusted_hash = 'HEX-FORMATTED BLOCK HASH'\n")),(0,o.kt)("h3",{id:"secret-keys"},"Secret Keys"),(0,o.kt)("p",null,"Provide the path to the secret keys for the node. This path is set to ",(0,o.kt)("inlineCode",{parentName:"p"},"etc/casper/validator_keys/")," by default. See ",(0,o.kt)("a",{parentName:"p",href:"#create-fund-keys"},"Creating Keys and Funding Accounts")," for more details."),(0,o.kt)("h3",{id:"networking--gossiping"},"Networking and Gossiping"),(0,o.kt)("p",null,"The node requires a publicly accessible IP address. The ",(0,o.kt)("inlineCode",{parentName:"p"},"config_from_example.sh")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"node_util.py")," both allow IP for network address translation (NAT) setup. Specify the public IP address of the node. If you use the ",(0,o.kt)("inlineCode",{parentName:"p"},"config_from_example.sh")," external services are called to find your IP and this is inserted into the ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," created."),(0,o.kt)("p",null,"The following default values are specified in the file if you want to change them:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"The port that will be used for status and deploys"),(0,o.kt)("li",{parentName:"ul"},"The port used for networking"),(0,o.kt)("li",{parentName:"ul"},"Known_addresses - these are the bootstrap nodes (there is no need to change these)")),(0,o.kt)("h3",{id:"enabling-speculative-execution"},"Enabling Speculative Execution"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"speculative_exec")," endpoint provides a method to execute a Deploy without committing its execution effects to global state. This can be used by developers to roughly estimate the gas costs of sending the Deploy in question. By default, ",(0,o.kt)("inlineCode",{parentName:"p"},"speculative_exec")," is disabled on a node."),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"speculative_exec")," can be enabled within ",(0,o.kt)("em",{parentName:"p"},"config.toml")," by changing ",(0,o.kt)("inlineCode",{parentName:"p"},"enable_server")," to ",(0,o.kt)("inlineCode",{parentName:"p"},"true")," under the configuration options for the speculative execution JSON-RPC HTTP server."),(0,o.kt)("p",null,"Node operators may also change the incoming request port for speculative execution, which defaults to ",(0,o.kt)("inlineCode",{parentName:"p"},"7778"),". Further, you can choose to alter the ",(0,o.kt)("inlineCode",{parentName:"p"},"qps_limit")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"max_body_bytes"),", which limit the amount and size of requests to the speculative execution server."),(0,o.kt)("h4",{id:"example-configtoml-configuration-with-speculative-execution-enabled"},"Example Config.toml configuration with speculative execution enabled"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"# ========================================================================\n# Configuration options for the speculative execution JSON-RPC HTTP server\n# ========================================================================\n[speculative_exec_server]\n\n# Flag which enables the speculative execution JSON-RPC HTTP server.\nenable_server = true\n\n# Listening address for speculative execution JSON-RPC HTTP server. If the port\n# is set to 0, a random port will be used.\n#\n# If the specified port cannot be bound to, a random port will be tried instead.\n# If binding fails, the speculative execution JSON-RPC HTTP server will not run,\n# but the node will be otherwise unaffected.\n#\n# The actual bound address will be reported via a log line if logging is enabled.\naddress = '0.0.0.0:7778'\n\n# The global max rate of requests (per second) before they are limited.\n# Request will be delayed to the next 1 second bucket once limited.\nqps_limit = 1\n\n# Maximum number of bytes to accept in a single request body.\nmax_body_bytes = 2_621_440\n\n# Specifies which origin will be reported as allowed by speculative execution server.\n#\n# If left empty, CORS will be disabled.\n# If set to '*', any origin is allowed.\n# Otherwise, only a specified origin is allowed. The given string must conform to the [origin scheme](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin).\ncors_origin = ''\n\n")),(0,o.kt)("h2",{id:"client-installation"},"Rust Client Installation"),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#the-casper-command-line-client"},"Prerequisites")," page lists installation instructions for the Casper client, which is useful for generating keys and retrieving information from the network."),(0,o.kt)("h2",{id:"create-fund-keys"},"Creating Keys and Funding Accounts"),(0,o.kt)("p",null,"The following command will create keys in the ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper/validator_keys")," folder."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client keygen /etc/casper/validator_keys\n")),(0,o.kt)("p",null,"To learn about other options for generating keys, see ",(0,o.kt)("a",{parentName:"p",href:"/concepts/accounts-and-keys"},"Accounts and Cryptographic Keys")," or run the Rust client ",(0,o.kt)("inlineCode",{parentName:"p"},"keygen")," command with the ",(0,o.kt)("inlineCode",{parentName:"p"},"--help")," option."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client keygen --help\n")),(0,o.kt)("p",null,"More about keys and key generation can also be found in ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper/validator_keys/README.md")," if the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," was installed from the Debian package."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Save your keys in a secure location, preferably offline.")),(0,o.kt)("p",null,"To submit a bonding request, you will need to ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#fund-your-account"},"fund your account")," as well."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9ae83eb2.4df50365.js b/assets/js/9ae83eb2.4df50365.js deleted file mode 100644 index 990c00aeee..0000000000 --- a/assets/js/9ae83eb2.4df50365.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5240],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return h}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(n),m=i,h=c["".concat(s,".").concat(m)]||c[m]||u[m]||o;return n?a.createElement(h,r(r({ref:t},d),{},{components:n})):a.createElement(h,r({ref:t},d))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,r[1]=l;for(var p=2;p/usr/bin/",id:"usrbin",level:3},{value:"/etc/casper/",id:"etccasper",level:3},{value:"/var/lib/casper/",id:"varlibcasper",level:3},{value:"Node Version Installation",id:"node-version-installation",level:2},{value:"The Node Configuration File",id:"config-file",level:2},{value:"The Trusted Hash for Synchronizing",id:"trusted-hash-for-synchronizing",level:3},{value:"Known Addresses",id:"known-addresses",level:3},{value:"Updating the config.toml file",id:"updating-config-file",level:3},{value:"Secret Keys",id:"secret-keys",level:3},{value:"Networking and Gossiping",id:"networking--gossiping",level:3},{value:"Enabling Speculative Execution",id:"enabling-speculative-execution",level:3},{value:"Example Config.toml configuration with speculative execution enabled",id:"example-configtoml-configuration-with-speculative-execution-enabled",level:4},{value:"Rust Client Installation",id:"client-installation",level:2},{value:"Creating Keys and Funding Accounts",id:"create-fund-keys",level:2}],u={toc:c},m="wrapper";function h(e){var t=e.components,n=(0,i.Z)(e,r);return(0,o.kt)(m,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"basic-node-configuration"},"Basic Node Configuration"),(0,o.kt)("p",null,"This page outlines the processes and files involved in setting up a Casper node. For step-by-step node installation instructions, follow the ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup/install-node"},"Node Setup")," guide."),(0,o.kt)("h2",{id:"casper-node-launcher"},"The Casper Node Launcher"),(0,o.kt)("p",null,"A node is usually run by executing the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher"),", which executes the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," as a child process and also handles upgrades to bring the node to the latest version released."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," can be installed via a Debian package, which also creates the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper")," user and directory structures and sets up a ",(0,o.kt)("inlineCode",{parentName:"p"},"systemd")," unit and logging."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," Debian package can be obtained from ",(0,o.kt)("a",{parentName:"p",href:"https://repo.casperlabs.io"},"https://repo.casperlabs.io"),". You only need to run the steps detailed there once."),(0,o.kt)("p",null,"Then, proceed to install the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," by running these commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt update\nsudo apt install casper-node-launcher\n")),(0,o.kt)("p",null,"You can also build ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node-launcher"},"from source"),". However, all the setup and pull of casper-node releases will be manual."),(0,o.kt)("h2",{id:"file-locations"},"File Locations"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," Debian installation creates the directories and files needed to run ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," versions and perform upgrades. A ",(0,o.kt)("inlineCode",{parentName:"p"},"casper")," user and ",(0,o.kt)("inlineCode",{parentName:"p"},"casper")," group are created during installation and used to run the software. Two main folders are relevant for our software: ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"/var/lib/casper"),"."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"The casper-node install version")),(0,o.kt)("p",null,"Each version of the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," install is located based on the semantic version with underscores. For example, version 1.0.3 is represented by a directory named ",(0,o.kt)("inlineCode",{parentName:"p"},"1_0_3"),". This convention applies to both binary and configuration file locations. Versioning with ",(0,o.kt)("inlineCode",{parentName:"p"},"[m_n_p]")," represents the major, minor, and patch of a semantic version."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Multiple versioned folders will exist on a system when upgrades are set up.")),(0,o.kt)("p",null,"The following is the filesystem's state after installing the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," Debian packages, and after running the command ",(0,o.kt)("inlineCode",{parentName:"p"},"sudo -u casper /etc/casper/node_util.py stage_protocols casper.conf")," (Use casper-test.conf if on Testnet)."),(0,o.kt)("h3",{id:"usrbin"},(0,o.kt)("inlineCode",{parentName:"h3"},"/usr/bin/")),(0,o.kt)("p",null,"The default location for executables from the Debian package install is ",(0,o.kt)("inlineCode",{parentName:"p"},"/usr/bin"),"."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-client")," - A client for interacting with a Casper network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-node-launcher")," - The launcher application which starts the ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-node")," as a child process")),(0,o.kt)("h3",{id:"etccasper"},(0,o.kt)("inlineCode",{parentName:"h3"},"/etc/casper/")),(0,o.kt)("p",null,"This is the default location for configuration files. It can be overwritten with the ",(0,o.kt)("inlineCode",{parentName:"p"},"CASPER_CONFIG_DIR")," environment variable. The paths in this document assume the default configuration file location of ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper"),". The data is organized as follows:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"delete_local_db.sh")," - Removes ",(0,o.kt)("inlineCode",{parentName:"li"},"*.lmdb*")," files from ",(0,o.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/casper-node")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"pull_casper_node_version.sh")," - Pulls ",(0,o.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," and ",(0,o.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," from ",(0,o.kt)("a",{parentName:"li",href:"https://genesis.casperlabs.io/"},"genesis.casperlabs.io")," for a specified protocol version and extracts them into ",(0,o.kt)("inlineCode",{parentName:"li"},"/var/lib/bin/")," and ",(0,o.kt)("inlineCode",{parentName:"li"},"/etc/casper/")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config_from_example.sh")," - Gets external IP to replace and create the ",(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," from ",(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node_util.py")," - A script that will be replacing other scripts and is the preferred method of performing the actions of ",(0,o.kt)("inlineCode",{parentName:"li"},"pull_casper_node_version.sh"),", ",(0,o.kt)("inlineCode",{parentName:"li"},"config_from_example.sh"),", and ",(0,o.kt)("inlineCode",{parentName:"li"},"delete_local_db.sh"),". Other scripts will be deprecated in future releases of ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-node-launcher"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-node-launcher-state.toml")," - The local state for the ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-node-launcher")," which is created during the first run"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"validator_keys/")," - The default folder for node keys, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"README.md")," - Instructions on how to create validator keys using the ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-client")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"secret_key.pem")," - Secret key used by the validator node to sign blocks and peer-to-peer messages"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key.pem")," - Public key associated with the secret key above, stored in PEM format"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key_hex")," - Public key associated with the secret key above, stored in hex format"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/")," - Folder for genesis configuration files, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"accounts.toml")," - Contains the genesis validators and delegators"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"chainspec.toml")," - Contains invariant network settings, with the ",(0,o.kt)("inlineCode",{parentName:"li"},"activation_point")," (network start time) as a timestamp"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml")," - Example for creating a ",(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," file"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," - Contains variable node configuration settings, created by a node operator manually or by running ",(0,o.kt)("inlineCode",{parentName:"li"},"config_from_example.sh 1_0_0")))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"m_n_p/")," - Folder for each installed upgrade package's configuration files, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"chainspec.toml")," - Contains invariant network settings, with the ",(0,o.kt)("inlineCode",{parentName:"li"},"activation_point")," as an era ID (the era at which this protocol version of the node became or will become active)"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml")," - As per ",(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/config-example.toml"),", but compatible with the ",(0,o.kt)("inlineCode",{parentName:"li"},"m.n.p")," version of the node"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," - As per ",(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/config.toml"),", but compatible with the ",(0,o.kt)("inlineCode",{parentName:"li"},"m.n.p")," version of the node")))),(0,o.kt)("h3",{id:"varlibcasper"},(0,o.kt)("inlineCode",{parentName:"h3"},"/var/lib/casper/")),(0,o.kt)("p",null,"This is the location for larger and variable data for the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node"),", organized in the following folders and files:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"bin/")," - The parent folder storing the versions of ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," executables. This location can be overwritten with the ",(0,o.kt)("inlineCode",{parentName:"p"},"CASPER_BIN_DIR")," environment variable. The paths in this document assume the default of ",(0,o.kt)("inlineCode",{parentName:"p"},"/var/lib/casper/bin/"),"."),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/")," - Folder for genesis binary files, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-node")," - The node executable - defaults to the Ubuntu 20.04 compatible binary"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"README.md")," - Information about the repository location and the Git hash used for compilation to allow a rebuild on other platforms"))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"m_n_p/")," - Folder for each installed upgrade package, containing:",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"casper-node")," - As per ",(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/casper-node"),", but the ",(0,o.kt)("inlineCode",{parentName:"li"},"m.n.p")," version of the node"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"README.md")," - As per ",(0,o.kt)("inlineCode",{parentName:"li"},"1_0_0/README.md"),", but compatible with the ",(0,o.kt)("inlineCode",{parentName:"li"},"m.n.p")," version of the node"))))),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("inlineCode",{parentName:"p"},"casper-node/")," - Folder containing databases and related files produced by the node binary. For Mainnet, the network name is ",(0,o.kt)("inlineCode",{parentName:"p"},"casper")," and for Testnet it is ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-test"),"."),(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"data.lmdb")," - Persistent global state store of the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"data.lmbd-lock")," - Lockfile for the ",(0,o.kt)("inlineCode",{parentName:"li"},"data.lmdb")," database"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"storage.lmdb")," - Persistent store of all other network data, primarily Blocks and Deploys"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"storage.lmdb-lock")," - Lockfile for the ",(0,o.kt)("inlineCode",{parentName:"li"},"storage.lmdb")," database"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"unit_files/")," - Folder containing transient caches of consensus information")))),(0,o.kt)("h2",{id:"node-version-installation"},"Node Version Installation"),(0,o.kt)("p",null,"Included with the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," is ",(0,o.kt)("inlineCode",{parentName:"p"},"node_util.py")," for installing ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," versions. This command will stage all current ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," versions:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/node_util.py stage_protocols \n")),(0,o.kt)("p",null,"For ",(0,o.kt)("inlineCode",{parentName:"p"},""),", we use ",(0,o.kt)("inlineCode",{parentName:"p"},"casper.conf")," for Mainnet and ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-test.conf")," for Testnet. This will install all currently released protocols in one step."),(0,o.kt)("p",null,"This command will do the following:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Create ",(0,o.kt)("inlineCode",{parentName:"li"},"/var/lib/casper/bin/1_0_2/")," and expand the ",(0,o.kt)("inlineCode",{parentName:"li"},"bin.tar.gz")," containing at a minimum ",(0,o.kt)("inlineCode",{parentName:"li"},"casper-node")),(0,o.kt)("li",{parentName:"ul"},"Create ",(0,o.kt)("inlineCode",{parentName:"li"},"/etc/casper/1_0_2/")," and expand the ",(0,o.kt)("inlineCode",{parentName:"li"},"config.tar.gz")," containing ",(0,o.kt)("inlineCode",{parentName:"li"},"chainspec.toml"),", ",(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml"),", and possibly ",(0,o.kt)("inlineCode",{parentName:"li"},"accounts.csv")," and other files"),(0,o.kt)("li",{parentName:"ul"},"Remove the archive files and run ",(0,o.kt)("inlineCode",{parentName:"li"},"/etc/casper/config_from_example.sh 1_0_2")," to create a ",(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," from the ",(0,o.kt)("inlineCode",{parentName:"li"},"config-example.toml"))),(0,o.kt)("p",null,"Release versions are invoked using the underscore format, such as:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper /etc/casper/pull_casper_node_version.sh 1_0_2\n")),(0,o.kt)("h2",{id:"config-file"},"The Node Configuration File"),(0,o.kt)("p",null,"One ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," file exists for each ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," version installed. It is located in the ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper/[m_n_p]/")," directory, where ",(0,o.kt)("inlineCode",{parentName:"p"},"m_n_p")," is the current semantic version. This can be created from the ",(0,o.kt)("inlineCode",{parentName:"p"},"config-example.toml")," by using ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper/config_from_example.sh [m_n_p]")," where ",(0,o.kt)("inlineCode",{parentName:"p"},"[m_n_p]")," is replaced with the current version, using underscores."),(0,o.kt)("p",null,"Below are some fields in the ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," that you may need to adjust."),(0,o.kt)("h3",{id:"trusted-hash-for-synchronizing"},"The Trusted Hash for Synchronizing"),(0,o.kt)("p",null,"Each Casper network is a permissionless, Proof-of-Stake network, implying that nodes can join and leave the network. As a result, some nodes may not be synchronized or as secure as bonded validators. Ideally, all nodes will join the network using a trusted source, such as a bonded validator."),(0,o.kt)("p",null,"When joining the network, the system will start from the hash of a recent block and then work backward to obtain the finalized blocks from the linear block store. Here is the process to get the trusted hash of a bonded validator:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Find a list of trusted validators"),(0,o.kt)("li",{parentName:"ul"},"Query the status endpoint of a trusted validator (",(0,o.kt)("inlineCode",{parentName:"li"},"http://:8888/status"),")"),(0,o.kt)("li",{parentName:"ul"},"Obtain the hash of a block from the status endpoint"),(0,o.kt)("li",{parentName:"ul"},"Update the ",(0,o.kt)("inlineCode",{parentName:"li"},"config.toml")," for the node to include the trusted hash. There is a field dedicated to this near the top of the file")),(0,o.kt)("p",null,"Here is an example command for obtaining a trusted hash. Replace the node address with an updated address from a node on the network."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo sed -i \"/trusted_hash =/c\\trusted_hash = '$(casper-client get-block --node-address http://3.14.161.135:7777 -b 20 | jq -r .result.block.hash | tr -d '\\n')'\" /etc/casper/1_0_0/config.toml\n")),(0,o.kt)("h3",{id:"known-addresses"},"Known Addresses"),(0,o.kt)("p",null,"For the node to connect to a network, the node needs a set of trusted peers for that network. For ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"Mainnet"),", these are listed in the ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," as ",(0,o.kt)("inlineCode",{parentName:"p"},"known_addresses"),". For other networks, locate and update the list to include at least two trusted IP addresses for peers in that network. Here is an ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-protocol-release/blob/main/config/config-example.toml"},"example configuration"),". The ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-protocol-release"},"casper-protocol-release")," repository stores configurations for various environments, which you can also use as examples."),(0,o.kt)("h3",{id:"updating-config-file"},"Updating the ",(0,o.kt)("inlineCode",{parentName:"h3"},"config.toml")," file"),(0,o.kt)("p",null,"At the top of a ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," file as shown here, enter the trusted block hash to replace the ",(0,o.kt)("inlineCode",{parentName:"p"},"'HEX-FORMATTED BLOCK HASH'")," and uncomment the line by deleting the leading '#'. See the ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup/basic-node-configuration#config-file"},"Configuration File")," for more details."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"# ================================\n# Configuration options for a node\n# ================================\n[node]\n\n# If set, use this hash as a trust anchor when joining an existing network.\n#trusted_hash = 'HEX-FORMATTED BLOCK HASH'\n")),(0,o.kt)("h3",{id:"secret-keys"},"Secret Keys"),(0,o.kt)("p",null,"Provide the path to the secret keys for the node. This path is set to ",(0,o.kt)("inlineCode",{parentName:"p"},"etc/casper/validator_keys/")," by default. See ",(0,o.kt)("a",{parentName:"p",href:"#create-fund-keys"},"Creating Keys and Funding Accounts")," for more details."),(0,o.kt)("h3",{id:"networking--gossiping"},"Networking and Gossiping"),(0,o.kt)("p",null,"The node requires a publicly accessible IP address. The ",(0,o.kt)("inlineCode",{parentName:"p"},"config_from_example.sh")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"node_util.py")," both allow IP for network address translation (NAT) setup. Specify the public IP address of the node. If you use the ",(0,o.kt)("inlineCode",{parentName:"p"},"config_from_example.sh")," external services are called to find your IP and this is inserted into the ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," created."),(0,o.kt)("p",null,"The following default values are specified in the file if you want to change them:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"The port that will be used for status and deploys"),(0,o.kt)("li",{parentName:"ul"},"The port used for networking"),(0,o.kt)("li",{parentName:"ul"},"Known_addresses - these are the bootstrap nodes (there is no need to change these)")),(0,o.kt)("h3",{id:"enabling-speculative-execution"},"Enabling Speculative Execution"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"speculative_exec")," endpoint provides a method to execute a Deploy without committing its execution effects to global state. This can be used by developers to roughly estimate the gas costs of sending the Deploy in question. By default, ",(0,o.kt)("inlineCode",{parentName:"p"},"speculative_exec")," is disabled on a node."),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"speculative_exec")," can be enabled within ",(0,o.kt)("em",{parentName:"p"},"config.toml")," by changing ",(0,o.kt)("inlineCode",{parentName:"p"},"enable_server")," to ",(0,o.kt)("inlineCode",{parentName:"p"},"true")," under the configuration options for the speculative execution JSON-RPC HTTP server."),(0,o.kt)("p",null,"Node operators may also change the incoming request port for speculative execution, which defaults to ",(0,o.kt)("inlineCode",{parentName:"p"},"7778"),". Further, you can choose to alter the ",(0,o.kt)("inlineCode",{parentName:"p"},"qps_limit")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"max_body_bytes"),", which limit the amount and size of requests to the speculative execution server."),(0,o.kt)("h4",{id:"example-configtoml-configuration-with-speculative-execution-enabled"},"Example Config.toml configuration with speculative execution enabled"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"# ========================================================================\n# Configuration options for the speculative execution JSON-RPC HTTP server\n# ========================================================================\n[speculative_exec_server]\n\n# Flag which enables the speculative execution JSON-RPC HTTP server.\nenable_server = true\n\n# Listening address for speculative execution JSON-RPC HTTP server. If the port\n# is set to 0, a random port will be used.\n#\n# If the specified port cannot be bound to, a random port will be tried instead.\n# If binding fails, the speculative execution JSON-RPC HTTP server will not run,\n# but the node will be otherwise unaffected.\n#\n# The actual bound address will be reported via a log line if logging is enabled.\naddress = '0.0.0.0:7778'\n\n# The global max rate of requests (per second) before they are limited.\n# Request will be delayed to the next 1 second bucket once limited.\nqps_limit = 1\n\n# Maximum number of bytes to accept in a single request body.\nmax_body_bytes = 2_621_440\n\n# Specifies which origin will be reported as allowed by speculative execution server.\n#\n# If left empty, CORS will be disabled.\n# If set to '*', any origin is allowed.\n# Otherwise, only a specified origin is allowed. The given string must conform to the [origin scheme](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin).\ncors_origin = ''\n\n")),(0,o.kt)("h2",{id:"client-installation"},"Rust Client Installation"),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#the-casper-command-line-client"},"Prerequisites")," page lists installation instructions for the Casper client, which is useful for generating keys and retrieving information from the network."),(0,o.kt)("h2",{id:"create-fund-keys"},"Creating Keys and Funding Accounts"),(0,o.kt)("p",null,"The following command will create keys in the ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper/validator_keys")," folder."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client keygen /etc/casper/validator_keys\n")),(0,o.kt)("p",null,"To learn about other options for generating keys, see ",(0,o.kt)("a",{parentName:"p",href:"/concepts/accounts-and-keys"},"Accounts and Cryptographic Keys")," or run the Rust client ",(0,o.kt)("inlineCode",{parentName:"p"},"keygen")," command with the ",(0,o.kt)("inlineCode",{parentName:"p"},"--help")," option."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client keygen --help\n")),(0,o.kt)("p",null,"More about keys and key generation can also be found in ",(0,o.kt)("inlineCode",{parentName:"p"},"/etc/casper/validator_keys/README.md")," if the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node-launcher")," was installed from the Debian package."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Save your keys in a secure location, preferably offline.")),(0,o.kt)("p",null,"To submit a bonding request, you will need to ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#fund-your-account"},"fund your account")," as well."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9b4bb048.4e65eeef.js b/assets/js/9b4bb048.a6783ade.js similarity index 71% rename from assets/js/9b4bb048.4e65eeef.js rename to assets/js/9b4bb048.a6783ade.js index 39816e6104..127520862e 100644 --- a/assets/js/9b4bb048.4e65eeef.js +++ b/assets/js/9b4bb048.a6783ade.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6171],{3905:function(e,t,r){r.d(t,{Zo:function(){return l},kt:function(){return f}});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=n.createContext({}),c=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=c(e.components);return n.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(r),m=o,f=p["".concat(u,".").concat(m)]||p[m]||d[m]||i;return r?n.createElement(f,a(a({ref:t},l),{},{components:r})):n.createElement(f,a({ref:t},l))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=m;var s={};for(var u in t)hasOwnProperty.call(t,u)&&(s[u]=t[u]);s.originalType=e,s[p]="string"==typeof e?e:o,a[1]=s;for(var c=2;c=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=n.createContext({}),c=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},l=function(e){var t=c(e.components);return n.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,u=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(r),m=o,f=p["".concat(u,".").concat(m)]||p[m]||d[m]||i;return r?n.createElement(f,a(a({ref:t},l),{},{components:r})):n.createElement(f,a({ref:t},l))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=m;var s={};for(var u in t)hasOwnProperty.call(t,u)&&(s[u]=t[u]);s.originalType=e,s[p]="string"==typeof e?e:o,a[1]=s;for(var c=2;c=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(a),m=r,h=p["".concat(l,".").concat(m)]||p[m]||d[m]||o;return a?n.createElement(h,i(i({ref:t},u),{},{components:a})):n.createElement(h,i({ref:t},u))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:a.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,a=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:p(a);return function(e){var t=(0,c.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,a])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function h(e){var t=e.queryString,a=void 0!==t&&t,n=e.groupId,o=(0,s.k6)(),i=function(e){var t=e.queryString,a=void 0!==t&&t,n=e.groupId;if("string"==typeof a)return a;if(!1===a)return null;if(!0===a&&!n)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=n?n:null}({queryString:a,groupId:n});return[(0,l._X)(i),(0,r.useCallback)((function(e){if(i){var t=new URLSearchParams(o.location.search);t.set(i,e),o.replace(Object.assign({},o.location,{search:t.toString()}))}}),[i,o])]}function f(e){var t,a,n,o,i=e.defaultValue,s=e.queryString,l=void 0!==s&&s,c=e.groupId,p=d(e),f=(0,r.useState)((function(){return function(e){var t,a=e.defaultValue,n=e.tabValues;if(0===n.length)throw new Error("Docusaurus error: the component requires at least one children component");if(a){if(!m({value:a,tabValues:n}))throw new Error('Docusaurus error: The has a defaultValue "'+a+'" but none of its children has the corresponding value. Available values are: '+n.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return a}var r=null!=(t=n.find((function(e){return e.default})))?t:n[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:i,tabValues:p})})),g=f[0],b=f[1],k=h({queryString:l,groupId:c}),y=k[0],v=k[1],w=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:c}.groupId),a=(0,u.Nk)(t),n=a[0],o=a[1],[n,(0,r.useCallback)((function(e){t&&o.set(e)}),[t,o])]),N=w[0],T=w[1],x=function(){var e=null!=y?y:N;return m({value:e,tabValues:p})?e:null}();return(0,r.useLayoutEffect)((function(){x&&b(x)}),[x]),{selectedValue:g,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:p}))throw new Error("Can't select invalid tab value="+e);b(e),v(e),T(e)}),[v,T,p]),tabValues:p}}var g=a(2389),b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function k(e){var t=e.className,a=e.block,s=e.selectedValue,l=e.selectValue,c=e.tabValues,u=[],p=(0,i.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,a=u.indexOf(t),n=c[a].value;n!==s&&(p(t),l(n))},m=function(e){var t,a=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var n,r=u.indexOf(e.currentTarget)+1;a=null!=(n=u[r])?n:u[0];break;case"ArrowLeft":var o,i=u.indexOf(e.currentTarget)-1;a=null!=(o=u[i])?o:u[u.length-1]}null==(t=a)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":a},t)},c.map((function(e){var t=e.value,a=e.label,i=e.attributes;return r.createElement("li",(0,n.Z)({role:"tab",tabIndex:s===t?0:-1,"aria-selected":s===t,key:t,ref:function(e){return u.push(e)},onKeyDown:m,onClick:d},i,{className:(0,o.Z)("tabs__item",b.tabItem,null==i?void 0:i.className,{"tabs__item--active":s===t})}),null!=a?a:t)})))}function y(e){var t=e.lazy,a=e.children,n=e.selectedValue,o=(Array.isArray(a)?a:[a]).filter(Boolean);if(t){var i=o.find((function(e){return e.props.value===n}));return i?(0,r.cloneElement)(i,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},o.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==n})})))}function v(e){var t=f(e);return r.createElement("div",{className:(0,o.Z)("tabs-container",b.tabList)},r.createElement(k,(0,n.Z)({},e,t)),r.createElement(y,(0,n.Z)({},e,t)))}function w(e){var t=(0,g.Z)();return r.createElement(v,(0,n.Z)({key:String(t)},e))}},2229:function(e,t,a){a.r(t),a.d(t,{assets:function(){return d},contentTitle:function(){return u},default:function(){return g},frontMatter:function(){return c},metadata:function(){return p},toc:function(){return m}});var n=a(7462),r=a(3366),o=(a(7294),a(3905)),i=(a(4996),a(4866)),s=a(5162),l=["components"],c={title:"Move to Casper"},u="Moving to Casper from another Blockchain",p={unversionedId:"resources/moving-to-casper",id:"resources/moving-to-casper",title:"Move to Casper",description:"moving-to-casper}",source:"@site/source/docs/casper/resources/moving-to-casper.md",sourceDirName:"resources",slug:"/resources/moving-to-casper",permalink:"/resources/moving-to-casper",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/resources/moving-to-casper.md",tags:[],version:"current",lastUpdatedAt:1707837031,formattedLastUpdatedAt:"Feb 13, 2024",frontMatter:{title:"Move to Casper"},sidebar:"resources",previous:{title:"Build on Casper",permalink:"/resources/build-on-casper/introduction"},next:{title:"Casper Token Standards",permalink:"/resources/tokens/"}},d={},m=[{value:"Smart Contract Platform",id:"contract-overview",level:2},{value:"Variable Storage and State Management",id:"variable-storage",level:2},{value:"Contract Functions",id:"contract-functions",level:2},{value:"Passing Arguments",id:"passing-arguments",level:2},{value:"Additional Considerations",id:"additional-considerations",level:2}],h={toc:m},f="wrapper";function g(e){var t=e.components,a=(0,r.Z)(e,l);return(0,o.kt)(f,(0,n.Z)({},h,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"moving-to-casper"},"Moving to Casper from another Blockchain"),(0,o.kt)("p",null,"This page covers various considerations for moving to Casper from another blockchain by comparing Casper to Ethereum, Near, Aptos, and Solana in these aspects:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"#contract-overview"},"Smart Contract Platform Overview")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"#variable-storage"},"Variable Storage and State Management")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"#contract-functions"},"Contract Functions")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"#passing-arguments"},"Passing Arguments"))),(0,o.kt)("p",null,"Since other blockchain projects use different technologies, it is essential to consider how those technologies serve your use case."),(0,o.kt)("p",null,"When choosing a blockchain, it is also essential to compare consensus mechanisms, tokenomics, cross-contract capabilities, contract upgradability, and software development kits (SDKs) as described ",(0,o.kt)("a",{parentName:"p",href:"#additional-considerations"},"here"),"."),(0,o.kt)("h2",{id:"contract-overview"},"Smart Contract Platform"),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"Casper",label:"Casper",mdxType:"TabItem"},(0,o.kt)("p",null,"Casper smart contracts are written in Rust."),(0,o.kt)("p",null,"Variables defined within the smart contract can be stored as either ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#namedkey"},"Named Keys")," or ",(0,o.kt)("a",{parentName:"p",href:"/concepts/dictionaries"},"Dictionaries")," as described in ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/reading-and-writing-to-the-blockchain"},"Reading and Writing Data to the Blockchain"),"."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function serves as the main entry point of the ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract"},"smart contract"),". It automatically executes when the smart contract is installed, setting the initial state of the contract and defining all other entry points."),(0,o.kt)("p",null,"It's worth noting that Casper only supports public entry points for contracts. Additionally, contracts can be defined as upgradable or immutable as described ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/upgrading-contracts"},"here"),".")),(0,o.kt)(s.Z,{value:"Ethereum",label:"Ethereum",mdxType:"TabItem"},(0,o.kt)("p",null,"Ethereum smart contracts are primarily written in Solidity, a programming language specifically designed for this purpose. These contracts comprise a collection of global variables that persist on the blockchain and define the contract's state."),(0,o.kt)("p",null,"Furthermore, Ethereum smart contracts feature a constructor that specifies an initial state after deployment on the blockchain. Public functions declared within the contract can be invoked from outside the blockchain."),(0,o.kt)("p",null,'In terms of immutability, Ethereum smart contracts are inherently immutable once deployed. However, design patterns such as "Proxy" or "Diamond" facilitate versioning contracts on the Ethereum blockchain.'),(0,o.kt)("p",null,"Solidity smart contracts adhere to object-oriented programming principles and support features such as inheritance and libraries.")),(0,o.kt)(s.Z,{value:"Near",label:"Near",mdxType:"TabItem"},(0,o.kt)("p",null,"Near smart contracts can be written in JavaScript or Rust, and the Near SDK can pack the code with lightweight runtime. This can be compiled into a single WebAssembly file and deployed on the NEAR network."),(0,o.kt)("p",null,'In the Near ecosystem, smart contracts function as classes. The constructor, referred to as the "init" method, can receive attributes required for initializing the contract\'s initial state.'),(0,o.kt)("p",null,"All public methods defined within the contract serve as its interface, exposing its functionality."),(0,o.kt)("p",null,"Near smart contracts are immutable, but their state can change as transactions are executed. Contracts can also be upgraded by deploying new versions of the contract. The Near blockchain provides various capabilities for versioning, including state migrations, state versioning, and contract self-updates.")),(0,o.kt)(s.Z,{value:"Aptos",label:"Aptos",mdxType:"TabItem"},(0,o.kt)("p",null,"The Aptos programming language is known as Move. Its primary concepts revolve around scripts and modules. Scripts enable developers to incorporate additional logic into transactions, while modules allow them to expand blockchain functionality or create custom smart contracts."),(0,o.kt)("p",null,"A distinctive feature of Move is the concept of Resources, which are specialized structures representing assets. This design allows resources to be managed similarly to other data types in Aptos, such as vectors or structs."),(0,o.kt)("p",null,"A smart contract in the Aptos blockchain is called a Module. It is always connected with an account address. The modules have to be compiled to call functions in the Module."),(0,o.kt)("p",null,"The Module's public methods are its interface and can be invoked from code outside the blockchain."),(0,o.kt)("p",null,"Module code can be upgraded and changed under the account address, which does not change. The upgrade is only accepted if the code is backward compatible.")),(0,o.kt)(s.Z,{value:"Solana",label:"Solana",mdxType:"TabItem"},(0,o.kt)("p",null,"Solana smart contracts are primarily written in Rust."),(0,o.kt)("p",null,"Unlike other blockchain platforms, Solana's smart contracts are stateless and solely focus on program logic. The management of the contract state is handled at the account level, separating the state stored within the account and the contract logic defined in the programs."),(0,o.kt)("p",null,"Smart contracts are commonly referred to as on-chain programs. These programs expose their interface as a public entry point, allowing external interaction."),(0,o.kt)("p",null,'It is worth noting that Solana programs can be updated using an authority known as the "update authority," which holds the necessary permissions for making modifications to the program.'))),(0,o.kt)("h2",{id:"variable-storage"},"Variable Storage and State Management"),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"Casper",label:"Casper",mdxType:"TabItem"},(0,o.kt)("p",null,"Variables can be stored as Named Keys or Dictionaries as described in ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/reading-and-writing-to-the-blockchain"},"Reading and Writing Data to the Blockchain"),"."),(0,o.kt)("p",null,"Additionally, local variables are available within the entry points and can be used to perform necessary actions or computations within the scope of each entry point.")),(0,o.kt)(s.Z,{value:"Ethereum",label:"Ethereum",mdxType:"TabItem"},(0,o.kt)("p",null,"The variables within the contract are responsible for storing the state of the contract at a specific moment in time. However, it's important to note that local variables used within the call functions are not stored in the contract's state. Instead, they are employed solely for computational purposes within those specific functions."),(0,o.kt)("p",null,"State variables must be strongly typed so that the smart contract compiler can enforce type consistency and ensure the storage space aligns with the declared data types. Strong typing promotes code correctness and prevents potential data corruption or memory-related issues related to the contract's state variables.")),(0,o.kt)(s.Z,{value:"Near",label:"Near",mdxType:"TabItem"},(0,o.kt)("p",null,"Variables in the contract can be stored as native types, SDK collections, or internal structures. SDK collections offer advantages over native types."),(0,o.kt)("p",null,"Additionally, there is a distinction between class attributes and local variables. Class attributes represent the state of the contract, while local variables are specific to the invocation of a function and have no impact on the contract's overall state."),(0,o.kt)("p",null,"SDK Collections are typical when creating state variables because they provide convenient data structures such as lists, maps, and sets. These data structures can organize and manage complex data within the contract's storage. Using SDK Collections ensures efficient storage and facilitates easier access and data management in the smart contract.")),(0,o.kt)(s.Z,{value:"Aptos",label:"Aptos",mdxType:"TabItem"},(0,o.kt)("p",null,"Aptos employs primitive types, such as integers, booleans, and addresses, to represent variables. These elementary types can be combined to create structures, but it's important to note that struct definitions are only permitted within Modules."),(0,o.kt)("p",null,"Aptos advises developers to cluster related data into Resources for efficient data management and organization. Resources represent assets or specific data entities on the blockchain. By grouping data into Resources, you can maintain logical coherence and improve the readability and maintainability of the code."),(0,o.kt)("p",null,"The Aptos blockchain introduces a tree-shaped persistent global storage that allows read and write operations. Global storage consists of trees originating from an account address.")),(0,o.kt)(s.Z,{value:"Solana",label:"Solana",mdxType:"TabItem"},(0,o.kt)("p",null,"Variables can be utilized locally within the execution context of a specific entry point. They are limited to the scope of that entry point and not accessible outside of it. These variables can be defined as elementary types such as bool, String, int, etc."),(0,o.kt)("p",null,"Data persists in structs within the account. The Binary Object Representation Serializer for Hashing (Borsh) facilitates the serialization and deserialization of these structs. The process involves reading the data from the account, deserializing it to obtain the values it contains, updating the values, and then serializing the modified data to save the new values back into the account."))),(0,o.kt)("h2",{id:"contract-functions"},"Contract Functions"),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"Casper",label:"Casper",mdxType:"TabItem"},(0,o.kt)("p",null,"For Casper smart contracts, public functions are called entry points. To declare them, the following format is used:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn counter_inc() {\n\n // Entry point body\n}\n')),(0,o.kt)("p",null,"It's important to note that entry points do not have input arguments in their definition, but the arguments can be accessed using the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/struct.RuntimeArgs.html"},"RuntimeArgs")," passed to the contract. Entry points are instantiated within the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point."),(0,o.kt)("p",null,"If a return value is needed, it should be declared using the syntax described in the ",(0,o.kt)("a",{parentName:"p",href:"/resources/tutorials/advanced/return-values-tutorial"},"Interacting with Runtime Return Values")," tutorial."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"runtime::ret(value);\n")),(0,o.kt)("p",null,"Each call to an entry point is treated as a ",(0,o.kt)("a",{parentName:"p",href:"/deploy-and-deploy-lifecycle"},"Deploy")," to the network, and therefore, each call incurs a cost paid in motes (the network's native accounting unit).")),(0,o.kt)(s.Z,{value:"Ethereum",label:"Ethereum",mdxType:"TabItem"},(0,o.kt)("p",null,"On Ethereum, public methods serve two purposes: they can be used to execute contract logic and modify the contract's state, or they can be utilized to retrieve data stored within the contract's state."),(0,o.kt)("p",null,"The declaration of public methods in Ethereum follows the format:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"function update_name(string value) public {\n dapp_name = value;\n}\n")),(0,o.kt)("p",null,"In cases where a public method only returns a value without modifying the state, it should be defined as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"function balanceOf(address _owner) public view returns (uint256 return_parameter) { }\n")),(0,o.kt)("p",null,"It is worth noting that public view methods on Ethereum, which solely retrieve data without making state changes, do not consume gas.")),(0,o.kt)(s.Z,{value:"Near",label:"Near",mdxType:"TabItem"},(0,o.kt)("p",null,"In the Near blockchain, there are three types of public functions:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Init Methods")," - These are used as the class constructors to initialize the state of the contract."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"View Methods")," - These functions are used to read the state of the contract variables."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Call Methods")," - These methods can mutate the state of the contract and perform specific actions, such as calling another contract.")),(0,o.kt)("p",null,"The definition of public methods in Near is as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn add_message(&mut self, ...) { }\n")),(0,o.kt)("p",null,"For public methods that return variables, the definition would be:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn get_messages(&self, from_index: Option, limit: Option) -> Vec { }\n")),(0,o.kt)("p",null,"The actual implementation of the functions may include the necessary parameters and logic based on the contract's specific requirements.")),(0,o.kt)(s.Z,{value:"Aptos",label:"Aptos",mdxType:"TabItem"},(0,o.kt)("p",null,"Public functions in Aptos are similar to public methods or functions found in other blockchain networks. The definition of a public function in Aptos appears as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"public fun start_collection(account: &signer) {}\n")),(0,o.kt)("p",null,"For public functions that return variables, the definition would be as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"public fun max(a: u8, b: u8): (u8, bool) {}\n")),(0,o.kt)("p",null,"In the Aptos blockchain, it is possible to return one or more values from a function.")),(0,o.kt)(s.Z,{value:"Solana",label:"Solana",mdxType:"TabItem"},(0,o.kt)("p",null,"In Solana, functions are defined as public entry points that act as interfaces visible to the network. The declaration of an entry point follows this format:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"entrypoint!(process_instruction);\n")),(0,o.kt)("p",null,"The implementation of the entry point may resemble the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn process_instruction(\n program_id: &Pubkey,\n accounts: &[AccountInfo],\n _instruction_data: &[u8],\n) -> ProgramResult {}\n")),(0,o.kt)("p",null,"Within the entry point function, the necessary parameters are specified, such as ",(0,o.kt)("inlineCode",{parentName:"p"},"program_id"),", which represents the program's identifier, ",(0,o.kt)("inlineCode",{parentName:"p"},"accounts"),", an array of ",(0,o.kt)("inlineCode",{parentName:"p"},"AccountInfo")," providing account details, and ",(0,o.kt)("inlineCode",{parentName:"p"},"_instruction_data"),", representing the instruction data received. The function returns a ",(0,o.kt)("inlineCode",{parentName:"p"},"ProgramResult"),", which indicates the success or failure of the instruction execution."))),(0,o.kt)("h2",{id:"passing-arguments"},"Passing Arguments"),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"Casper",label:"Casper",mdxType:"TabItem"},(0,o.kt)("p",null,"Named arguments are passed as strings with type specifiers. To provide session arguments to the entry point during a Deploy, you can utilize the following approach:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address http://65.21.235.219:7777 \\\n --chain-name casper-test \\\n --secret-key [KEY_PATH]/secret_key.pem \\\n --payment-amount 2500000000 \\\n --session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n --session-entry-point "delegate" \\\n --session-arg "validator:public_key=\'0145fb72c75e1b459839555d70356a5e6172e706efa204d86c86050e2f7878960f\'" \\\n --session-arg "amount:u512=\'500000000000\'" \\\n --session-arg "delegator:public_key=\'0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf\'"\n')),(0,o.kt)("p",null,"To understand the context of this example, refer to: ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/delegate"},"Delegating with the Casper Client"),"."),(0,o.kt)("p",null,"In the contract, you can access the session arguments as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"let uref: URef = runtime::get_key(Key_Name)\n")),(0,o.kt)("p",null,"Use the ",(0,o.kt)("inlineCode",{parentName:"p"},"get_key")," function to retrieve the desired session argument by specifying the key's name."),(0,o.kt)("p",null,"If you are uncertain how to use the ",(0,o.kt)("inlineCode",{parentName:"p"},"get_key")," function to obtain a specific session argument, check how to ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract"},"write a basic smart contract on Casper"),".")),(0,o.kt)(s.Z,{value:"Ethereum",label:"Ethereum",mdxType:"TabItem"},(0,o.kt)("p",null,"Ethereum uses strongly typed function arguments, and developers must explicitly define the input and return variables. The compiler checks the correctness of the arguments passed to the functions during runtime. As a result, developers must explicitly specify the argument and return types in the function signature. The compiler ensures that the provided arguments adhere to the specified types, helping to catch type-related errors and ensure type safety."),(0,o.kt)("p",null,"By enforcing strong typing, the compiler helps prevent potential runtime errors and enhances code reliability by verifying the compatibility of the passed arguments and expected return types.")),(0,o.kt)(s.Z,{value:"Near",label:"Near",mdxType:"TabItem"},(0,o.kt)("p",null,"Strongly typed function arguments require explicitly defining the input and return variables. By enforcing strong typing, the programming language ensures that the arguments passed to a function match the expected types, preventing type-related errors and promoting code correctness. Strong typing provides additional clarity and safety by explicitly stating the data types of the function's inputs and outputs.")),(0,o.kt)(s.Z,{value:"Aptos",label:"Aptos",mdxType:"TabItem"},(0,o.kt)("p",null,"Like Near, Aptos requires strongly typed function arguments, thus preventing type-related errors and promoting code correctness.")),(0,o.kt)(s.Z,{value:"Solana",label:"Solana",mdxType:"TabItem"},(0,o.kt)("p",null,"Like Near and Aptos, Solana requires strongly typed function arguments, thus preventing type-related errors and promoting code correctness."))),(0,o.kt)("h2",{id:"additional-considerations"},"Additional Considerations"),(0,o.kt)("p",null,"When choosing a blockchain, you may also look into the network's consensus mechanism, the tokenomics or economic model, cross-contract communication, smart contract upgrades, and the available software development kits (SDKs)."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Consensus mechanism")," refers to the algorithm the blockchain network uses to achieve agreement on the validity and ordering of transactions. Different blockchains employ various consensus mechanisms such as Proof-of-Work (PoW), Proof-of-Stake (PoS), or Delegated Proof-of-Stake (DPoS). The choice of consensus mechanism impacts factors like security, scalability, and energy efficiency.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Tokenomics")," relates to the economic model of the blockchain network and its native tokens, involving token distribution, inflation, utility, and governance. Understanding the tokenomics of the network is crucial for evaluating the ecosystem's long-term viability and potential value.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Cross-contract capabilities")," refer to the ability of smart contracts to interact and communicate within the blockchain network. This feature is essential for building complex decentralized applications (dApps) and implementing inter-contract functionality.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Contract upgradability")," determines whether the smart contracts installed on the network can be modified or updated after installation. It is essential to assess the flexibility of the chosen blockchain in terms of contract maintenance, bug fixes, and incorporating new features or improvements without disrupting the existing ecosystem.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"SDK availability")," also plays a significant role in the development process. SDKs provide tools, libraries, and documentation to simplify the creation of applications and smart contracts on the blockchain. Evaluating the maturity, community support, and compatibility of the available SDKs is crucial for developers."))),(0,o.kt)("p",null,"Considering these aspects helps when selecting a blockchain that aligns with a project or application's specific requirements and goals."),(0,o.kt)("p",null,"The Casper ecosystem aims to fulfill all of these aspects, including supporting enterprise-grade projects."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9c5b046c.47890976.js b/assets/js/9c5b046c.47890976.js deleted file mode 100644 index 507c96f895..0000000000 --- a/assets/js/9c5b046c.47890976.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[319],{3905:function(e,t,a){a.d(t,{Zo:function(){return u},kt:function(){return h}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=c(a),m=r,h=p["".concat(l,".").concat(m)]||p[m]||d[m]||o;return a?n.createElement(h,i(i({ref:t},u),{},{components:a})):n.createElement(h,i({ref:t},u))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:a.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,a=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:p(a);return function(e){var t=(0,c.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,a])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function h(e){var t=e.queryString,a=void 0!==t&&t,n=e.groupId,o=(0,s.k6)(),i=function(e){var t=e.queryString,a=void 0!==t&&t,n=e.groupId;if("string"==typeof a)return a;if(!1===a)return null;if(!0===a&&!n)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=n?n:null}({queryString:a,groupId:n});return[(0,l._X)(i),(0,r.useCallback)((function(e){if(i){var t=new URLSearchParams(o.location.search);t.set(i,e),o.replace(Object.assign({},o.location,{search:t.toString()}))}}),[i,o])]}function f(e){var t,a,n,o,i=e.defaultValue,s=e.queryString,l=void 0!==s&&s,c=e.groupId,p=d(e),f=(0,r.useState)((function(){return function(e){var t,a=e.defaultValue,n=e.tabValues;if(0===n.length)throw new Error("Docusaurus error: the component requires at least one children component");if(a){if(!m({value:a,tabValues:n}))throw new Error('Docusaurus error: The has a defaultValue "'+a+'" but none of its children has the corresponding value. Available values are: '+n.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return a}var r=null!=(t=n.find((function(e){return e.default})))?t:n[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:i,tabValues:p})})),g=f[0],b=f[1],k=h({queryString:l,groupId:c}),y=k[0],v=k[1],w=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:c}.groupId),a=(0,u.Nk)(t),n=a[0],o=a[1],[n,(0,r.useCallback)((function(e){t&&o.set(e)}),[t,o])]),N=w[0],T=w[1],x=function(){var e=null!=y?y:N;return m({value:e,tabValues:p})?e:null}();return(0,r.useLayoutEffect)((function(){x&&b(x)}),[x]),{selectedValue:g,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:p}))throw new Error("Can't select invalid tab value="+e);b(e),v(e),T(e)}),[v,T,p]),tabValues:p}}var g=a(2389),b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function k(e){var t=e.className,a=e.block,s=e.selectedValue,l=e.selectValue,c=e.tabValues,u=[],p=(0,i.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,a=u.indexOf(t),n=c[a].value;n!==s&&(p(t),l(n))},m=function(e){var t,a=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var n,r=u.indexOf(e.currentTarget)+1;a=null!=(n=u[r])?n:u[0];break;case"ArrowLeft":var o,i=u.indexOf(e.currentTarget)-1;a=null!=(o=u[i])?o:u[u.length-1]}null==(t=a)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":a},t)},c.map((function(e){var t=e.value,a=e.label,i=e.attributes;return r.createElement("li",(0,n.Z)({role:"tab",tabIndex:s===t?0:-1,"aria-selected":s===t,key:t,ref:function(e){return u.push(e)},onKeyDown:m,onClick:d},i,{className:(0,o.Z)("tabs__item",b.tabItem,null==i?void 0:i.className,{"tabs__item--active":s===t})}),null!=a?a:t)})))}function y(e){var t=e.lazy,a=e.children,n=e.selectedValue,o=(Array.isArray(a)?a:[a]).filter(Boolean);if(t){var i=o.find((function(e){return e.props.value===n}));return i?(0,r.cloneElement)(i,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},o.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==n})})))}function v(e){var t=f(e);return r.createElement("div",{className:(0,o.Z)("tabs-container",b.tabList)},r.createElement(k,(0,n.Z)({},e,t)),r.createElement(y,(0,n.Z)({},e,t)))}function w(e){var t=(0,g.Z)();return r.createElement(v,(0,n.Z)({key:String(t)},e))}},2229:function(e,t,a){a.r(t),a.d(t,{assets:function(){return d},contentTitle:function(){return u},default:function(){return g},frontMatter:function(){return c},metadata:function(){return p},toc:function(){return m}});var n=a(7462),r=a(3366),o=(a(7294),a(3905)),i=(a(4996),a(4866)),s=a(5162),l=["components"],c={title:"Move to Casper"},u="Moving to Casper from another Blockchain",p={unversionedId:"resources/moving-to-casper",id:"resources/moving-to-casper",title:"Move to Casper",description:"moving-to-casper}",source:"@site/source/docs/casper/resources/moving-to-casper.md",sourceDirName:"resources",slug:"/resources/moving-to-casper",permalink:"/resources/moving-to-casper",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/resources/moving-to-casper.md",tags:[],version:"current",lastUpdatedAt:1707229568,formattedLastUpdatedAt:"Feb 6, 2024",frontMatter:{title:"Move to Casper"},sidebar:"resources",previous:{title:"Build on Casper",permalink:"/resources/build-on-casper/introduction"},next:{title:"Casper Token Standards",permalink:"/resources/tokens/"}},d={},m=[{value:"Smart Contract Platform",id:"contract-overview",level:2},{value:"Variable Storage and State Management",id:"variable-storage",level:2},{value:"Contract Functions",id:"contract-functions",level:2},{value:"Passing Arguments",id:"passing-arguments",level:2},{value:"Additional Considerations",id:"additional-considerations",level:2}],h={toc:m},f="wrapper";function g(e){var t=e.components,a=(0,r.Z)(e,l);return(0,o.kt)(f,(0,n.Z)({},h,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"moving-to-casper"},"Moving to Casper from another Blockchain"),(0,o.kt)("p",null,"This page covers various considerations for moving to Casper from another blockchain by comparing Casper to Ethereum, Near, Aptos, and Solana in these aspects:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"#contract-overview"},"Smart Contract Platform Overview")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"#variable-storage"},"Variable Storage and State Management")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"#contract-functions"},"Contract Functions")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("a",{parentName:"li",href:"#passing-arguments"},"Passing Arguments"))),(0,o.kt)("p",null,"Since other blockchain projects use different technologies, it is essential to consider how those technologies serve your use case."),(0,o.kt)("p",null,"When choosing a blockchain, it is also essential to compare consensus mechanisms, tokenomics, cross-contract capabilities, contract upgradability, and software development kits (SDKs) as described ",(0,o.kt)("a",{parentName:"p",href:"#additional-considerations"},"here"),"."),(0,o.kt)("h2",{id:"contract-overview"},"Smart Contract Platform"),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"Casper",label:"Casper",mdxType:"TabItem"},(0,o.kt)("p",null,"Casper smart contracts are written in Rust."),(0,o.kt)("p",null,"Variables defined within the smart contract can be stored as either ",(0,o.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#namedkey"},"Named Keys")," or ",(0,o.kt)("a",{parentName:"p",href:"/concepts/dictionaries"},"Dictionaries")," as described in ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/reading-and-writing-to-the-blockchain"},"Reading and Writing Data to the Blockchain"),"."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function serves as the main entry point of the ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract"},"smart contract"),". It automatically executes when the smart contract is installed, setting the initial state of the contract and defining all other entry points."),(0,o.kt)("p",null,"It's worth noting that Casper only supports public entry points for contracts. Additionally, contracts can be defined as upgradable or immutable as described ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/upgrading-contracts"},"here"),".")),(0,o.kt)(s.Z,{value:"Ethereum",label:"Ethereum",mdxType:"TabItem"},(0,o.kt)("p",null,"Ethereum smart contracts are primarily written in Solidity, a programming language specifically designed for this purpose. These contracts comprise a collection of global variables that persist on the blockchain and define the contract's state."),(0,o.kt)("p",null,"Furthermore, Ethereum smart contracts feature a constructor that specifies an initial state after deployment on the blockchain. Public functions declared within the contract can be invoked from outside the blockchain."),(0,o.kt)("p",null,'In terms of immutability, Ethereum smart contracts are inherently immutable once deployed. However, design patterns such as "Proxy" or "Diamond" facilitate versioning contracts on the Ethereum blockchain.'),(0,o.kt)("p",null,"Solidity smart contracts adhere to object-oriented programming principles and support features such as inheritance and libraries.")),(0,o.kt)(s.Z,{value:"Near",label:"Near",mdxType:"TabItem"},(0,o.kt)("p",null,"Near smart contracts can be written in JavaScript or Rust, and the Near SDK can pack the code with lightweight runtime. This can be compiled into a single WebAssembly file and deployed on the NEAR network."),(0,o.kt)("p",null,'In the Near ecosystem, smart contracts function as classes. The constructor, referred to as the "init" method, can receive attributes required for initializing the contract\'s initial state.'),(0,o.kt)("p",null,"All public methods defined within the contract serve as its interface, exposing its functionality."),(0,o.kt)("p",null,"Near smart contracts are immutable, but their state can change as transactions are executed. Contracts can also be upgraded by deploying new versions of the contract. The Near blockchain provides various capabilities for versioning, including state migrations, state versioning, and contract self-updates.")),(0,o.kt)(s.Z,{value:"Aptos",label:"Aptos",mdxType:"TabItem"},(0,o.kt)("p",null,"The Aptos programming language is known as Move. Its primary concepts revolve around scripts and modules. Scripts enable developers to incorporate additional logic into transactions, while modules allow them to expand blockchain functionality or create custom smart contracts."),(0,o.kt)("p",null,"A distinctive feature of Move is the concept of Resources, which are specialized structures representing assets. This design allows resources to be managed similarly to other data types in Aptos, such as vectors or structs."),(0,o.kt)("p",null,"A smart contract in the Aptos blockchain is called a Module. It is always connected with an account address. The modules have to be compiled to call functions in the Module."),(0,o.kt)("p",null,"The Module's public methods are its interface and can be invoked from code outside the blockchain."),(0,o.kt)("p",null,"Module code can be upgraded and changed under the account address, which does not change. The upgrade is only accepted if the code is backward compatible.")),(0,o.kt)(s.Z,{value:"Solana",label:"Solana",mdxType:"TabItem"},(0,o.kt)("p",null,"Solana smart contracts are primarily written in Rust."),(0,o.kt)("p",null,"Unlike other blockchain platforms, Solana's smart contracts are stateless and solely focus on program logic. The management of the contract state is handled at the account level, separating the state stored within the account and the contract logic defined in the programs."),(0,o.kt)("p",null,"Smart contracts are commonly referred to as on-chain programs. These programs expose their interface as a public entry point, allowing external interaction."),(0,o.kt)("p",null,'It is worth noting that Solana programs can be updated using an authority known as the "update authority," which holds the necessary permissions for making modifications to the program.'))),(0,o.kt)("h2",{id:"variable-storage"},"Variable Storage and State Management"),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"Casper",label:"Casper",mdxType:"TabItem"},(0,o.kt)("p",null,"Variables can be stored as Named Keys or Dictionaries as described in ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/reading-and-writing-to-the-blockchain"},"Reading and Writing Data to the Blockchain"),"."),(0,o.kt)("p",null,"Additionally, local variables are available within the entry points and can be used to perform necessary actions or computations within the scope of each entry point.")),(0,o.kt)(s.Z,{value:"Ethereum",label:"Ethereum",mdxType:"TabItem"},(0,o.kt)("p",null,"The variables within the contract are responsible for storing the state of the contract at a specific moment in time. However, it's important to note that local variables used within the call functions are not stored in the contract's state. Instead, they are employed solely for computational purposes within those specific functions."),(0,o.kt)("p",null,"State variables must be strongly typed so that the smart contract compiler can enforce type consistency and ensure the storage space aligns with the declared data types. Strong typing promotes code correctness and prevents potential data corruption or memory-related issues related to the contract's state variables.")),(0,o.kt)(s.Z,{value:"Near",label:"Near",mdxType:"TabItem"},(0,o.kt)("p",null,"Variables in the contract can be stored as native types, SDK collections, or internal structures. SDK collections offer advantages over native types."),(0,o.kt)("p",null,"Additionally, there is a distinction between class attributes and local variables. Class attributes represent the state of the contract, while local variables are specific to the invocation of a function and have no impact on the contract's overall state."),(0,o.kt)("p",null,"SDK Collections are typical when creating state variables because they provide convenient data structures such as lists, maps, and sets. These data structures can organize and manage complex data within the contract's storage. Using SDK Collections ensures efficient storage and facilitates easier access and data management in the smart contract.")),(0,o.kt)(s.Z,{value:"Aptos",label:"Aptos",mdxType:"TabItem"},(0,o.kt)("p",null,"Aptos employs primitive types, such as integers, booleans, and addresses, to represent variables. These elementary types can be combined to create structures, but it's important to note that struct definitions are only permitted within Modules."),(0,o.kt)("p",null,"Aptos advises developers to cluster related data into Resources for efficient data management and organization. Resources represent assets or specific data entities on the blockchain. By grouping data into Resources, you can maintain logical coherence and improve the readability and maintainability of the code."),(0,o.kt)("p",null,"The Aptos blockchain introduces a tree-shaped persistent global storage that allows read and write operations. Global storage consists of trees originating from an account address.")),(0,o.kt)(s.Z,{value:"Solana",label:"Solana",mdxType:"TabItem"},(0,o.kt)("p",null,"Variables can be utilized locally within the execution context of a specific entry point. They are limited to the scope of that entry point and not accessible outside of it. These variables can be defined as elementary types such as bool, String, int, etc."),(0,o.kt)("p",null,"Data persists in structs within the account. The Binary Object Representation Serializer for Hashing (Borsh) facilitates the serialization and deserialization of these structs. The process involves reading the data from the account, deserializing it to obtain the values it contains, updating the values, and then serializing the modified data to save the new values back into the account."))),(0,o.kt)("h2",{id:"contract-functions"},"Contract Functions"),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"Casper",label:"Casper",mdxType:"TabItem"},(0,o.kt)("p",null,"For Casper smart contracts, public functions are called entry points. To declare them, the following format is used:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn counter_inc() {\n\n // Entry point body\n}\n')),(0,o.kt)("p",null,"It's important to note that entry points do not have input arguments in their definition, but the arguments can be accessed using the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/struct.RuntimeArgs.html"},"RuntimeArgs")," passed to the contract. Entry points are instantiated within the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point."),(0,o.kt)("p",null,"If a return value is needed, it should be declared using the syntax described in the ",(0,o.kt)("a",{parentName:"p",href:"/resources/tutorials/advanced/return-values-tutorial"},"Interacting with Runtime Return Values")," tutorial."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"runtime::ret(value);\n")),(0,o.kt)("p",null,"Each call to an entry point is treated as a ",(0,o.kt)("a",{parentName:"p",href:"/deploy-and-deploy-lifecycle"},"Deploy")," to the network, and therefore, each call incurs a cost paid in motes (the network's native accounting unit).")),(0,o.kt)(s.Z,{value:"Ethereum",label:"Ethereum",mdxType:"TabItem"},(0,o.kt)("p",null,"On Ethereum, public methods serve two purposes: they can be used to execute contract logic and modify the contract's state, or they can be utilized to retrieve data stored within the contract's state."),(0,o.kt)("p",null,"The declaration of public methods in Ethereum follows the format:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"function update_name(string value) public {\n dapp_name = value;\n}\n")),(0,o.kt)("p",null,"In cases where a public method only returns a value without modifying the state, it should be defined as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"function balanceOf(address _owner) public view returns (uint256 return_parameter) { }\n")),(0,o.kt)("p",null,"It is worth noting that public view methods on Ethereum, which solely retrieve data without making state changes, do not consume gas.")),(0,o.kt)(s.Z,{value:"Near",label:"Near",mdxType:"TabItem"},(0,o.kt)("p",null,"In the Near blockchain, there are three types of public functions:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Init Methods")," - These are used as the class constructors to initialize the state of the contract."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"View Methods")," - These functions are used to read the state of the contract variables."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Call Methods")," - These methods can mutate the state of the contract and perform specific actions, such as calling another contract.")),(0,o.kt)("p",null,"The definition of public methods in Near is as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn add_message(&mut self, ...) { }\n")),(0,o.kt)("p",null,"For public methods that return variables, the definition would be:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn get_messages(&self, from_index: Option, limit: Option) -> Vec { }\n")),(0,o.kt)("p",null,"The actual implementation of the functions may include the necessary parameters and logic based on the contract's specific requirements.")),(0,o.kt)(s.Z,{value:"Aptos",label:"Aptos",mdxType:"TabItem"},(0,o.kt)("p",null,"Public functions in Aptos are similar to public methods or functions found in other blockchain networks. The definition of a public function in Aptos appears as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"public fun start_collection(account: &signer) {}\n")),(0,o.kt)("p",null,"For public functions that return variables, the definition would be as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"public fun max(a: u8, b: u8): (u8, bool) {}\n")),(0,o.kt)("p",null,"In the Aptos blockchain, it is possible to return one or more values from a function.")),(0,o.kt)(s.Z,{value:"Solana",label:"Solana",mdxType:"TabItem"},(0,o.kt)("p",null,"In Solana, functions are defined as public entry points that act as interfaces visible to the network. The declaration of an entry point follows this format:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"entrypoint!(process_instruction);\n")),(0,o.kt)("p",null,"The implementation of the entry point may resemble the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn process_instruction(\n program_id: &Pubkey,\n accounts: &[AccountInfo],\n _instruction_data: &[u8],\n) -> ProgramResult {}\n")),(0,o.kt)("p",null,"Within the entry point function, the necessary parameters are specified, such as ",(0,o.kt)("inlineCode",{parentName:"p"},"program_id"),", which represents the program's identifier, ",(0,o.kt)("inlineCode",{parentName:"p"},"accounts"),", an array of ",(0,o.kt)("inlineCode",{parentName:"p"},"AccountInfo")," providing account details, and ",(0,o.kt)("inlineCode",{parentName:"p"},"_instruction_data"),", representing the instruction data received. The function returns a ",(0,o.kt)("inlineCode",{parentName:"p"},"ProgramResult"),", which indicates the success or failure of the instruction execution."))),(0,o.kt)("h2",{id:"passing-arguments"},"Passing Arguments"),(0,o.kt)(i.Z,{mdxType:"Tabs"},(0,o.kt)(s.Z,{value:"Casper",label:"Casper",mdxType:"TabItem"},(0,o.kt)("p",null,"Named arguments are passed as strings with type specifiers. To provide session arguments to the entry point during a Deploy, you can utilize the following approach:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address http://65.21.235.219:7777 \\\n --chain-name casper-test \\\n --secret-key [KEY_PATH]/secret_key.pem \\\n --payment-amount 2500000000 \\\n --session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n --session-entry-point "delegate" \\\n --session-arg "validator:public_key=\'0145fb72c75e1b459839555d70356a5e6172e706efa204d86c86050e2f7878960f\'" \\\n --session-arg "amount:u512=\'500000000000\'" \\\n --session-arg "delegator:public_key=\'0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf\'"\n')),(0,o.kt)("p",null,"To understand the context of this example, refer to: ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/delegate"},"Delegating with the Casper Client"),"."),(0,o.kt)("p",null,"In the contract, you can access the session arguments as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"let uref: URef = runtime::get_key(Key_Name)\n")),(0,o.kt)("p",null,"Use the ",(0,o.kt)("inlineCode",{parentName:"p"},"get_key")," function to retrieve the desired session argument by specifying the key's name."),(0,o.kt)("p",null,"If you are uncertain how to use the ",(0,o.kt)("inlineCode",{parentName:"p"},"get_key")," function to obtain a specific session argument, check how to ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract"},"write a basic smart contract on Casper"),".")),(0,o.kt)(s.Z,{value:"Ethereum",label:"Ethereum",mdxType:"TabItem"},(0,o.kt)("p",null,"Ethereum uses strongly typed function arguments, and developers must explicitly define the input and return variables. The compiler checks the correctness of the arguments passed to the functions during runtime. As a result, developers must explicitly specify the argument and return types in the function signature. The compiler ensures that the provided arguments adhere to the specified types, helping to catch type-related errors and ensure type safety."),(0,o.kt)("p",null,"By enforcing strong typing, the compiler helps prevent potential runtime errors and enhances code reliability by verifying the compatibility of the passed arguments and expected return types.")),(0,o.kt)(s.Z,{value:"Near",label:"Near",mdxType:"TabItem"},(0,o.kt)("p",null,"Strongly typed function arguments require explicitly defining the input and return variables. By enforcing strong typing, the programming language ensures that the arguments passed to a function match the expected types, preventing type-related errors and promoting code correctness. Strong typing provides additional clarity and safety by explicitly stating the data types of the function's inputs and outputs.")),(0,o.kt)(s.Z,{value:"Aptos",label:"Aptos",mdxType:"TabItem"},(0,o.kt)("p",null,"Like Near, Aptos requires strongly typed function arguments, thus preventing type-related errors and promoting code correctness.")),(0,o.kt)(s.Z,{value:"Solana",label:"Solana",mdxType:"TabItem"},(0,o.kt)("p",null,"Like Near and Aptos, Solana requires strongly typed function arguments, thus preventing type-related errors and promoting code correctness."))),(0,o.kt)("h2",{id:"additional-considerations"},"Additional Considerations"),(0,o.kt)("p",null,"When choosing a blockchain, you may also look into the network's consensus mechanism, the tokenomics or economic model, cross-contract communication, smart contract upgrades, and the available software development kits (SDKs)."),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Consensus mechanism")," refers to the algorithm the blockchain network uses to achieve agreement on the validity and ordering of transactions. Different blockchains employ various consensus mechanisms such as Proof-of-Work (PoW), Proof-of-Stake (PoS), or Delegated Proof-of-Stake (DPoS). The choice of consensus mechanism impacts factors like security, scalability, and energy efficiency.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Tokenomics")," relates to the economic model of the blockchain network and its native tokens, involving token distribution, inflation, utility, and governance. Understanding the tokenomics of the network is crucial for evaluating the ecosystem's long-term viability and potential value.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Cross-contract capabilities")," refer to the ability of smart contracts to interact and communicate within the blockchain network. This feature is essential for building complex decentralized applications (dApps) and implementing inter-contract functionality.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"Contract upgradability")," determines whether the smart contracts installed on the network can be modified or updated after installation. It is essential to assess the flexibility of the chosen blockchain in terms of contract maintenance, bug fixes, and incorporating new features or improvements without disrupting the existing ecosystem.")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("p",{parentName:"li"},(0,o.kt)("strong",{parentName:"p"},"SDK availability")," also plays a significant role in the development process. SDKs provide tools, libraries, and documentation to simplify the creation of applications and smart contracts on the blockchain. Evaluating the maturity, community support, and compatibility of the available SDKs is crucial for developers."))),(0,o.kt)("p",null,"Considering these aspects helps when selecting a blockchain that aligns with a project or application's specific requirements and goals."),(0,o.kt)("p",null,"The Casper ecosystem aims to fulfill all of these aspects, including supporting enterprise-grade projects."))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9df8dea5.0d854a46.js b/assets/js/9df8dea5.0d854a46.js deleted file mode 100644 index 064db81864..0000000000 --- a/assets/js/9df8dea5.0d854a46.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4685],{3905:function(t,e,a){a.d(e,{Zo:function(){return m},kt:function(){return N}});var n=a(7294);function r(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function l(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function i(t){for(var e=1;e=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var o=n.createContext({}),p=function(t){var e=n.useContext(o),a=e;return t&&(a="function"==typeof t?t(e):i(i({},e),t)),a},m=function(t){var e=p(t.components);return n.createElement(o.Provider,{value:e},t.children)},s="mdxType",k={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},u=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,l=t.originalType,o=t.parentName,m=d(t,["components","mdxType","originalType","parentName"]),s=p(a),u=r,N=s["".concat(o,".").concat(u)]||s[u]||k[u]||l;return a?n.createElement(N,i(i({ref:e},m),{},{components:a})):n.createElement(N,i({ref:e},m))}));function N(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=a.length,i=new Array(l);i[0]=u;var d={};for(var o in e)hasOwnProperty.call(e,o)&&(d[o]=e[o]);d.originalType=t,d[s]="string"==typeof t?t:r,i[1]=d;for(var p=2;p=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var o=n.createContext({}),p=function(t){var e=n.useContext(o),a=e;return t&&(a="function"==typeof t?t(e):i(i({},e),t)),a},m=function(t){var e=p(t.components);return n.createElement(o.Provider,{value:e},t.children)},s="mdxType",k={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},u=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,l=t.originalType,o=t.parentName,m=d(t,["components","mdxType","originalType","parentName"]),s=p(a),u=r,N=s["".concat(o,".").concat(u)]||s[u]||k[u]||l;return a?n.createElement(N,i(i({ref:e},m),{},{components:a})):n.createElement(N,i({ref:e},m))}));function N(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=a.length,i=new Array(l);i[0]=u;var d={};for(var o in e)hasOwnProperty.call(e,o)&&(d[o]=e[o]);d.originalType=t,d[s]="string"==typeof t?t:r,i[1]=d;for(var p=2;p=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),s=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=s(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=r,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return n?o.createElement(f,i(i({ref:t},p),{},{components:n})):o.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:r,i[1]=l;for(var s=2;s=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),s=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=s(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=s(n),m=r,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return n?o.createElement(f,i(i({ref:t},p),{},{components:n})):o.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:r,i[1]=l;for(var s=2;s=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=a.createContext({}),c=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=c(e.components);return a.createElement(p.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=c(n),h=o,f=d["".concat(p,".").concat(h)]||d[h]||u[h]||r;return n?a.createElement(f,i(i({ref:t},l),{},{components:n})):a.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var c=2;c=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=a.createContext({}),c=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=c(e.components);return a.createElement(p.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),d=c(n),h=o,f=d["".concat(p,".").concat(h)]||d[h]||u[h]||r;return n?a.createElement(f,i(i({ref:t},l),{},{components:n})):a.createElement(f,i({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var c=2;c=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var i=a.createContext({}),c=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},d=function(e){var n=c(e.components);return a.createElement(i.Provider,{value:n},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=c(t),h=r,b=u["".concat(i,".").concat(h)]||u[h]||p[h]||o;return t?a.createElement(b,s(s({ref:n},d),{},{components:t})):a.createElement(b,s({ref:n},d))}));function b(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,s=new Array(o);s[0]=h;var l={};for(var i in n)hasOwnProperty.call(n,i)&&(l[i]=n[i]);l.originalType=e,l[u]="string"==typeof e?e:r,s[1]=l;for(var c=2;c:7777\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - (STRING OR INTEGER) Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "chain_get_state_root_hash",\n "params": null,\n "id": 1\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "state_root_hash": "f97d8d36630a8f4acdb323223596f6fa01ee3b0d49ad70d84d715c156c5dbec6"\n },\n "id": 1\n}\n'))),(0,o.kt)("h2",{id:"querying-an-account"},"Querying an Account"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Accounts")," are stored in the global state and can be queried using the ",(0,o.kt)("inlineCode",{parentName:"p"},"query-global-state")," command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n --id 4 \\\n --node-address http://:7777 \\\n --state-root-hash \\\n --key \n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"state-root-hash")," - Hex-encoded hash of the state root"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"key")," - The base key for the query. This must be a properly formatted public key, account hash, contract address hash, URef, transfer hash or deploy-info hash.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Important response fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'"result"."stored_value"."Account"."main_purse"')," - the address of the main purse containing the sender's tokens. This purse is the source of the tokens transferred in this example")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example Account Query with Verbose Output:")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -v \\\n --id 4 \\\n --node-address https://rpc.testnet.casperlabs.io/ \\\n --state-root-hash a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2 \\\n --key 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Explore the sample JSON-RPC request and response generated."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "query_global_state",\n "params": {\n "state_identifier": {\n "StateRootHash": "a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2"\n },\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "path": []\n },\n "id": 4\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "id": 4,\n "result": {\n "api_version": "1.5.2",\n "block_header": null,\n "stored_value": {\n "Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "named_keys": [\n {\n "name": "counter",\n "key": "hash-4bf23564c8849a0a3193781f0a9df7d27c4bce2cc585d6e9bb161a7a1ce5cd7e"\n },\n {\n "name": "counter_access_uref",\n "key": "uref-76b6c7e7a87b752d34a8c3ccdc070dbfd1940960016c537525b2ab9076b61a3e-007"\n },\n {\n "name": "counter_package_name",\n "key": "hash-e4b2060f098fa763f9a68c5c98a2d98a4fa80815ec0fd6b93ac9efbb0c18f19b"\n },\n {\n "name": "my-key-name",\n "key": "uref-09376d4202d32457ceefa4d9cdf1db6ab2324981ade06ba6f495cdf14124c3b9-007"\n },\n {\n "name": "version",\n "key": "uref-244a270207dd13ef5ff190f75d84efe4ab54bd5787be0bbb175c3fb154b7f5ed-007"\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "associated_keys": [\n {\n "account_hash": "account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n },\n {\n "account_hash": "account-hash-77ea2e433c94c9cb8303942335da458672249d38c1fa5d1d7a7500b862ff52a4",\n "weight": 1\n },\n {\n "account_hash": "account-hash-d65d053f5017af101b752a9a12ba4c41fe3054b8632998a69193b891eab4caf5",\n "weight": 1\n },\n {\n "account_hash": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",\n "weight": 1\n },\n {\n "account_hash": "account-hash-f1802d2dbd83e41f638eb9b046f762e481d56b27d4aa00817fec77fbb21f944a",\n "weight": 1\n }\n ],\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n }\n }\n },\n "merkle_proof": "[32054 hex chars]"\n }\n}\n'))),(0,o.kt)("p",null,"To query the account balance, use the ",(0,o.kt)("inlineCode",{parentName:"p"},"query-balance")," command and the purse identifier, which can be a public key or account hash, implying the main purse of the given account should be used. Alternatively, the purse's URef can be used. The balance returned is in motes (the unit that makes up the Casper token). For full details, run the following help command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-balance --help\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-balance \\\n--id 6 \\\n--node-address http://:7777 \\\n--state-root-hash \\\n--purse-identifier \n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"state-root-hash")," - Hex-encoded hash of the state root"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"purse-identifier")," - A public key or account hash, implying the main purse of the given account should be used. Alternatively, the purse's URef.")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"-v")," option generates verbose output, printing the RPC request and response generated. Let's explore an example below."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example Balance Query with Verbose Output:")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-balance -v \\\n --id 6 \\\n --node-address https://rpc.testnet.casperlabs.io/ \\\n --state-root-hash a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2 \\\n --purse-identifier 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "query_balance",\n "params": {\n "state_identifier": {\n "StateRootHash": "a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2"\n },\n "purse_identifier": {\n "main_purse_under_public_key": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986"\n }\n },\n "id": 6\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.5.2",\n "balance": "164000000000"\n },\n "id": 6\n}\n'))),(0,o.kt)("h2",{id:"querying-blocks"},"Querying Blocks"),(0,o.kt)("p",null,"It is possible to obtain detailed block information from the system. To do this, obtain the hash of the block of interest and send this query to a node in the network. Here is an example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-block \\\n --id 3 \\\n --node-address http://:7777 \\\n --block-identifier \\\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"block-identifier")," - Hex-encoded block hash or height of the block. If not given, the last block added to the chain as known at the given node will be used")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Important response fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'"result"."block"."header"."state_root_hash"')," - contains the ",(0,o.kt)("inlineCode",{parentName:"li"},"state-root-hash")," for this block")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": 3,\n "jsonrpc": "2.0",\n "method": "chain_get_block",\n "params": {\n "block_identifier": {\n "Hash": "7c7e9b0f087bba5ce6fc4bd067b57f69ea3c8109157a3ad7f6d98b8da77d97f9"\n }\n }\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": 3,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block": {\n "body": {\n "deploy_hashes": [],\n "proposer": "012c6775c0e9e09f93b9450f1c5348c5f6b97895b0f52bb438f781f96ba2675a94",\n "transfer_hashes": ["ec2d477a532e00b08cfa9447b7841a645a27d34ee12ec55318263617e5740713"]\n },\n "hash": "7c7e9b0f087bba5ce6fc4bd067b57f69ea3c8109157a3ad7f6d98b8da77d97f9",\n "header": {\n "accumulated_seed": "50b8ac019b7300cd1fdeec050310e61b900e9238aa879929745900a91bd0fc4f",\n "body_hash": "224076b19c04279ae9b97f620801d5ff40ba64f431fe0d5089ef7cb84fdff45a",\n "era_end": null,\n "era_id": 0,\n "height": 8,\n "parent_hash": "416f339c4c2ff299c64a4b3271c5ef2ac2297bb40a477ceacce1483451a4db16",\n "protocol_version": "1.0.0",\n "random_bit": true,\n "state_root_hash": "cfdbf775b6671de3787cfb1f62f0c5319605a7c1711d6ece4660b37e57e81aa3",\n "timestamp": "2021-04-20T18:04:42.368Z"\n },\n "proofs": [\n {\n "public_key": "010f50b0116f213ef65b99d1bd54483f92bf6131de2f8aceb7e3f825a838292150",\n "signature": "130 chars"\n },\n {\n "public_key": "012c6775c0e9e09f93b9450f1c5348c5f6b97895b0f52bb438f781f96ba2675a94",\n "signature": "130 chars"\n },\n {\n "public_key": "018d5da83f22c9b65cdfdf9f9fdf9f7c98aa2b8c7bcf14bf855177bbb9c1ac7f0a",\n "signature": "130 chars"\n },\n {\n "public_key": "01b9088b92c8a8d592f6ec8c3e8153d7c55fc0c38b5999a214e37e73a2edd6fe0f",\n "signature": "130 chars"\n },\n {\n "public_key": "01b9e3484d96d5693e6c5fe789e7b28972aa392b054a76d175f079692967f604de",\n "signature": "130 chars"\n }\n ]\n }\n }\n}\n'))),(0,o.kt)("h2",{id:"querying-deploys"},"Querying Deploys"),(0,o.kt)("p",null,"Once you submit a deploy to the network, you can check its execution status using ",(0,o.kt)("inlineCode",{parentName:"p"},"get-deploy"),". If the ",(0,o.kt)("inlineCode",{parentName:"p"},"execution_results")," in the output are null, the transaction has not run yet. Note that transactions are finalized upon execution."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --id 2 \\\n --node-address http://:7777 \\\n \n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - JSON-RPC identifier, applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"deploy-hash")," - Hex-encoded hash of the deploy")))}b.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9ff556dd.aa8b8800.js b/assets/js/9ff556dd.aa8b8800.js deleted file mode 100644 index 78f2522032..0000000000 --- a/assets/js/9ff556dd.aa8b8800.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3355],{3905:function(e,n,t){t.d(n,{Zo:function(){return d},kt:function(){return b}});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function s(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var i=a.createContext({}),c=function(e){var n=a.useContext(i),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},d=function(e){var n=c(e.components);return a.createElement(i.Provider,{value:n},e.children)},u="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=c(t),h=r,b=u["".concat(i,".").concat(h)]||u[h]||p[h]||o;return t?a.createElement(b,s(s({ref:n},d),{},{components:t})):a.createElement(b,s({ref:n},d))}));function b(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,s=new Array(o);s[0]=h;var l={};for(var i in n)hasOwnProperty.call(n,i)&&(l[i]=n[i]);l.originalType=e,l[u]="string"==typeof e?e:r,s[1]=l;for(var c=2;c:7777\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - (STRING OR INTEGER) Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "chain_get_state_root_hash",\n "params": null,\n "id": 1\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "state_root_hash": "f97d8d36630a8f4acdb323223596f6fa01ee3b0d49ad70d84d715c156c5dbec6"\n },\n "id": 1\n}\n'))),(0,o.kt)("h2",{id:"querying-an-account"},"Querying an Account"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Accounts")," are stored in the global state and can be queried using the ",(0,o.kt)("inlineCode",{parentName:"p"},"query-global-state")," command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n --id 4 \\\n --node-address http://:7777 \\\n --state-root-hash \\\n --key \n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"state-root-hash")," - Hex-encoded hash of the state root"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"key")," - The base key for the query. This must be a properly formatted public key, account hash, contract address hash, URef, transfer hash or deploy-info hash.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Important response fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'"result"."stored_value"."Account"."main_purse"')," - the address of the main purse containing the sender's tokens. This purse is the source of the tokens transferred in this example")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example Account Query with Verbose Output:")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state -v \\\n --id 4 \\\n --node-address https://rpc.testnet.casperlabs.io/ \\\n --state-root-hash a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2 \\\n --key 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Explore the sample JSON-RPC request and response generated."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "query_global_state",\n "params": {\n "state_identifier": {\n "StateRootHash": "a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2"\n },\n "key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "path": []\n },\n "id": 4\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "id": 4,\n "result": {\n "api_version": "1.5.2",\n "block_header": null,\n "stored_value": {\n "Account": {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "named_keys": [\n {\n "name": "counter",\n "key": "hash-4bf23564c8849a0a3193781f0a9df7d27c4bce2cc585d6e9bb161a7a1ce5cd7e"\n },\n {\n "name": "counter_access_uref",\n "key": "uref-76b6c7e7a87b752d34a8c3ccdc070dbfd1940960016c537525b2ab9076b61a3e-007"\n },\n {\n "name": "counter_package_name",\n "key": "hash-e4b2060f098fa763f9a68c5c98a2d98a4fa80815ec0fd6b93ac9efbb0c18f19b"\n },\n {\n "name": "my-key-name",\n "key": "uref-09376d4202d32457ceefa4d9cdf1db6ab2324981ade06ba6f495cdf14124c3b9-007"\n },\n {\n "name": "version",\n "key": "uref-244a270207dd13ef5ff190f75d84efe4ab54bd5787be0bbb175c3fb154b7f5ed-007"\n }\n ],\n "main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",\n "associated_keys": [\n {\n "account_hash": "account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34",\n "weight": 1\n },\n {\n "account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",\n "weight": 3\n },\n {\n "account_hash": "account-hash-77ea2e433c94c9cb8303942335da458672249d38c1fa5d1d7a7500b862ff52a4",\n "weight": 1\n },\n {\n "account_hash": "account-hash-d65d053f5017af101b752a9a12ba4c41fe3054b8632998a69193b891eab4caf5",\n "weight": 1\n },\n {\n "account_hash": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",\n "weight": 1\n },\n {\n "account_hash": "account-hash-f1802d2dbd83e41f638eb9b046f762e481d56b27d4aa00817fec77fbb21f944a",\n "weight": 1\n }\n ],\n "action_thresholds": {\n "deployment": 2,\n "key_management": 3\n }\n }\n },\n "merkle_proof": "[32054 hex chars]"\n }\n}\n'))),(0,o.kt)("p",null,"To query the account balance, use the ",(0,o.kt)("inlineCode",{parentName:"p"},"query-balance")," command and the purse identifier, which can be a public key or account hash, implying the main purse of the given account should be used. Alternatively, the purse's URef can be used. The balance returned is in motes (the unit that makes up the Casper token). For full details, run the following help command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-balance --help\n")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-balance \\\n--id 6 \\\n--node-address http://:7777 \\\n--state-root-hash \\\n--purse-identifier \n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"state-root-hash")," - Hex-encoded hash of the state root"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"purse-identifier")," - A public key or account hash, implying the main purse of the given account should be used. Alternatively, the purse's URef.")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"-v")," option generates verbose output, printing the RPC request and response generated. Let's explore an example below."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example Balance Query with Verbose Output:")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-balance -v \\\n --id 6 \\\n --node-address https://rpc.testnet.casperlabs.io/ \\\n --state-root-hash a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2 \\\n --purse-identifier 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "method": "query_balance",\n "params": {\n "state_identifier": {\n "StateRootHash": "a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2"\n },\n "purse_identifier": {\n "main_purse_under_public_key": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986"\n }\n },\n "id": 6\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.5.2",\n "balance": "164000000000"\n },\n "id": 6\n}\n'))),(0,o.kt)("h2",{id:"querying-blocks"},"Querying Blocks"),(0,o.kt)("p",null,"It is possible to obtain detailed block information from the system. To do this, obtain the hash of the block of interest and send this query to a node in the network. Here is an example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-block \\\n --id 3 \\\n --node-address http://:7777 \\\n --block-identifier \\\n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"block-identifier")," - Hex-encoded block hash or height of the block. If not given, the last block added to the chain as known at the given node will be used")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Important response fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'"result"."block"."header"."state_root_hash"')," - contains the ",(0,o.kt)("inlineCode",{parentName:"li"},"state-root-hash")," for this block")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Explore the JSON-RPC request and response generated."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Request"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": 3,\n "jsonrpc": "2.0",\n "method": "chain_get_block",\n "params": {\n "block_identifier": {\n "Hash": "7c7e9b0f087bba5ce6fc4bd067b57f69ea3c8109157a3ad7f6d98b8da77d97f9"\n }\n }\n}\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"JSON-RPC Response"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": 3,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "block": {\n "body": {\n "deploy_hashes": [],\n "proposer": "012c6775c0e9e09f93b9450f1c5348c5f6b97895b0f52bb438f781f96ba2675a94",\n "transfer_hashes": ["ec2d477a532e00b08cfa9447b7841a645a27d34ee12ec55318263617e5740713"]\n },\n "hash": "7c7e9b0f087bba5ce6fc4bd067b57f69ea3c8109157a3ad7f6d98b8da77d97f9",\n "header": {\n "accumulated_seed": "50b8ac019b7300cd1fdeec050310e61b900e9238aa879929745900a91bd0fc4f",\n "body_hash": "224076b19c04279ae9b97f620801d5ff40ba64f431fe0d5089ef7cb84fdff45a",\n "era_end": null,\n "era_id": 0,\n "height": 8,\n "parent_hash": "416f339c4c2ff299c64a4b3271c5ef2ac2297bb40a477ceacce1483451a4db16",\n "protocol_version": "1.0.0",\n "random_bit": true,\n "state_root_hash": "cfdbf775b6671de3787cfb1f62f0c5319605a7c1711d6ece4660b37e57e81aa3",\n "timestamp": "2021-04-20T18:04:42.368Z"\n },\n "proofs": [\n {\n "public_key": "010f50b0116f213ef65b99d1bd54483f92bf6131de2f8aceb7e3f825a838292150",\n "signature": "130 chars"\n },\n {\n "public_key": "012c6775c0e9e09f93b9450f1c5348c5f6b97895b0f52bb438f781f96ba2675a94",\n "signature": "130 chars"\n },\n {\n "public_key": "018d5da83f22c9b65cdfdf9f9fdf9f7c98aa2b8c7bcf14bf855177bbb9c1ac7f0a",\n "signature": "130 chars"\n },\n {\n "public_key": "01b9088b92c8a8d592f6ec8c3e8153d7c55fc0c38b5999a214e37e73a2edd6fe0f",\n "signature": "130 chars"\n },\n {\n "public_key": "01b9e3484d96d5693e6c5fe789e7b28972aa392b054a76d175f079692967f604de",\n "signature": "130 chars"\n }\n ]\n }\n }\n}\n'))),(0,o.kt)("h2",{id:"querying-deploys"},"Querying Deploys"),(0,o.kt)("p",null,"Once you submit a deploy to the network, you can check its execution status using ",(0,o.kt)("inlineCode",{parentName:"p"},"get-deploy"),". If the ",(0,o.kt)("inlineCode",{parentName:"p"},"execution_results")," in the output are null, the transaction has not run yet. Note that transactions are finalized upon execution."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --id 2 \\\n --node-address http://:7777 \\\n \n")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Request fields:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"id")," - JSON-RPC identifier, applied to the request and returned in the response. If not provided, a random integer will be assigned"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"deploy-hash")," - Hex-encoded hash of the deploy")))}b.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a27f3afe.1685f38a.js b/assets/js/a27f3afe.1685f38a.js new file mode 100644 index 0000000000..3b44b0636e --- /dev/null +++ b/assets/js/a27f3afe.1685f38a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3055],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=l(n),h=r,m=p["".concat(c,".").concat(h)]||p[h]||d[h]||s;return n?a.createElement(m,o(o({ref:t},u),{},{components:n})):a.createElement(m,o({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,o=new Array(s);o[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[p]="string"==typeof e?e:r,o[1]=i;for(var l=2;lCargo.toml",id:"defining-dependencies-in-cargotoml",level:3},{value:"Writing the Tests",id:"writing-the-tests",level:2},{value:"Importing Builders and Constants",id:"importing-builders-and-constants",level:3},{value:"Creating a Test Function",id:"creating-a-test-function",level:3},{value:"Installing the Contract",id:"installing-the-contract",level:4},{value:"Calling the Contract by Hash",id:"calling-the-contract-by-hash",level:4},{value:"Calling the Contract using Session Code",id:"calling-the-contract-using-session-code",level:4},{value:"Evaluating and Comparing Results",id:"evaluating-and-comparing-results",level:4},{value:"Testing Contracts that Call Contracts",id:"testing-contracts-that-call-contracts",level:2},{value:"Running the Tests",id:"running-the-tests",level:2},{value:"Video Walkthrough",id:"video-walkthrough",level:2},{value:"Further Testing",id:"further-testing",level:2},{value:"What's Next?",id:"whats-next",level:2}],d={toc:p},h="wrapper";function m(e){var t=e.components,n=(0,r.Z)(e,o);return(0,s.kt)(h,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"testing-smart-contracts"},"Testing Smart Contracts"),(0,s.kt)("h2",{id:"introduction"},"Introduction"),(0,s.kt)("p",null,"As part of the Casper development environment, we provide a ",(0,s.kt)("a",{parentName:"p",href:"https://docs.rs/casper-engine-test-support/latest/casper_engine_test_support/"},"testing framework")," to test new contracts without running a full node. The framework creates an instance of the Casper execution engine, which can confirm successful deploys and monitor changes to global state using assertions. The Casper test crate must be included within the Rust workspace alongside the Wasm-producing crate to be validated."),(0,s.kt)("admonition",{type:"note"},(0,s.kt)("p",{parentName:"admonition"},"The Casper test support crate is one of many options for testing contracts before sending them to a Casper network. If you prefer, you can create your own testing framework.")),(0,s.kt)("h3",{id:"defining-dependencies-in-cargotoml"},"Defining Dependencies in ",(0,s.kt)("inlineCode",{parentName:"h3"},"Cargo.toml")),(0,s.kt)("p",null,"This guide uses the project structure, and example contract outlined ",(0,s.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract#directory-structure"},"here")," for creating tests."),(0,s.kt)("p",null,"To begin, outline the required test dependencies in the ",(0,s.kt)("inlineCode",{parentName:"p"},"/tests/Cargo.toml")," file. Specify the dependencies for your tests similarly and update the crate versions. Dependencies may vary with each project. For the counter tests, we have the following dependencies:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'[dependencies]\ncasper-execution-engine = "2.0.1"\ncasper-engine-test-support = { version = "2.2.0", features = ["test-support"] }\ncasper-types = "1.5.0"\n')),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"casper-execution-engine")," - This crate imports the execution engine functionality, enabling Wasm execution within the test framework. Each node contains an instance of an execution engine, and the testing framework simulates this behavior."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"casper-engine-test-support")," - A helper crate that provides the interface to write tests and interact with an instance of the execution engine."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"casper-types")," - Types shared by many Casper crates for use on a Casper network.")),(0,s.kt)("h2",{id:"writing-the-tests"},"Writing the Tests"),(0,s.kt)("p",null,"The tests for the contract usually reside in the ",(0,s.kt)("inlineCode",{parentName:"p"},"tests")," directory. Tests for the counter contract reside in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/tests/src/integration_tests.rs"},"tests/src/integration-tests.rs")," file. Notice that this file contains an empty ",(0,s.kt)("inlineCode",{parentName:"p"},"main")," method to initialize the test program. Alternatively, we could use the ",(0,s.kt)("inlineCode",{parentName:"p"},"#![no_main]")," annotation at the top of the file, as we did ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/8a622cd92d768893b9ef9fc2b150c674415be87e/contract-v1/src/main.rs#L1-L2"},"here"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'fn main() {\n panic!("Execute \\"cargo test\\" to test the contract, not \\"cargo run\\".");\n}\n')),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"#[cfg(test)]")," attribute tells the Rust compiler to compile and run the tests only when invoking ",(0,s.kt)("inlineCode",{parentName:"p"},"cargo test"),", not while debugging or releasing. All testing functions reside within the grouping mechanism ",(0,s.kt)("inlineCode",{parentName:"p"},"mod tests"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"#[cfg(test)]\nmod tests {\n // The entire test program resides here\n}\n")),(0,s.kt)("h3",{id:"importing-builders-and-constants"},"Importing Builders and Constants"),(0,s.kt)("p",null,"Import external test support, which includes a variety of default values and helper methods to be used throughout the test. Additionally, you will need to import any ",(0,s.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_cl"},"CLTypes")," used within the contract code to be tested."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," // Outlining aspects of the Casper test support crate to include.\n use casper_engine_test_support::{\n ExecuteRequestBuilder, InMemoryWasmTestBuilder, DEFAULT_ACCOUNT_ADDR,\n DEFAULT_RUN_GENESIS_REQUEST,\n };\n // Custom Casper types that will be used within this test.\n use casper_types::{runtime_args, ContractHash, RuntimeArgs};\n")),(0,s.kt)("p",null,"Next, you need to define any global variables or constants for the test."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},' const COUNTER_V1_WASM: &str = "counter-v1.wasm"; // The first version of the contract\n const COUNTER_V2_WASM: &str = "counter-v2.wasm"; // The second version of the contract\n const COUNTER_CALL_WASM: &str = "counter-call.wasm"; // Session code that calls the contract\n\n const CONTRACT_KEY: &str = "counter"; // Named key referencing this contract\n const COUNT_KEY: &str = "count"; // Named key referencing the value to increment/decrement\n const CONTRACT_VERSION_KEY: &str = "version"; // Key maintaining the version of a contract package\n\n const ENTRY_POINT_COUNTER_DECREMENT: &str = "counter_decrement"; // Entry point to decrement the count value\n const ENTRY_POINT_COUNTER_INC: &str = "counter_inc"; // Entry point to increment the count value\n')),(0,s.kt)("h3",{id:"creating-a-test-function"},"Creating a Test Function"),(0,s.kt)("p",null,"Each test function installs the contract and calls entry points to assert that the contract's behavior matches expectations. The test uses the ",(0,s.kt)("inlineCode",{parentName:"p"},"InMemoryWasmTestBuilder")," to invoke an instance of the execution engine, effectively simulating the process of installing the contract on the chain."),(0,s.kt)("p",null,"As part of this process, we use the ",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_RUN_GENESIS_REQUEST")," to install the system contracts necessary for the tests, including the ",(0,s.kt)("inlineCode",{parentName:"p"},"Mint"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"Auction"),", and ",(0,s.kt)("inlineCode",{parentName:"p"},"HandlePayment"),"contracts, as well as establishing a default account and funding the associated purse."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," #[test]\n /// Install version 1 of the counter contract and check its available entry points. ...\n fn install_version1_and_check_entry_points() {\n let mut builder = InMemoryWasmTestBuilder::default();\n builder.run_genesis(&*DEFAULT_RUN_GENESIS_REQUEST).commit();\n\n // See the repository for the full function.\n }\n")),(0,s.kt)("h4",{id:"installing-the-contract"},"Installing the Contract"),(0,s.kt)("p",null,"Test functions use the ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder")," to install a contract to be tested. In the counter tests, we use standard dependencies and the counter contract. Within the execution request, we specify the ",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR")," established by our genesis builder as the account sending the Deploy."),(0,s.kt)("p",null,"After building the ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder")," (in this example, ",(0,s.kt)("inlineCode",{parentName:"p"},"contract_installation_request"),"), we process the request through ",(0,s.kt)("inlineCode",{parentName:"p"},"builder.exec")," and then add and process other requests as necessary."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," // Install the contract.\n let contract_v1_installation_request = ExecuteRequestBuilder::standard(\n *DEFAULT_ACCOUNT_ADDR,\n COUNTER_V1_WASM,\n runtime_args! {},\n )\n .build();\n\n builder\n .exec(contract_v1_installation_request)\n .expect_success()\n .commit();\n")),(0,s.kt)("h4",{id:"calling-the-contract-by-hash"},"Calling the Contract by Hash"),(0,s.kt)("p",null,"To verify the installed contract, we need its contract hash. The test will then call its entry points using the ",(0,s.kt)("inlineCode",{parentName:"p"},"contract_call_by_hash")," function. The following code retrieves the contract hash from the named keys of the ",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR")," that sent the installation Deploy."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},' // Check the contract hash.\n let contract_v1_hash = builder\n .get_expected_account(*DEFAULT_ACCOUNT_ADDR)\n .named_keys()\n .get(CONTRACT_KEY)\n .expect("must have contract hash key as part of contract creation")\n .into_hash()\n .map(ContractHash::new)\n .expect("must get contract hash");\n')),(0,s.kt)("p",null,"Next, we test an entry point that should not exist in the first version of the contract."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," // Call the decrement entry point, which should not be in version 1 before the upgrade.\n let contract_decrement_request = ExecuteRequestBuilder::contract_call_by_hash(\n *DEFAULT_ACCOUNT_ADDR,\n contract_v1_hash,\n ENTRY_POINT_COUNTER_DECREMENT,\n runtime_args! {},\n )\n .build();\n\n // Try executing the decrement entry point and expect an error.\n builder\n .exec(contract_decrement_request)\n .expect_failure()\n .commit();\n")),(0,s.kt)("h4",{id:"calling-the-contract-using-session-code"},"Calling the Contract using Session Code"),(0,s.kt)("p",null,"In the counter example, we use the session code included in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/counter-call/src/main.rs"},"counter-call.wasm")," file. For more details on what session code is and how it differs from contract code, see the ",(0,s.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"next section"),"."),(0,s.kt)("p",null,"The following session code uses the contract hash to identify the contract, the account for sending the deploy (",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR"),"), the deploy to be sent (",(0,s.kt)("inlineCode",{parentName:"p"},"COUNTER_CALL_WASM"),"), and the runtime arguments required. Once again, the ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder")," simulates the execution of session code and calls the ",(0,s.kt)("inlineCode",{parentName:"p"},"counter-inc")," entry point."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," // Use session code to increment the counter.\n let session_code_request = ExecuteRequestBuilder::standard(\n *DEFAULT_ACCOUNT_ADDR,\n COUNTER_CALL_WASM,\n runtime_args! {\n CONTRACT_KEY => contract_v1_hash\n },\n )\n .build();\n\n builder.exec(session_code_request)\n .expect_success()\n .commit();\n")),(0,s.kt)("h4",{id:"evaluating-and-comparing-results"},"Evaluating and Comparing Results"),(0,s.kt)("p",null,"After calling the contract, we should verify the results received to ensure the contract operated as intended. The ",(0,s.kt)("inlineCode",{parentName:"p"},"builder")," method retrieves the required information and converts it to the value type required. Then, ",(0,s.kt)("inlineCode",{parentName:"p"},"assert_eq!()")," compares the result against the expected value."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},' // Verify the value of count is now 1.\n let incremented_count = builder\n .query(None, count_key, &[])\n .expect("should be stored value.")\n .as_cl_value()\n .expect("should be cl value.")\n .clone()\n .into_t::()\n .expect("should be i32.");\n\n assert_eq!(incremented_count, 1);\n')),(0,s.kt)("p",null,"For more test examples, visit the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/test"},"casper-node")," GitHub repository."),(0,s.kt)("h2",{id:"testing-contracts-that-call-contracts"},"Testing Contracts that Call Contracts"),(0,s.kt)("p",null,"If the code to be tested involves multiple contracts, they must be installed within the test. The exceptions are system contracts installed as part of the ",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_RUN_GENESIS_REQUEST"),". The testing framework exists independently of any Casper network, so you will need access to the original contract installation code or the Wasm you wish to include."),(0,s.kt)("p",null,"Each contract installation will require an additional Wasm file installed through a ",(0,s.kt)("inlineCode",{parentName:"p"},"Deploy")," using ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder"),". Depending on your requirements as a smart contract author, you may need to use ",(0,s.kt)("a",{parentName:"p",href:"/resources/tutorials/advanced/return-values-tutorial"},"return values")," to interact with stacks of contracts. Interaction between contracts will require session code to initiate the process, as contracts will not execute actions autonomously."),(0,s.kt)("p",null,"The major difference between calling a contract from session code versus contract code is the ability to use non-standard dependencies for the ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder"),". Where session code must designate a Wasm file within the standard dependencies, contract code can use one of the four available options for calling other contracts, namely:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"contract_call_by_hash")," - Calling a contract by its ",(0,s.kt)("inlineCode",{parentName:"li"},"ContractHash"),"."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"contract_call_by_name")," - Calling a contract referenced by a named key in the signer's Account context."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"versioned_contract_call_by_hash")," - Calling a specific contract version using its ",(0,s.kt)("inlineCode",{parentName:"li"},"ContractHash"),"."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"versioned_contract_call_by_name")," - Calling a specific version of a contract referenced by a named key in the signer's Account context.")),(0,s.kt)("p",null,"The calling contract must also provide an entry point and any necessary runtime arguments in all cases."),(0,s.kt)("h2",{id:"running-the-tests"},"Running the Tests"),(0,s.kt)("p",null,"To run the tests, the counter example uses a ",(0,s.kt)("inlineCode",{parentName:"p"},"Makefile"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"make test\n")),(0,s.kt)("p",null,"Under the hood, the ",(0,s.kt)("inlineCode",{parentName:"p"},"Makefile")," generates a ",(0,s.kt)("inlineCode",{parentName:"p"},"tests/wasm")," folder, copies the Wasm files to the folder, and runs the tests using ",(0,s.kt)("inlineCode",{parentName:"p"},"cargo test"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"test: build-contract\n mkdir -p tests/wasm\n cp contract-v1/target/wasm32-unknown-unknown/release/counter-v1.wasm tests/wasm\n cp contract-v2/target/wasm32-unknown-unknown/release/counter-v2.wasm tests/wasm\n cp counter-call/target/wasm32-unknown-unknown/release/counter-call.wasm tests/wasm\n cd tests && cargo test\n")),(0,s.kt)("h2",{id:"video-walkthrough"},"Video Walkthrough"),(0,s.kt)("p",null,"The following brief video describes testing ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/"},"sample contract code"),"."),(0,s.kt)("p",{align:"center"},(0,s.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed?v=sUg0nh3K3iQ&list=PL8oWxbJ-csEqi5FP87EJZViE2aLz6X1Mj&index=7",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,s.kt)("h2",{id:"further-testing"},"Further Testing"),(0,s.kt)("p",null,"Unit testing is only one way to test contracts before installing them on a Casper network. After unit testing a contract, you may perform ",(0,s.kt)("a",{parentName:"p",href:"/developers/dapps/setup-nctl"},"local network testing")," using NCTL. This allows you to set up and control multiple local Casper nodes to perform ",(0,s.kt)("a",{parentName:"p",href:"/developers/dapps/nctl-test"},"testing in an other simulated network environment"),"."),(0,s.kt)("p",null,"You may also wish to test your contracts on the Casper ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"Testnet"),"."),(0,s.kt)("h2",{id:"whats-next"},"What's Next?"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"Understand ",(0,s.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session code")," and how it triggers a smart contract."),(0,s.kt)("li",{parentName:"ul"},"Learn to ",(0,s.kt)("a",{parentName:"li",href:"/developers/cli/installing-contracts"},"install a contract and query global state")," with the Casper command-line client.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a27f3afe.ab134fd8.js b/assets/js/a27f3afe.ab134fd8.js deleted file mode 100644 index 0e225bc4d5..0000000000 --- a/assets/js/a27f3afe.ab134fd8.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3055],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,c=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=l(n),h=r,m=p["".concat(c,".").concat(h)]||p[h]||d[h]||s;return n?a.createElement(m,o(o({ref:t},u),{},{components:n})):a.createElement(m,o({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,o=new Array(s);o[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[p]="string"==typeof e?e:r,o[1]=i;for(var l=2;lCargo.toml",id:"defining-dependencies-in-cargotoml",level:3},{value:"Writing the Tests",id:"writing-the-tests",level:2},{value:"Importing Builders and Constants",id:"importing-builders-and-constants",level:3},{value:"Creating a Test Function",id:"creating-a-test-function",level:3},{value:"Installing the Contract",id:"installing-the-contract",level:4},{value:"Calling the Contract by Hash",id:"calling-the-contract-by-hash",level:4},{value:"Calling the Contract using Session Code",id:"calling-the-contract-using-session-code",level:4},{value:"Evaluating and Comparing Results",id:"evaluating-and-comparing-results",level:4},{value:"Testing Contracts that Call Contracts",id:"testing-contracts-that-call-contracts",level:2},{value:"Running the Tests",id:"running-the-tests",level:2},{value:"Video Walkthrough",id:"video-walkthrough",level:2},{value:"Further Testing",id:"further-testing",level:2},{value:"What's Next?",id:"whats-next",level:2}],d={toc:p},h="wrapper";function m(e){var t=e.components,n=(0,r.Z)(e,o);return(0,s.kt)(h,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"testing-smart-contracts"},"Testing Smart Contracts"),(0,s.kt)("h2",{id:"introduction"},"Introduction"),(0,s.kt)("p",null,"As part of the Casper development environment, we provide a ",(0,s.kt)("a",{parentName:"p",href:"https://docs.rs/casper-engine-test-support/latest/casper_engine_test_support/"},"testing framework")," to test new contracts without running a full node. The framework creates an instance of the Casper execution engine, which can confirm successful deploys and monitor changes to global state using assertions. The Casper test crate must be included within the Rust workspace alongside the Wasm-producing crate to be validated."),(0,s.kt)("admonition",{type:"note"},(0,s.kt)("p",{parentName:"admonition"},"The Casper test support crate is one of many options for testing contracts before sending them to a Casper network. If you prefer, you can create your own testing framework.")),(0,s.kt)("h3",{id:"defining-dependencies-in-cargotoml"},"Defining Dependencies in ",(0,s.kt)("inlineCode",{parentName:"h3"},"Cargo.toml")),(0,s.kt)("p",null,"This guide uses the project structure, and example contract outlined ",(0,s.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract#directory-structure"},"here")," for creating tests."),(0,s.kt)("p",null,"To begin, outline the required test dependencies in the ",(0,s.kt)("inlineCode",{parentName:"p"},"/tests/Cargo.toml")," file. Specify the dependencies for your tests similarly and update the crate versions. Dependencies may vary with each project. For the counter tests, we have the following dependencies:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'[dependencies]\ncasper-execution-engine = "2.0.1"\ncasper-engine-test-support = { version = "2.2.0", features = ["test-support"] }\ncasper-types = "1.5.0"\n')),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"casper-execution-engine")," - This crate imports the execution engine functionality, enabling Wasm execution within the test framework. Each node contains an instance of an execution engine, and the testing framework simulates this behavior."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"casper-engine-test-support")," - A helper crate that provides the interface to write tests and interact with an instance of the execution engine."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"casper-types")," - Types shared by many Casper crates for use on a Casper network.")),(0,s.kt)("h2",{id:"writing-the-tests"},"Writing the Tests"),(0,s.kt)("p",null,"The tests for the contract usually reside in the ",(0,s.kt)("inlineCode",{parentName:"p"},"tests")," directory. Tests for the counter contract reside in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/tests/src/integration_tests.rs"},"tests/src/integration-tests.rs")," file. Notice that this file contains an empty ",(0,s.kt)("inlineCode",{parentName:"p"},"main")," method to initialize the test program. Alternatively, we could use the ",(0,s.kt)("inlineCode",{parentName:"p"},"#![no_main]")," annotation at the top of the file, as we did ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/8a622cd92d768893b9ef9fc2b150c674415be87e/contract-v1/src/main.rs#L1-L2"},"here"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'fn main() {\n panic!("Execute \\"cargo test\\" to test the contract, not \\"cargo run\\".");\n}\n')),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"#[cfg(test)]")," attribute tells the Rust compiler to compile and run the tests only when invoking ",(0,s.kt)("inlineCode",{parentName:"p"},"cargo test"),", not while debugging or releasing. All testing functions reside within the grouping mechanism ",(0,s.kt)("inlineCode",{parentName:"p"},"mod tests"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"#[cfg(test)]\nmod tests {\n // The entire test program resides here\n}\n")),(0,s.kt)("h3",{id:"importing-builders-and-constants"},"Importing Builders and Constants"),(0,s.kt)("p",null,"Import external test support, which includes a variety of default values and helper methods to be used throughout the test. Additionally, you will need to import any ",(0,s.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_cl"},"CLTypes")," used within the contract code to be tested."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," // Outlining aspects of the Casper test support crate to include.\n use casper_engine_test_support::{\n ExecuteRequestBuilder, InMemoryWasmTestBuilder, DEFAULT_ACCOUNT_ADDR,\n DEFAULT_RUN_GENESIS_REQUEST,\n };\n // Custom Casper types that will be used within this test.\n use casper_types::{runtime_args, ContractHash, RuntimeArgs};\n")),(0,s.kt)("p",null,"Next, you need to define any global variables or constants for the test."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},' const COUNTER_V1_WASM: &str = "counter-v1.wasm"; // The first version of the contract\n const COUNTER_V2_WASM: &str = "counter-v2.wasm"; // The second version of the contract\n const COUNTER_CALL_WASM: &str = "counter-call.wasm"; // Session code that calls the contract\n\n const CONTRACT_KEY: &str = "counter"; // Named key referencing this contract\n const COUNT_KEY: &str = "count"; // Named key referencing the value to increment/decrement\n const CONTRACT_VERSION_KEY: &str = "version"; // Key maintaining the version of a contract package\n\n const ENTRY_POINT_COUNTER_DECREMENT: &str = "counter_decrement"; // Entry point to decrement the count value\n const ENTRY_POINT_COUNTER_INC: &str = "counter_inc"; // Entry point to increment the count value\n')),(0,s.kt)("h3",{id:"creating-a-test-function"},"Creating a Test Function"),(0,s.kt)("p",null,"Each test function installs the contract and calls entry points to assert that the contract's behavior matches expectations. The test uses the ",(0,s.kt)("inlineCode",{parentName:"p"},"InMemoryWasmTestBuilder")," to invoke an instance of the execution engine, effectively simulating the process of installing the contract on the chain."),(0,s.kt)("p",null,"As part of this process, we use the ",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_RUN_GENESIS_REQUEST")," to install the system contracts necessary for the tests, including the ",(0,s.kt)("inlineCode",{parentName:"p"},"Mint"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"Auction"),", and ",(0,s.kt)("inlineCode",{parentName:"p"},"HandlePayment"),"contracts, as well as establishing a default account and funding the associated purse."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," #[test]\n /// Install version 1 of the counter contract and check its available entry points. ...\n fn install_version1_and_check_entry_points() {\n let mut builder = InMemoryWasmTestBuilder::default();\n builder.run_genesis(&*DEFAULT_RUN_GENESIS_REQUEST).commit();\n\n // See the repository for the full function.\n }\n")),(0,s.kt)("h4",{id:"installing-the-contract"},"Installing the Contract"),(0,s.kt)("p",null,"Test functions use the ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder")," to install a contract to be tested. In the counter tests, we use standard dependencies and the counter contract. Within the execution request, we specify the ",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR")," established by our genesis builder as the account sending the Deploy."),(0,s.kt)("p",null,"After building the ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder")," (in this example, ",(0,s.kt)("inlineCode",{parentName:"p"},"contract_installation_request"),"), we process the request through ",(0,s.kt)("inlineCode",{parentName:"p"},"builder.exec")," and then add and process other requests as necessary."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," // Install the contract.\n let contract_v1_installation_request = ExecuteRequestBuilder::standard(\n *DEFAULT_ACCOUNT_ADDR,\n COUNTER_V1_WASM,\n runtime_args! {},\n )\n .build();\n\n builder\n .exec(contract_v1_installation_request)\n .expect_success()\n .commit();\n")),(0,s.kt)("h4",{id:"calling-the-contract-by-hash"},"Calling the Contract by Hash"),(0,s.kt)("p",null,"To verify the installed contract, we need its contract hash. The test will then call its entry points using the ",(0,s.kt)("inlineCode",{parentName:"p"},"contract_call_by_hash")," function. The following code retrieves the contract hash from the named keys of the ",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR")," that sent the installation Deploy."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},' // Check the contract hash.\n let contract_v1_hash = builder\n .get_expected_account(*DEFAULT_ACCOUNT_ADDR)\n .named_keys()\n .get(CONTRACT_KEY)\n .expect("must have contract hash key as part of contract creation")\n .into_hash()\n .map(ContractHash::new)\n .expect("must get contract hash");\n')),(0,s.kt)("p",null,"Next, we test an entry point that should not exist in the first version of the contract."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," // Call the decrement entry point, which should not be in version 1 before the upgrade.\n let contract_decrement_request = ExecuteRequestBuilder::contract_call_by_hash(\n *DEFAULT_ACCOUNT_ADDR,\n contract_v1_hash,\n ENTRY_POINT_COUNTER_DECREMENT,\n runtime_args! {},\n )\n .build();\n\n // Try executing the decrement entry point and expect an error.\n builder\n .exec(contract_decrement_request)\n .expect_failure()\n .commit();\n")),(0,s.kt)("h4",{id:"calling-the-contract-using-session-code"},"Calling the Contract using Session Code"),(0,s.kt)("p",null,"In the counter example, we use the session code included in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/counter-call/src/main.rs"},"counter-call.wasm")," file. For more details on what session code is and how it differs from contract code, see the ",(0,s.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"next section"),"."),(0,s.kt)("p",null,"The following session code uses the contract hash to identify the contract, the account for sending the deploy (",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_ACCOUNT_ADDR"),"), the deploy to be sent (",(0,s.kt)("inlineCode",{parentName:"p"},"COUNTER_CALL_WASM"),"), and the runtime arguments required. Once again, the ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder")," simulates the execution of session code and calls the ",(0,s.kt)("inlineCode",{parentName:"p"},"counter-inc")," entry point."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"}," // Use session code to increment the counter.\n let session_code_request = ExecuteRequestBuilder::standard(\n *DEFAULT_ACCOUNT_ADDR,\n COUNTER_CALL_WASM,\n runtime_args! {\n CONTRACT_KEY => contract_v1_hash\n },\n )\n .build();\n\n builder.exec(session_code_request)\n .expect_success()\n .commit();\n")),(0,s.kt)("h4",{id:"evaluating-and-comparing-results"},"Evaluating and Comparing Results"),(0,s.kt)("p",null,"After calling the contract, we should verify the results received to ensure the contract operated as intended. The ",(0,s.kt)("inlineCode",{parentName:"p"},"builder")," method retrieves the required information and converts it to the value type required. Then, ",(0,s.kt)("inlineCode",{parentName:"p"},"assert_eq!()")," compares the result against the expected value."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},' // Verify the value of count is now 1.\n let incremented_count = builder\n .query(None, count_key, &[])\n .expect("should be stored value.")\n .as_cl_value()\n .expect("should be cl value.")\n .clone()\n .into_t::()\n .expect("should be i32.");\n\n assert_eq!(incremented_count, 1);\n')),(0,s.kt)("p",null,"For more test examples, visit the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/tree/dev/smart_contracts/contracts/test"},"casper-node")," GitHub repository."),(0,s.kt)("h2",{id:"testing-contracts-that-call-contracts"},"Testing Contracts that Call Contracts"),(0,s.kt)("p",null,"If the code to be tested involves multiple contracts, they must be installed within the test. The exceptions are system contracts installed as part of the ",(0,s.kt)("inlineCode",{parentName:"p"},"DEFAULT_RUN_GENESIS_REQUEST"),". The testing framework exists independently of any Casper network, so you will need access to the original contract installation code or the Wasm you wish to include."),(0,s.kt)("p",null,"Each contract installation will require an additional Wasm file installed through a ",(0,s.kt)("inlineCode",{parentName:"p"},"Deploy")," using ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder"),". Depending on your requirements as a smart contract author, you may need to use ",(0,s.kt)("a",{parentName:"p",href:"/resources/tutorials/advanced/return-values-tutorial"},"return values")," to interact with stacks of contracts. Interaction between contracts will require session code to initiate the process, as contracts will not execute actions autonomously."),(0,s.kt)("p",null,"The major difference between calling a contract from session code versus contract code is the ability to use non-standard dependencies for the ",(0,s.kt)("inlineCode",{parentName:"p"},"ExecuteRequestBuilder"),". Where session code must designate a Wasm file within the standard dependencies, contract code can use one of the four available options for calling other contracts, namely:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"contract_call_by_hash")," - Calling a contract by its ",(0,s.kt)("inlineCode",{parentName:"li"},"ContractHash"),"."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"contract_call_by_name")," - Calling a contract referenced by a named key in the signer's Account context."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"versioned_contract_call_by_hash")," - Calling a specific contract version using its ",(0,s.kt)("inlineCode",{parentName:"li"},"ContractHash"),"."),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"versioned_contract_call_by_name")," - Calling a specific version of a contract referenced by a named key in the signer's Account context.")),(0,s.kt)("p",null,"The calling contract must also provide an entry point and any necessary runtime arguments in all cases."),(0,s.kt)("h2",{id:"running-the-tests"},"Running the Tests"),(0,s.kt)("p",null,"To run the tests, the counter example uses a ",(0,s.kt)("inlineCode",{parentName:"p"},"Makefile"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"make test\n")),(0,s.kt)("p",null,"Under the hood, the ",(0,s.kt)("inlineCode",{parentName:"p"},"Makefile")," generates a ",(0,s.kt)("inlineCode",{parentName:"p"},"tests/wasm")," folder, copies the Wasm files to the folder, and runs the tests using ",(0,s.kt)("inlineCode",{parentName:"p"},"cargo test"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"test: build-contract\n mkdir -p tests/wasm\n cp contract-v1/target/wasm32-unknown-unknown/release/counter-v1.wasm tests/wasm\n cp contract-v2/target/wasm32-unknown-unknown/release/counter-v2.wasm tests/wasm\n cp counter-call/target/wasm32-unknown-unknown/release/counter-call.wasm tests/wasm\n cd tests && cargo test\n")),(0,s.kt)("h2",{id:"video-walkthrough"},"Video Walkthrough"),(0,s.kt)("p",null,"The following brief video describes testing ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/"},"sample contract code"),"."),(0,s.kt)("p",{align:"center"},(0,s.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed?v=sUg0nh3K3iQ&list=PL8oWxbJ-csEqi5FP87EJZViE2aLz6X1Mj&index=7",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,s.kt)("h2",{id:"further-testing"},"Further Testing"),(0,s.kt)("p",null,"Unit testing is only one way to test contracts before installing them on a Casper network. After unit testing a contract, you may perform ",(0,s.kt)("a",{parentName:"p",href:"/developers/dapps/setup-nctl"},"local network testing")," using NCTL. This allows you to set up and control multiple local Casper nodes to perform ",(0,s.kt)("a",{parentName:"p",href:"/developers/dapps/nctl-test"},"testing in an other simulated network environment"),"."),(0,s.kt)("p",null,"You may also wish to test your contracts on the Casper ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"Testnet"),"."),(0,s.kt)("h2",{id:"whats-next"},"What's Next?"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"Understand ",(0,s.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session code")," and how it triggers a smart contract."),(0,s.kt)("li",{parentName:"ul"},"Learn to ",(0,s.kt)("a",{parentName:"li",href:"/developers/cli/installing-contracts"},"install a contract and query global state")," with the Casper command-line client.")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a2831d13.7c52010a.js b/assets/js/a2831d13.7c52010a.js deleted file mode 100644 index aa50782f77..0000000000 --- a/assets/js/a2831d13.7c52010a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5826],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),h=a,m=u["".concat(l,".").concat(h)]||u[h]||d[h]||r;return n?o.createElement(m,i(i({ref:t},p),{},{components:n})):o.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var c=2;c}\\_m{modulo}\\_p{}"'),". Once again using the 2,350th token as an example, the receipt would read:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cep78_collection_m_350_p_2\n")),(0,r.kt)("p",null,"You can determine the token number by multiplying the ",(0,r.kt)("inlineCode",{parentName:"p"},"page_number")," by the ",(0,r.kt)("inlineCode",{parentName:"p"},"page_size"),"(1,000) and adding the ",(0,r.kt)("inlineCode",{parentName:"p"},"modulo"),"."),(0,r.kt)("p",null,"If the ",(0,r.kt)("inlineCode",{parentName:"p"},"NFTIdentifierMode")," is set to ",(0,r.kt)("inlineCode",{parentName:"p"},"Ordinal"),", this number corresponds directly to the token ID."),(0,r.kt)("p",null,"If it is set to ",(0,r.kt)("inlineCode",{parentName:"p"},"Hash"),", you will need to reference the ",(0,r.kt)("inlineCode",{parentName:"p"},"HASH_BY_INDEX")," dictionary to determine the mapping of token numbers to token hashes."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a2831d13.c42a8c60.js b/assets/js/a2831d13.c42a8c60.js new file mode 100644 index 0000000000..7b83a2a17d --- /dev/null +++ b/assets/js/a2831d13.c42a8c60.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5826],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),h=a,m=u["".concat(l,".").concat(h)]||u[h]||d[h]||r;return n?o.createElement(m,i(i({ref:t},p),{},{components:n})):o.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var c=2;c}\\_m{modulo}\\_p{}"'),". Once again using the 2,350th token as an example, the receipt would read:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"cep78_collection_m_350_p_2\n")),(0,r.kt)("p",null,"You can determine the token number by multiplying the ",(0,r.kt)("inlineCode",{parentName:"p"},"page_number")," by the ",(0,r.kt)("inlineCode",{parentName:"p"},"page_size"),"(1,000) and adding the ",(0,r.kt)("inlineCode",{parentName:"p"},"modulo"),"."),(0,r.kt)("p",null,"If the ",(0,r.kt)("inlineCode",{parentName:"p"},"NFTIdentifierMode")," is set to ",(0,r.kt)("inlineCode",{parentName:"p"},"Ordinal"),", this number corresponds directly to the token ID."),(0,r.kt)("p",null,"If it is set to ",(0,r.kt)("inlineCode",{parentName:"p"},"Hash"),", you will need to reference the ",(0,r.kt)("inlineCode",{parentName:"p"},"HASH_BY_INDEX")," dictionary to determine the mapping of token numbers to token hashes."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a45056cf.1c475a77.js b/assets/js/a45056cf.1c475a77.js deleted file mode 100644 index c2e8e32166..0000000000 --- a/assets/js/a45056cf.1c475a77.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6563],{3905:function(e,t,r){r.d(t,{Zo:function(){return l},kt:function(){return h}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),i=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},l=function(e){var t=i(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=i(r),y=a,h=u["".concat(p,".").concat(y)]||u[y]||f[y]||o;return r?n.createElement(h,s(s({ref:t},l),{},{components:r})):n.createElement(h,s({ref:t},l))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var i=2;i=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),i=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},l=function(e){var t=i(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=i(r),y=a,h=u["".concat(p,".").concat(y)]||u[y]||f[y]||o;return r?n.createElement(h,s(s({ref:t},l),{},{components:r})):n.createElement(h,s({ref:t},l))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var i=2;i=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),p=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(i.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,i=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,f=d["".concat(i,".").concat(m)]||d[m]||u[m]||s;return n?a.createElement(f,l(l({ref:t},c),{},{components:n})):a.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,l=new Array(s);l[0]=m;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[d]="string"==typeof e?e:r,l[1]=o;for(var p=2;p=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),p=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(i.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,i=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=p(n),m=r,f=d["".concat(i,".").concat(m)]||d[m]||u[m]||s;return n?a.createElement(f,l(l({ref:t},c),{},{components:n})):a.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,l=new Array(s);l[0]=m;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[d]="string"==typeof e?e:r,l[1]=o;for(var p=2;p=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var i=n.createContext({}),p=function(e){var r=n.useContext(i),t=r;return e&&(t="function"==typeof e?e(r):s(s({},r),e)),t},l=function(e){var r=p(e.components);return n.createElement(i.Provider,{value:r},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=p(t),m=o,f=u["".concat(i,".").concat(m)]||u[m]||d[m]||a;return t?n.createElement(f,s(s({ref:r},l),{},{components:t})):n.createElement(f,s({ref:r},l))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,s=new Array(a);s[0]=m;var c={};for(var i in r)hasOwnProperty.call(r,i)&&(c[i]=r[i]);c.originalType=e,c[u]="string"==typeof e?e:o,s[1]=c;for(var p=2;p=0||(o[t]=e[t]);return o}(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var i=n.createContext({}),p=function(e){var r=n.useContext(i),t=r;return e&&(t="function"==typeof e?e(r):s(s({},r),e)),t},l=function(e){var r=p(e.components);return n.createElement(i.Provider,{value:r},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var r=e.children;return n.createElement(n.Fragment,{},r)}},m=n.forwardRef((function(e,r){var t=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=p(t),m=o,f=u["".concat(i,".").concat(m)]||u[m]||d[m]||a;return t?n.createElement(f,s(s({ref:r},l),{},{components:t})):n.createElement(f,s({ref:r},l))}));function f(e,r){var t=arguments,o=r&&r.mdxType;if("string"==typeof e||o){var a=t.length,s=new Array(a);s[0]=m;var c={};for(var i in r)hasOwnProperty.call(r,i)&&(c[i]=r[i]);c.originalType=e,c[u]="string"==typeof e?e:o,s[1]=c;for(var p=2;p=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=p(n),m=o,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return n?r.createElement(f,s(s({ref:t},l),{},{components:n})):r.createElement(f,s({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var p=2;p=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=p(n),m=o,f=u["".concat(c,".").concat(m)]||u[m]||d[m]||a;return n?r.createElement(f,s(s({ref:t},l),{},{components:n})):r.createElement(f,s({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var p=2;p=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=d(n),m=r,f=p["".concat(s,".").concat(m)]||p[m]||u[m]||i;return n?a.createElement(f,l(l({ref:t},c),{},{components:n})):a.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,l=new Array(i);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:r,l[1]=o;for(var d=2;d child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function u(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:p(n);return function(e){var t=(0,d.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function f(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,i=(0,o.k6)(),l=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,s._X)(l),(0,r.useCallback)((function(e){if(l){var t=new URLSearchParams(i.location.search);t.set(l,e),i.replace(Object.assign({},i.location,{search:t.toString()}))}}),[l,i])]}function h(e){var t,n,a,i,l=e.defaultValue,o=e.queryString,s=void 0!==o&&o,d=e.groupId,p=u(e),h=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:l,tabValues:p})})),v=h[0],k=h[1],b=f({queryString:s,groupId:d}),y=b[0],g=b[1],N=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:d}.groupId),n=(0,c.Nk)(t),a=n[0],i=n[1],[a,(0,r.useCallback)((function(e){t&&i.set(e)}),[t,i])]),w=N[0],E=N[1],T=function(){var e=null!=y?y:w;return m({value:e,tabValues:p})?e:null}();return(0,r.useLayoutEffect)((function(){T&&k(T)}),[T]),{selectedValue:v,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:p}))throw new Error("Can't select invalid tab value="+e);k(e),g(e),E(e)}),[g,E,p]),tabValues:p}}var v=n(2389),k={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function b(e){var t=e.className,n=e.block,o=e.selectedValue,s=e.selectValue,d=e.tabValues,c=[],p=(0,l.o5)().blockElementScrollPositionUntilNextRender,u=function(e){var t=e.currentTarget,n=c.indexOf(t),a=d[n].value;a!==o&&(p(t),s(a))},m=function(e){var t,n=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":var a,r=c.indexOf(e.currentTarget)+1;n=null!=(a=c[r])?a:c[0];break;case"ArrowLeft":var i,l=c.indexOf(e.currentTarget)-1;n=null!=(i=c[l])?i:c[c.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":n},t)},d.map((function(e){var t=e.value,n=e.label,l=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:o===t?0:-1,"aria-selected":o===t,key:t,ref:function(e){return c.push(e)},onKeyDown:m,onClick:u},l,{className:(0,i.Z)("tabs__item",k.tabItem,null==l?void 0:l.className,{"tabs__item--active":o===t})}),null!=n?n:t)})))}function y(e){var t=e.lazy,n=e.children,a=e.selectedValue,i=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var l=i.find((function(e){return e.props.value===a}));return l?(0,r.cloneElement)(l,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},i.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function g(e){var t=h(e);return r.createElement("div",{className:(0,i.Z)("tabs-container",k.tabList)},r.createElement(b,(0,a.Z)({},e,t)),r.createElement(y,(0,a.Z)({},e,t)))}function N(e){var t=(0,v.Z)();return r.createElement(g,(0,a.Z)({key:String(t)},e))}},9827:function(e,t,n){n.r(t),n.d(t,{assets:function(){return u},contentTitle:function(){return c},default:function(){return v},frontMatter:function(){return d},metadata:function(){return p},toc:function(){return m}});var a=n(7462),r=n(3366),i=(n(7294),n(3905)),l=n(4866),o=n(5162),s=["components"],d={},c="Monitoring and Consuming Events",p={unversionedId:"developers/dapps/monitor-and-consume-events",id:"developers/dapps/monitor-and-consume-events",title:"Monitoring and Consuming Events",description:"The Casper platform uses event streaming to signal state changes in smart contracts and nodes. Using Casper's client-side SDKs, dApps actively listening for emitted events can consume these events and perform actions based on event data.",source:"@site/source/docs/casper/developers/dapps/monitor-and-consume-events.md",sourceDirName:"developers/dapps",slug:"/developers/dapps/monitor-and-consume-events",permalink:"/developers/dapps/monitor-and-consume-events",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/dapps/monitor-and-consume-events.md",tags:[],version:"current",lastUpdatedAt:1707229568,formattedLastUpdatedAt:"Feb 6, 2024",frontMatter:{},sidebar:"developers",previous:{title:"Local Network Testing",permalink:"/developers/dapps/nctl-test"},next:{title:"Interacting with the Blockchain",permalink:"/developers/cli/"}},u={},m=[{value:"Listening to the Event Stream",id:"listening-to-the-event-stream",level:2},{value:"Event Types",id:"event-types",level:2},{value:"ApiVersion",id:"apiversion",level:3},{value:"BlockAdded",id:"blockadded",level:3},{value:"DeployAccepted",id:"deployaccepted",level:3},{value:"DeployProcessed",id:"deployprocessed",level:3},{value:"DeployExpired",id:"deployexpired",level:3},{value:"Fault",id:"fault",level:3},{value:"FinalitySignature",id:"finalitysignature",level:3},{value:"Step",id:"step",level:3},{value:"Shutdown",id:"shutdown",level:3},{value:"Reacting to Events",id:"reacting-to-events",level:2},{value:"Unsubscribing from Events",id:"unsubscribing-from-events",level:2},{value:"Stopping the Event Stream",id:"stopping-the-event-stream",level:2},{value:"Replaying the Event Stream",id:"replaying-the-event-stream",level:2}],f={toc:m},h="wrapper";function v(e){var t=e.components,n=(0,r.Z)(e,s);return(0,i.kt)(h,(0,a.Z)({},f,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"monitoring-and-consuming-events"},"Monitoring and Consuming Events"),(0,i.kt)("p",null,"The Casper platform uses event streaming to signal state changes in smart contracts and nodes. Using Casper's client-side SDKs, dApps actively listening for emitted events can consume these events and perform actions based on event data."),(0,i.kt)("p",null,"Each Casper node streams events through the SSE (Server Sent Event) server via the port specified as the ",(0,i.kt)("inlineCode",{parentName:"p"},"event_stream_server.address")," in the node's ",(0,i.kt)("em",{parentName:"p"},"config.toml"),". This port is by default ",(0,i.kt)("inlineCode",{parentName:"p"},"9999")," for nodes on ",(0,i.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"Testnet")," and ",(0,i.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"Mainnet"),"."),(0,i.kt)("p",null,"Events are divided into three categories and streamed on their respective endpoints:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Deploy events")," - Associated with ",(0,i.kt)("a",{parentName:"li",href:"/concepts/design/casper-design#execution-semantics-deploys"},"Deploys")," on a node. Currently, only a ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployAccepted")," event is emitted. The URL to consume deploy-related events on Mainnet and Testnet is ",(0,i.kt)("inlineCode",{parentName:"li"},"http://:9999/events/deploys/"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Finality Signature events")," - Emitted when a block has been finalized and cannot be altered. The URL to consume finality signature events on Mainnet and Testnet is ",(0,i.kt)("inlineCode",{parentName:"li"},"http://:9999/events/sigs/"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Main events")," - All other events fall under this type, including: ",(0,i.kt)("inlineCode",{parentName:"li"},"BlockAdded"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployProcessed"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployExpired"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Fault"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Step"),", and ",(0,i.kt)("inlineCode",{parentName:"li"},"Shutdown")," events. The URL to consume these events on Mainnet and Testnet is ",(0,i.kt)("inlineCode",{parentName:"li"},"http://:9999/events/main/"),".")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"An ",(0,i.kt)("inlineCode",{parentName:"p"},"ApiVersion")," event is always emitted when a new client connects to a node's SSE server, informing the client of the node's software version.")),(0,i.kt)("h2",{id:"listening-to-the-event-stream"},"Listening to the Event Stream"),(0,i.kt)("p",null,"Applications can listen for such events for a specific account during a particular era, containing certain data. Then, they can parse the data and discard what they do not need. To consume the event stream, set up an event listener in your dApp using the following code:"),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},'const { EventStream, EventName } = require("casper-js-sdk");\n\nconst es = new EventStream("http://NODE_ADDRESS:9999/events/" + CHANNEL);\nes.start();\nes.subscribe(EventName.EVENT_NAME, eventHandler);\n\nconst eventHandler = (event) => {\n console.log(event);\n};\n'))),(0,i.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-python"},'from pycspr import NodeClient, NodeConnection, NodeEventChannel, NodeEventType\n\ndef eventHandler(event):\n print(event)\n\nclient = NodeClient(NodeConnection(host = "NODE_ADDRESS", port_rpc = 7777))\nclient.get_events(eventHandler, NodeEventChannel.CHANNEL, NodeEventType.EVENT_NAME)\n'))),(0,i.kt)(o.Z,{value:"curl",label:"cURL",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://NODE_ADDRESS:9999/events/CHANNEL\n")))),(0,i.kt)("p",null,"You can find node addresses of active online peers to replace ",(0,i.kt)("inlineCode",{parentName:"p"},"NODE_ADDRESS"),", by navigating to ",(0,i.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"cspr.live")," for Mainnet and ",(0,i.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"testnet.cspr.live")," for Testnet."),(0,i.kt)("p",null,"Replace ",(0,i.kt)("inlineCode",{parentName:"p"},"EVENT_NAME")," with one of the event types listed ",(0,i.kt)("a",{parentName:"p",href:"#event-types"},"below"),"."),(0,i.kt)("p",null,"Replace ",(0,i.kt)("inlineCode",{parentName:"p"},"CHANNEL")," with one of the following event streams:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"main")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"ApiVersion"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"BlockAdded"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployExpired"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployProcessed"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Fault"),", or ",(0,i.kt)("inlineCode",{parentName:"li"},"Step")," events."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"deploys")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployAccepted")," events."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sigs")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"FinalitySignature")," events.")),(0,i.kt)("h2",{id:"event-types"},"Event Types"),(0,i.kt)("h3",{id:"apiversion"},"ApiVersion"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ApiVersion")," event is always the first event emitted when a new client connects to a node's SSE server. It specifies the protocol version of a node on the Casper platform. The following example contains the JSON representation of the ",(0,i.kt)("inlineCode",{parentName:"p"},"ApiVersion")," event structure."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'data:{"ApiVersion":"1.0.0"}\n')),(0,i.kt)("h3",{id:"blockadded"},"BlockAdded"),(0,i.kt)("p",null,"A ",(0,i.kt)("inlineCode",{parentName:"p"},"BlockAdded")," event is emitted when a new block is added to the blockchain and stored locally in the node."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "BlockAdded": {\n "block_hash": "62ddf902e9b6988b978413e2a9a2c6c95f8e1ddf452afd8e8a68f0ac22bf391a",\n "block": {\n "hash": "62ddf105e9b6988b378413e2a9a2c6c95f8e1ddf458afd8e8268f0ac72bfe91a",\n "header": {\n "parent_hash": "ed11ac2117edb9c5b26cf0cde318a807fd68e76206855a70429012ef16b557f5",\n "state_root_hash": "3c1ad31757ae40f934de4825a818274e0c246d304c661daf656e22b65174ad66",\n "body_hash": "eb2344f37193395bbc83587e498bc12ad5f0019055abcfa4c3b989d382a7969a",\n "random_bit": true,\n "accumulated_seed": "b8b671530f2221c8fdf201083f43c51e215e2f6ffcbe2d63238a2779eb177922",\n "era_end": null,\n "timestamp": "2023-01-01T09:55:25.312Z",\n "era_id": 8426,\n "height": 1566677,\n "protocol_version": "1.4.13"\n },\n "body": {\n "proposer": "010e5669b0f0545e2b32bc66363b9d3d4390fca56bf52305f1411b7fa12ca311c7",\n "deploy_hashes": [],\n "transfer_hashes": []\n },\n "proofs": []\n }\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#block-hash"},"block_hash")," - The cryptographic hash that identifies a block."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-block"},"block")," - The JSON representation of the block."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#body"},"proposer")," - The validator selected to propose the block."))),(0,i.kt)("h3",{id:"deployaccepted"},"DeployAccepted"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"DeployAccepted")," events are emitted when a node on the network receives a deploy."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "DeployAccepted": {\n "hash": "db84ba229ea37716230ac9874f66c0f12b9731d8d42f28060e481ef3d7263ead",\n "header": {\n "account": "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c",\n "timestamp": "2023-01-01T20:22:45.383Z",\n "ttl": "30m",\n "gas_price": 1,\n "body_hash": "8a377b07a01ac23905b2e416ff388508301feffbb9bdf275c59f87be1e9d0de5",\n "dependencies": [],\n "chain_name": "casper-test"\n },\n "payment": {\n "ModuleBytes": {\n "module_bytes": "",\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "040008af2f",\n "parsed": "800000000"\n }\n ]\n ]\n }\n },\n "session": {\n "StoredContractByHash": {\n "hash": "1040f40d06f0355a80149befc4b5d1f203231231d66c4903688e178c36066539",\n "entry_point": "test_entry_point",\n "args": [\n [\n "cost",\n {\n "cl_type": "U512",\n "bytes": "0500c817a804",\n "parsed": "20000000000"\n }\n ]\n ]\n }\n },\n "approvals": [\n {\n "signer": "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c",\n "signature": "01d81d4dc9504a356c23d3c161b87b39b1708cd282b59d3e44d9b999e787643ab495f168475bed8dc48d1056605e06c8ba74d96c69ae5b506c4312be8871c0c701"\n }\n ]\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/hash-types"},"hash")," - The blake2b hash of the Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-account"},"account")," - The hexadecimal-encoded public key of the account submitting the Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/hash-types"},"body_hash")," - The blake2b hash of the Deploy body."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/glossary/P#payment-code"},"payment")," - Gas payment information."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session")," - The session logic defining the Deploy's functionality."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/developers/json-rpc/types_chain#approval"},"approvals")," - The signer's hexadecimal-encoded public key and signature."))),(0,i.kt)("p",null,"For details on custom serializations, check the ",(0,i.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"Serialization Standard"),". Also, the ",(0,i.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain"},"Types")," page defines the terms used in the event stream output."),(0,i.kt)("h3",{id:"deployprocessed"},"DeployProcessed"),(0,i.kt)("p",null,"A ",(0,i.kt)("inlineCode",{parentName:"p"},"DeployProcessed")," event is emitted when a given Deploy has been executed."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "DeployProcessed": {\n "deploy_hash": "0f33be8f56ff23d7d503a9804675472e043830a6c17e6141dce717b4f0973c7d",\n "account": "0201cbff12155b6ae1e99d571c01d56e9e1ba0def6719a6f06bc3e4a08f30a887444",\n "timestamp": "2023-01-01T10:07:00.401Z",\n "ttl": "30m",\n "dependencies": [],\n "block_hash": "509b754648168a73e6ab67e64d4a783cf580d6fc0c7c0ec560c6650f717841e0",\n "execution_result": {\n "Success": {\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "account-hash-a8261377ef9cf8e7411d6858801c71e28c9322e66355586549c75ab24cdd73f2",\n "transform": "Identity"\n }\n ]\n },\n "transfers": ["transfer-3389144d15238240f48f5966f2dc299b6b20eb19c13d834409b4d28fc50fa909"],\n "cost": "100000000"\n }\n }\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#deploy-hash"},"deploy_hash")," - The cryptographic hash of a Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-account"},"account")," - The hexadecimal-encoded public key of the account submitting the Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#timestamp"},"timestamp")," - A timestamp type representing a concrete moment in time."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#deploy-header"},"dependencies")," - A list of Deploy hashes."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#block-hash"},"block_hash")," - A cryptographic hash identifying a Block."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#executionresult"},"execution_result")," - The execution status of the Deploy, which is either ",(0,i.kt)("inlineCode",{parentName:"li"},"Success")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"Failure"),"."))),(0,i.kt)("h3",{id:"deployexpired"},"DeployExpired"),(0,i.kt)("p",null,"A ",(0,i.kt)("inlineCode",{parentName:"p"},"DeployExpired")," event is emitted when the Deploy is no longer valid for processing or being added to a block due to its time to live (TTL) having expired."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "DeployExpired": {\n "deploy_hash": "7ecf22fc284526d6db16fbf455f489e0a9cbf782234131c010cf3078fb9be353"\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#deploy-hash"},"deploy_hash")," - The cryptographic hash of a Deploy."))),(0,i.kt)("h3",{id:"fault"},"Fault"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Fault")," event is emitted if there is a validator error."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand the below section to view the Fault event details:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "Fault": {\n "era_id": 4591448806312642600,\n "public_key": "013da85eb06279da42e28530e1116be04bfd2aa25ed8d63401ebff4d9153a609a9",\n "timestamp": "2023-01-01T01:26:58.364Z"\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#eraid"},"era_id")," - A period of time during which the validator set does not change."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#publickey"},"public_key")," - The hexadecimal-encoded public key of the validator that caused the fault."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#timestamp"},"timestamp")," - A timestamp representing the moment the validator faulted."))),(0,i.kt)("h3",{id:"finalitysignature"},"FinalitySignature"),(0,i.kt)("p",null,"This event indicates validators have signed the final approvals and further alterations to the block will not be allowed. Refer to the ",(0,i.kt)("a",{parentName:"p",href:"/deploy-and-deploy-lifecycle#consensus-reached"},"consensus reached")," and ",(0,i.kt)("a",{parentName:"p",href:"/concepts/glossary/B#block-finality"},"block finality")," sections to learn more about finality signatures."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "FinalitySignature": {\n "block_hash": "eceed827e11f7969a7d3fe91d6fa4ce9749dd79d9f3ea26474fe2014db90e98d",\n "era_id": 8419,\n "signature": "0117087ef4b9a786e5a0ea8f198050e9de93dd94f87469b8124c346aeae5f36ad9adf80f670ee9c5887263267ed32cf932dce9b370353c596d59f91fbd57a1a205",\n "public_key": "01c375b425a36de25dc325c9182861679db2f634abcacd9ae2ee27b84ba62ac1f7"\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#block-hash"},"block_hash")," - A cryptographic hash identifying a Block."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#eraid"},"era_id")," - A period of time during which the validator set does not change."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#signature"},"signature")," - Serialized bytes representing the validator's signature."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#publickey"},"public_key")," - The hexadecimal-encoded public key of the validator."))),(0,i.kt)("h3",{id:"step"},"Step"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Step")," event is emitted at the end of every era and contains the execution effects produced by running the auction contract's ",(0,i.kt)("inlineCode",{parentName:"p"},"step")," function."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "Step": {\n "era_id": 1,\n "execution_effect": {\n "operations": [],\n "transforms": [\n {\n "key": "uref-53df18bf01396fbd1ef3a8757c7bdffc684c407d90f2cfeebff166db1d923613-000",\n "transform": "Identity"\n },\n {\n "key": "uref-f268de37fcea55f8fb1abeba8536a1cc041b2aed2691f1cf34aeaaf0ae379aa5-000",\n "transform": "Identity"\n },\n {\n "key": "bid-278e5af1ca6cddf5d5438999cb072b47f0d65e1484799f692c3c9c40304be30e",\n "transform": "Identity"\n },\n {\n "key": "bid-278e5af1ca6cddf5d5438999cb072b47f0d65e1484799f692c3c9c40304be30e",\n "transform": {\n "WriteBid": {\n "validator_public_key": "0133eaae2821f090ac3ba0eadc0a897742094c0604df72b465c41d4b773298a7b9",\n "bonding_purse": "uref-136552c255d4d737bf7e43d2be250f9f38691b9fe5d9e34446bff18d6d1cf984-007",\n "staked_amount": "1000000000000005",\n "delegation_rate": 5,\n "vesting_schedule": {\n "initial_release_timestamp_millis": 1664475057182,\n "locked_amounts": null\n },\n "delegators": {\n "012a241eaa9fa3bd6ccb0e0aaaf4658538f3540e04e2f58973614a168f2f2f813d": {\n "delegator_public_key": "012a241eaa9fa3bd6ccb0e0aaaf4658538f3540e04e2f58973614a168f2f2f813d",\n "staked_amount": "51312014671568117976319379",\n "bonding_purse": "uref-c5ad00f9e6b2f2631ca647ad188187e63799a278a0a46ca25f6b4da64d556662-007",\n "validator_public_key": "0133eaae2821f090ac3ba0eadc0a897742094c0604df72b465c41d4b773298a7b9",\n "vesting_schedule": {\n "initial_release_timestamp_millis": 1664475057182,\n "locked_amounts": null\n }\n }\n },\n "inactive": false\n }\n }\n }\n ]\n }\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#eraid"},"era_id")," - A period of time during which the validator set does not change."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#executioneffect"},"execution_effect")," - The journal of execution transforms from a single Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#operation"},"operations")," - Operations performed while executing a Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#transform"},"transform")," - The actual transformation performed while executing a Deploy."))),(0,i.kt)("h3",{id:"shutdown"},"Shutdown"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Shutdown")," event is emitted when the node is about to shut down, usually for an upgrade, causing a termination of the event stream."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand the below section to view the Shutdown event details:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'"Shutdown"\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'Shutdown - The "Shutdown" text notifies the event listener that a shutdown will occur.'))),(0,i.kt)("h2",{id:"reacting-to-events"},"Reacting to Events"),(0,i.kt)("p",null,"An application may parse each event needed for its use case and respond accordingly. The dApp may act on some events and not others, or it may act upon them all, depending on its use case. Each event type contains additional data that might help in deciding whether or not to take an action. For example, ",(0,i.kt)("inlineCode",{parentName:"p"},"DeployAccepted")," events contain the account's public key that submitted the deploy, the contract address, and more. This information can help determine how to proceed or whether or not to react."),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},'const eventHandler = (event) => {\n if (event.body.DeployAccepted.header.account == "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c") {\n // Perform an action\n }\n};\n'))),(0,i.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-python"},'def eventHandler(event):\n if event["DeployAccepted"]["header"]["account"] == "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c":\n # Perform an action\n')))),(0,i.kt)("h2",{id:"unsubscribing-from-events"},"Unsubscribing from Events"),(0,i.kt)("p",null,"In many cases, an application may need to unsubscribe after a certain time or may want to unsubscribe from some events but not others. The Casper SDKs provide this ability with the ",(0,i.kt)("inlineCode",{parentName:"p"},"unsubscribe")," function:"),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},"es.unsubscribe(EventName.EVENT_NAME);\n")))),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"EVENT_NAME")," - One of the different ",(0,i.kt)("a",{parentName:"li",href:"#event-types"},"event types")," emitted by a Casper node.")),(0,i.kt)("h2",{id:"stopping-the-event-stream"},"Stopping the Event Stream"),(0,i.kt)("p",null,"A dApp may cease listening to all events using the ",(0,i.kt)("inlineCode",{parentName:"p"},"stop")," function:"),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},"es.stop();\n")))),(0,i.kt)("h2",{id:"replaying-the-event-stream"},"Replaying the Event Stream"),(0,i.kt)("p",null,"This command will replay the event stream from an old event onward. Replace the ",(0,i.kt)("inlineCode",{parentName:"p"},"NODE_ADDRESS"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"CHANNEL"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"ID")," fields with the values of your scenario."),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"curl",label:"cURL",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"curl -sN http://NODE_ADDRESS:9999/events/CHANNEL?start_from=ID\n")),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"Example:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"curl -sN http://65.21.235.219:9999/events/main?start_from=29267508\n")))),(0,i.kt)("p",null,"Each URL can have a query string added to the form ",(0,i.kt)("inlineCode",{parentName:"p"},"?start_from=ID"),", where ID is an integer representing an old event ID. With this query, you can replay the event stream from that old event onward. If you specify an event ID already purged from the cache, the server will replay all the cached events."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"The server keeps only a limited number of events cached to allow replaying the stream to clients using the ",(0,i.kt)("inlineCode",{parentName:"p"},"?start_from=")," query string. The cache size can be set differently on each node using the ",(0,i.kt)("inlineCode",{parentName:"p"},"event_stream_buffer_length")," value in the ",(0,i.kt)("em",{parentName:"p"},"config.toml"),". By default, it is only 5000. The intended use case is to allow a client consuming the event stream that loses its connection to reconnect and catch up with events that were emitted while it was disconnected.")))}v.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a6d4c72e.d9f9eacc.js b/assets/js/a6d4c72e.d9f9eacc.js new file mode 100644 index 0000000000..27fff44692 --- /dev/null +++ b/assets/js/a6d4c72e.d9f9eacc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2691],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return f}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),p=d(n),m=r,f=p["".concat(s,".").concat(m)]||p[m]||u[m]||i;return n?a.createElement(f,l(l({ref:t},c),{},{components:n})):a.createElement(f,l({ref:t},c))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,l=new Array(i);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:r,l[1]=o;for(var d=2;d child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function u(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:p(n);return function(e){var t=(0,d.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function f(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,i=(0,o.k6)(),l=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,s._X)(l),(0,r.useCallback)((function(e){if(l){var t=new URLSearchParams(i.location.search);t.set(l,e),i.replace(Object.assign({},i.location,{search:t.toString()}))}}),[l,i])]}function h(e){var t,n,a,i,l=e.defaultValue,o=e.queryString,s=void 0!==o&&o,d=e.groupId,p=u(e),h=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:l,tabValues:p})})),v=h[0],k=h[1],b=f({queryString:s,groupId:d}),y=b[0],g=b[1],N=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:d}.groupId),n=(0,c.Nk)(t),a=n[0],i=n[1],[a,(0,r.useCallback)((function(e){t&&i.set(e)}),[t,i])]),w=N[0],E=N[1],T=function(){var e=null!=y?y:w;return m({value:e,tabValues:p})?e:null}();return(0,r.useLayoutEffect)((function(){T&&k(T)}),[T]),{selectedValue:v,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:p}))throw new Error("Can't select invalid tab value="+e);k(e),g(e),E(e)}),[g,E,p]),tabValues:p}}var v=n(2389),k={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function b(e){var t=e.className,n=e.block,o=e.selectedValue,s=e.selectValue,d=e.tabValues,c=[],p=(0,l.o5)().blockElementScrollPositionUntilNextRender,u=function(e){var t=e.currentTarget,n=c.indexOf(t),a=d[n].value;a!==o&&(p(t),s(a))},m=function(e){var t,n=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":var a,r=c.indexOf(e.currentTarget)+1;n=null!=(a=c[r])?a:c[0];break;case"ArrowLeft":var i,l=c.indexOf(e.currentTarget)-1;n=null!=(i=c[l])?i:c[c.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":n},t)},d.map((function(e){var t=e.value,n=e.label,l=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:o===t?0:-1,"aria-selected":o===t,key:t,ref:function(e){return c.push(e)},onKeyDown:m,onClick:u},l,{className:(0,i.Z)("tabs__item",k.tabItem,null==l?void 0:l.className,{"tabs__item--active":o===t})}),null!=n?n:t)})))}function y(e){var t=e.lazy,n=e.children,a=e.selectedValue,i=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var l=i.find((function(e){return e.props.value===a}));return l?(0,r.cloneElement)(l,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},i.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function g(e){var t=h(e);return r.createElement("div",{className:(0,i.Z)("tabs-container",k.tabList)},r.createElement(b,(0,a.Z)({},e,t)),r.createElement(y,(0,a.Z)({},e,t)))}function N(e){var t=(0,v.Z)();return r.createElement(g,(0,a.Z)({key:String(t)},e))}},9827:function(e,t,n){n.r(t),n.d(t,{assets:function(){return u},contentTitle:function(){return c},default:function(){return v},frontMatter:function(){return d},metadata:function(){return p},toc:function(){return m}});var a=n(7462),r=n(3366),i=(n(7294),n(3905)),l=n(4866),o=n(5162),s=["components"],d={},c="Monitoring and Consuming Events",p={unversionedId:"developers/dapps/monitor-and-consume-events",id:"developers/dapps/monitor-and-consume-events",title:"Monitoring and Consuming Events",description:"The Casper platform uses event streaming to signal state changes in smart contracts and nodes. Using Casper's client-side SDKs, dApps actively listening for emitted events can consume these events and perform actions based on event data.",source:"@site/source/docs/casper/developers/dapps/monitor-and-consume-events.md",sourceDirName:"developers/dapps",slug:"/developers/dapps/monitor-and-consume-events",permalink:"/developers/dapps/monitor-and-consume-events",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/dapps/monitor-and-consume-events.md",tags:[],version:"current",lastUpdatedAt:1707837031,formattedLastUpdatedAt:"Feb 13, 2024",frontMatter:{},sidebar:"developers",previous:{title:"Local Network Testing",permalink:"/developers/dapps/nctl-test"},next:{title:"Interacting with the Blockchain",permalink:"/developers/cli/"}},u={},m=[{value:"Listening to the Event Stream",id:"listening-to-the-event-stream",level:2},{value:"Event Types",id:"event-types",level:2},{value:"ApiVersion",id:"apiversion",level:3},{value:"BlockAdded",id:"blockadded",level:3},{value:"DeployAccepted",id:"deployaccepted",level:3},{value:"DeployProcessed",id:"deployprocessed",level:3},{value:"DeployExpired",id:"deployexpired",level:3},{value:"Fault",id:"fault",level:3},{value:"FinalitySignature",id:"finalitysignature",level:3},{value:"Step",id:"step",level:3},{value:"Shutdown",id:"shutdown",level:3},{value:"Reacting to Events",id:"reacting-to-events",level:2},{value:"Unsubscribing from Events",id:"unsubscribing-from-events",level:2},{value:"Stopping the Event Stream",id:"stopping-the-event-stream",level:2},{value:"Replaying the Event Stream",id:"replaying-the-event-stream",level:2}],f={toc:m},h="wrapper";function v(e){var t=e.components,n=(0,r.Z)(e,s);return(0,i.kt)(h,(0,a.Z)({},f,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"monitoring-and-consuming-events"},"Monitoring and Consuming Events"),(0,i.kt)("p",null,"The Casper platform uses event streaming to signal state changes in smart contracts and nodes. Using Casper's client-side SDKs, dApps actively listening for emitted events can consume these events and perform actions based on event data."),(0,i.kt)("p",null,"Each Casper node streams events through the SSE (Server Sent Event) server via the port specified as the ",(0,i.kt)("inlineCode",{parentName:"p"},"event_stream_server.address")," in the node's ",(0,i.kt)("em",{parentName:"p"},"config.toml"),". This port is by default ",(0,i.kt)("inlineCode",{parentName:"p"},"9999")," for nodes on ",(0,i.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"Testnet")," and ",(0,i.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"Mainnet"),"."),(0,i.kt)("p",null,"Events are divided into three categories and streamed on their respective endpoints:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Deploy events")," - Associated with ",(0,i.kt)("a",{parentName:"li",href:"/concepts/design/casper-design#execution-semantics-deploys"},"Deploys")," on a node. Currently, only a ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployAccepted")," event is emitted. The URL to consume deploy-related events on Mainnet and Testnet is ",(0,i.kt)("inlineCode",{parentName:"li"},"http://:9999/events/deploys/"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Finality Signature events")," - Emitted when a block has been finalized and cannot be altered. The URL to consume finality signature events on Mainnet and Testnet is ",(0,i.kt)("inlineCode",{parentName:"li"},"http://:9999/events/sigs/"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Main events")," - All other events fall under this type, including: ",(0,i.kt)("inlineCode",{parentName:"li"},"BlockAdded"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployProcessed"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployExpired"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Fault"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Step"),", and ",(0,i.kt)("inlineCode",{parentName:"li"},"Shutdown")," events. The URL to consume these events on Mainnet and Testnet is ",(0,i.kt)("inlineCode",{parentName:"li"},"http://:9999/events/main/"),".")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"An ",(0,i.kt)("inlineCode",{parentName:"p"},"ApiVersion")," event is always emitted when a new client connects to a node's SSE server, informing the client of the node's software version.")),(0,i.kt)("h2",{id:"listening-to-the-event-stream"},"Listening to the Event Stream"),(0,i.kt)("p",null,"Applications can listen for such events for a specific account during a particular era, containing certain data. Then, they can parse the data and discard what they do not need. To consume the event stream, set up an event listener in your dApp using the following code:"),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},'const { EventStream, EventName } = require("casper-js-sdk");\n\nconst es = new EventStream("http://NODE_ADDRESS:9999/events/" + CHANNEL);\nes.start();\nes.subscribe(EventName.EVENT_NAME, eventHandler);\n\nconst eventHandler = (event) => {\n console.log(event);\n};\n'))),(0,i.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-python"},'from pycspr import NodeClient, NodeConnection, NodeEventChannel, NodeEventType\n\ndef eventHandler(event):\n print(event)\n\nclient = NodeClient(NodeConnection(host = "NODE_ADDRESS", port_rpc = 7777))\nclient.get_events(eventHandler, NodeEventChannel.CHANNEL, NodeEventType.EVENT_NAME)\n'))),(0,i.kt)(o.Z,{value:"curl",label:"cURL",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://NODE_ADDRESS:9999/events/CHANNEL\n")))),(0,i.kt)("p",null,"You can find node addresses of active online peers to replace ",(0,i.kt)("inlineCode",{parentName:"p"},"NODE_ADDRESS"),", by navigating to ",(0,i.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"cspr.live")," for Mainnet and ",(0,i.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"testnet.cspr.live")," for Testnet."),(0,i.kt)("p",null,"Replace ",(0,i.kt)("inlineCode",{parentName:"p"},"EVENT_NAME")," with one of the event types listed ",(0,i.kt)("a",{parentName:"p",href:"#event-types"},"below"),"."),(0,i.kt)("p",null,"Replace ",(0,i.kt)("inlineCode",{parentName:"p"},"CHANNEL")," with one of the following event streams:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"main")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"ApiVersion"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"BlockAdded"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployExpired"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployProcessed"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Fault"),", or ",(0,i.kt)("inlineCode",{parentName:"li"},"Step")," events."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"deploys")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"DeployAccepted")," events."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sigs")," for ",(0,i.kt)("inlineCode",{parentName:"li"},"FinalitySignature")," events.")),(0,i.kt)("h2",{id:"event-types"},"Event Types"),(0,i.kt)("h3",{id:"apiversion"},"ApiVersion"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"ApiVersion")," event is always the first event emitted when a new client connects to a node's SSE server. It specifies the protocol version of a node on the Casper platform. The following example contains the JSON representation of the ",(0,i.kt)("inlineCode",{parentName:"p"},"ApiVersion")," event structure."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'data:{"ApiVersion":"1.0.0"}\n')),(0,i.kt)("h3",{id:"blockadded"},"BlockAdded"),(0,i.kt)("p",null,"A ",(0,i.kt)("inlineCode",{parentName:"p"},"BlockAdded")," event is emitted when a new block is added to the blockchain and stored locally in the node."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "BlockAdded": {\n "block_hash": "62ddf902e9b6988b978413e2a9a2c6c95f8e1ddf452afd8e8a68f0ac22bf391a",\n "block": {\n "hash": "62ddf105e9b6988b378413e2a9a2c6c95f8e1ddf458afd8e8268f0ac72bfe91a",\n "header": {\n "parent_hash": "ed11ac2117edb9c5b26cf0cde318a807fd68e76206855a70429012ef16b557f5",\n "state_root_hash": "3c1ad31757ae40f934de4825a818274e0c246d304c661daf656e22b65174ad66",\n "body_hash": "eb2344f37193395bbc83587e498bc12ad5f0019055abcfa4c3b989d382a7969a",\n "random_bit": true,\n "accumulated_seed": "b8b671530f2221c8fdf201083f43c51e215e2f6ffcbe2d63238a2779eb177922",\n "era_end": null,\n "timestamp": "2023-01-01T09:55:25.312Z",\n "era_id": 8426,\n "height": 1566677,\n "protocol_version": "1.4.13"\n },\n "body": {\n "proposer": "010e5669b0f0545e2b32bc66363b9d3d4390fca56bf52305f1411b7fa12ca311c7",\n "deploy_hashes": [],\n "transfer_hashes": []\n },\n "proofs": []\n }\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#block-hash"},"block_hash")," - The cryptographic hash that identifies a block."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-block"},"block")," - The JSON representation of the block."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#body"},"proposer")," - The validator selected to propose the block."))),(0,i.kt)("h3",{id:"deployaccepted"},"DeployAccepted"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"DeployAccepted")," events are emitted when a node on the network receives a deploy."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "DeployAccepted": {\n "hash": "db84ba229ea37716230ac9874f66c0f12b9731d8d42f28060e481ef3d7263ead",\n "header": {\n "account": "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c",\n "timestamp": "2023-01-01T20:22:45.383Z",\n "ttl": "30m",\n "gas_price": 1,\n "body_hash": "8a377b07a01ac23905b2e416ff388508301feffbb9bdf275c59f87be1e9d0de5",\n "dependencies": [],\n "chain_name": "casper-test"\n },\n "payment": {\n "ModuleBytes": {\n "module_bytes": "",\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "040008af2f",\n "parsed": "800000000"\n }\n ]\n ]\n }\n },\n "session": {\n "StoredContractByHash": {\n "hash": "1040f40d06f0355a80149befc4b5d1f203231231d66c4903688e178c36066539",\n "entry_point": "test_entry_point",\n "args": [\n [\n "cost",\n {\n "cl_type": "U512",\n "bytes": "0500c817a804",\n "parsed": "20000000000"\n }\n ]\n ]\n }\n },\n "approvals": [\n {\n "signer": "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c",\n "signature": "01d81d4dc9504a356c23d3c161b87b39b1708cd282b59d3e44d9b999e787643ab495f168475bed8dc48d1056605e06c8ba74d96c69ae5b506c4312be8871c0c701"\n }\n ]\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/hash-types"},"hash")," - The blake2b hash of the Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-account"},"account")," - The hexadecimal-encoded public key of the account submitting the Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/hash-types"},"body_hash")," - The blake2b hash of the Deploy body."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/glossary/P#payment-code"},"payment")," - Gas payment information."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"session")," - The session logic defining the Deploy's functionality."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/developers/json-rpc/types_chain#approval"},"approvals")," - The signer's hexadecimal-encoded public key and signature."))),(0,i.kt)("p",null,"For details on custom serializations, check the ",(0,i.kt)("a",{parentName:"p",href:"/concepts/serialization-standard"},"Serialization Standard"),". Also, the ",(0,i.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain"},"Types")," page defines the terms used in the event stream output."),(0,i.kt)("h3",{id:"deployprocessed"},"DeployProcessed"),(0,i.kt)("p",null,"A ",(0,i.kt)("inlineCode",{parentName:"p"},"DeployProcessed")," event is emitted when a given Deploy has been executed."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "DeployProcessed": {\n "deploy_hash": "0f33be8f56ff23d7d503a9804675472e043830a6c17e6141dce717b4f0973c7d",\n "account": "0201cbff12155b6ae1e99d571c01d56e9e1ba0def6719a6f06bc3e4a08f30a887444",\n "timestamp": "2023-01-01T10:07:00.401Z",\n "ttl": "30m",\n "dependencies": [],\n "block_hash": "509b754648168a73e6ab67e64d4a783cf580d6fc0c7c0ec560c6650f717841e0",\n "execution_result": {\n "Success": {\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "account-hash-a8261377ef9cf8e7411d6858801c71e28c9322e66355586549c75ab24cdd73f2",\n "transform": "Identity"\n }\n ]\n },\n "transfers": ["transfer-3389144d15238240f48f5966f2dc299b6b20eb19c13d834409b4d28fc50fa909"],\n "cost": "100000000"\n }\n }\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#deploy-hash"},"deploy_hash")," - The cryptographic hash of a Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#serialization-standard-account"},"account")," - The hexadecimal-encoded public key of the account submitting the Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#timestamp"},"timestamp")," - A timestamp type representing a concrete moment in time."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#deploy-header"},"dependencies")," - A list of Deploy hashes."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#block-hash"},"block_hash")," - A cryptographic hash identifying a Block."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#executionresult"},"execution_result")," - The execution status of the Deploy, which is either ",(0,i.kt)("inlineCode",{parentName:"li"},"Success")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"Failure"),"."))),(0,i.kt)("h3",{id:"deployexpired"},"DeployExpired"),(0,i.kt)("p",null,"A ",(0,i.kt)("inlineCode",{parentName:"p"},"DeployExpired")," event is emitted when the Deploy is no longer valid for processing or being added to a block due to its time to live (TTL) having expired."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "DeployExpired": {\n "deploy_hash": "7ecf22fc284526d6db16fbf455f489e0a9cbf782234131c010cf3078fb9be353"\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#deploy-hash"},"deploy_hash")," - The cryptographic hash of a Deploy."))),(0,i.kt)("h3",{id:"fault"},"Fault"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Fault")," event is emitted if there is a validator error."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand the below section to view the Fault event details:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "Fault": {\n "era_id": 4591448806312642600,\n "public_key": "013da85eb06279da42e28530e1116be04bfd2aa25ed8d63401ebff4d9153a609a9",\n "timestamp": "2023-01-01T01:26:58.364Z"\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#eraid"},"era_id")," - A period of time during which the validator set does not change."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#publickey"},"public_key")," - The hexadecimal-encoded public key of the validator that caused the fault."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#timestamp"},"timestamp")," - A timestamp representing the moment the validator faulted."))),(0,i.kt)("h3",{id:"finalitysignature"},"FinalitySignature"),(0,i.kt)("p",null,"This event indicates validators have signed the final approvals and further alterations to the block will not be allowed. Refer to the ",(0,i.kt)("a",{parentName:"p",href:"/deploy-and-deploy-lifecycle#consensus-reached"},"consensus reached")," and ",(0,i.kt)("a",{parentName:"p",href:"/concepts/glossary/B#block-finality"},"block finality")," sections to learn more about finality signatures."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "FinalitySignature": {\n "block_hash": "eceed827e11f7969a7d3fe91d6fa4ce9749dd79d9f3ea26474fe2014db90e98d",\n "era_id": 8419,\n "signature": "0117087ef4b9a786e5a0ea8f198050e9de93dd94f87469b8124c346aeae5f36ad9adf80f670ee9c5887263267ed32cf932dce9b370353c596d59f91fbd57a1a205",\n "public_key": "01c375b425a36de25dc325c9182861679db2f634abcacd9ae2ee27b84ba62ac1f7"\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#block-hash"},"block_hash")," - A cryptographic hash identifying a Block."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#eraid"},"era_id")," - A period of time during which the validator set does not change."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#signature"},"signature")," - Serialized bytes representing the validator's signature."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#publickey"},"public_key")," - The hexadecimal-encoded public key of the validator."))),(0,i.kt)("h3",{id:"step"},"Step"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Step")," event is emitted at the end of every era and contains the execution effects produced by running the auction contract's ",(0,i.kt)("inlineCode",{parentName:"p"},"step")," function."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand to view output:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "Step": {\n "era_id": 1,\n "execution_effect": {\n "operations": [],\n "transforms": [\n {\n "key": "uref-53df18bf01396fbd1ef3a8757c7bdffc684c407d90f2cfeebff166db1d923613-000",\n "transform": "Identity"\n },\n {\n "key": "uref-f268de37fcea55f8fb1abeba8536a1cc041b2aed2691f1cf34aeaaf0ae379aa5-000",\n "transform": "Identity"\n },\n {\n "key": "bid-278e5af1ca6cddf5d5438999cb072b47f0d65e1484799f692c3c9c40304be30e",\n "transform": "Identity"\n },\n {\n "key": "bid-278e5af1ca6cddf5d5438999cb072b47f0d65e1484799f692c3c9c40304be30e",\n "transform": {\n "WriteBid": {\n "validator_public_key": "0133eaae2821f090ac3ba0eadc0a897742094c0604df72b465c41d4b773298a7b9",\n "bonding_purse": "uref-136552c255d4d737bf7e43d2be250f9f38691b9fe5d9e34446bff18d6d1cf984-007",\n "staked_amount": "1000000000000005",\n "delegation_rate": 5,\n "vesting_schedule": {\n "initial_release_timestamp_millis": 1664475057182,\n "locked_amounts": null\n },\n "delegators": {\n "012a241eaa9fa3bd6ccb0e0aaaf4658538f3540e04e2f58973614a168f2f2f813d": {\n "delegator_public_key": "012a241eaa9fa3bd6ccb0e0aaaf4658538f3540e04e2f58973614a168f2f2f813d",\n "staked_amount": "51312014671568117976319379",\n "bonding_purse": "uref-c5ad00f9e6b2f2631ca647ad188187e63799a278a0a46ca25f6b4da64d556662-007",\n "validator_public_key": "0133eaae2821f090ac3ba0eadc0a897742094c0604df72b465c41d4b773298a7b9",\n "vesting_schedule": {\n "initial_release_timestamp_millis": 1664475057182,\n "locked_amounts": null\n }\n }\n },\n "inactive": false\n }\n }\n }\n ]\n }\n }\n}\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#eraid"},"era_id")," - A period of time during which the validator set does not change."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#executioneffect"},"execution_effect")," - The journal of execution transforms from a single Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#operation"},"operations")," - Operations performed while executing a Deploy."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/concepts/serialization-standard#transform"},"transform")," - The actual transformation performed while executing a Deploy."))),(0,i.kt)("h3",{id:"shutdown"},"Shutdown"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"Shutdown")," event is emitted when the node is about to shut down, usually for an upgrade, causing a termination of the event stream."),(0,i.kt)("details",null,(0,i.kt)("summary",null,"Expand the below section to view the Shutdown event details:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'"Shutdown"\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},'Shutdown - The "Shutdown" text notifies the event listener that a shutdown will occur.'))),(0,i.kt)("h2",{id:"reacting-to-events"},"Reacting to Events"),(0,i.kt)("p",null,"An application may parse each event needed for its use case and respond accordingly. The dApp may act on some events and not others, or it may act upon them all, depending on its use case. Each event type contains additional data that might help in deciding whether or not to take an action. For example, ",(0,i.kt)("inlineCode",{parentName:"p"},"DeployAccepted")," events contain the account's public key that submitted the deploy, the contract address, and more. This information can help determine how to proceed or whether or not to react."),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},'const eventHandler = (event) => {\n if (event.body.DeployAccepted.header.account == "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c") {\n // Perform an action\n }\n};\n'))),(0,i.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-python"},'def eventHandler(event):\n if event["DeployAccepted"]["header"]["account"] == "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c":\n # Perform an action\n')))),(0,i.kt)("h2",{id:"unsubscribing-from-events"},"Unsubscribing from Events"),(0,i.kt)("p",null,"In many cases, an application may need to unsubscribe after a certain time or may want to unsubscribe from some events but not others. The Casper SDKs provide this ability with the ",(0,i.kt)("inlineCode",{parentName:"p"},"unsubscribe")," function:"),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},"es.unsubscribe(EventName.EVENT_NAME);\n")))),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"EVENT_NAME")," - One of the different ",(0,i.kt)("a",{parentName:"li",href:"#event-types"},"event types")," emitted by a Casper node.")),(0,i.kt)("h2",{id:"stopping-the-event-stream"},"Stopping the Event Stream"),(0,i.kt)("p",null,"A dApp may cease listening to all events using the ",(0,i.kt)("inlineCode",{parentName:"p"},"stop")," function:"),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},"es.stop();\n")))),(0,i.kt)("h2",{id:"replaying-the-event-stream"},"Replaying the Event Stream"),(0,i.kt)("p",null,"This command will replay the event stream from an old event onward. Replace the ",(0,i.kt)("inlineCode",{parentName:"p"},"NODE_ADDRESS"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"CHANNEL"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"ID")," fields with the values of your scenario."),(0,i.kt)(l.Z,{mdxType:"Tabs"},(0,i.kt)(o.Z,{value:"curl",label:"cURL",mdxType:"TabItem"},(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"curl -sN http://NODE_ADDRESS:9999/events/CHANNEL?start_from=ID\n")),(0,i.kt)("p",null,(0,i.kt)("em",{parentName:"p"},"Example:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"curl -sN http://65.21.235.219:9999/events/main?start_from=29267508\n")))),(0,i.kt)("p",null,"Each URL can have a query string added to the form ",(0,i.kt)("inlineCode",{parentName:"p"},"?start_from=ID"),", where ID is an integer representing an old event ID. With this query, you can replay the event stream from that old event onward. If you specify an event ID already purged from the cache, the server will replay all the cached events."),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"The server keeps only a limited number of events cached to allow replaying the stream to clients using the ",(0,i.kt)("inlineCode",{parentName:"p"},"?start_from=")," query string. The cache size can be set differently on each node using the ",(0,i.kt)("inlineCode",{parentName:"p"},"event_stream_buffer_length")," value in the ",(0,i.kt)("em",{parentName:"p"},"config.toml"),". By default, it is only 5000. The intended use case is to allow a client consuming the event stream that loses its connection to reconnect and catch up with events that were emitted while it was disconnected.")))}v.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a6f4e53a.273888e4.js b/assets/js/a6f4e53a.273888e4.js deleted file mode 100644 index 33d29752f3..0000000000 --- a/assets/js/a6f4e53a.273888e4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9989],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(n),u=i,m=c["".concat(s,".").concat(u)]||c[u]||h[u]||o;return n?a.createElement(m,r(r({ref:t},p),{},{components:n})):a.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,r[1]=l;for(var d=2;d \\\n--secret-key \\\n--chain-name \\\n--payment-amount 2500000000 \\\n--session-hash \\\n--session-entry-point redelegate \\\n--session-arg \"delegator:public_key=''\" \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"new_validator:public_key=''\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entrypoint that will be used when calling the contract")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate")," entry point expects four arguments:"),(0,o.kt)("ol",{start:7},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"delegator:public_key"),": The hexadecimal public key of the account submitting the redelegate request. This key must match the secret key that signs the deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"validator:public_key"),": The hexadecimal public key of the validator from whom the tokens will be undelegated"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"amount"),": The amount to be redelegated to the new validator"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"new_validator:public_key"),": The hexadecimal public key of the validator to whom the tokens will be delegated")),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate")," entry point on the auction contract has a fixed cost of 2.5 CSPR and there is a minimum delegation amount of 500 CSPR that also applies to redelegations.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"This example uses a private network running ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," version 1.5. The payment amount specified is 2.5 CSPR. You must modify the payment and other values in the deploy based on the network's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://3.143.158.19:7777 \\\n--chain-name integration-test \\\n--secret-key ~/KEYS/integration/Test_secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-hash hash-e22d38bcf3454a93face78a353feaccbf1d637d1ef9ef2e061a655728ff59bbe \\\n--session-entry-point redelegate \\\n--session-arg \"validator:public_key='017fec504c642f2b321b8591f1c3008348c57a81acafceb5a392cf8416a5fb4a3c'\" \\\n--session-arg \"amount:u512='500000000000'\" \\\n--session-arg \"delegator:public_key='01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986'\" \\\n--session-arg \"new_validator:public_key='019e7b8bdec03ba83be4f5443d9f7f9111c77fec984ce9bb5bb7eb3da1e689c02d'\"\n")),(0,o.kt)("p",null,"Next, ",(0,o.kt)("a",{parentName:"p",href:"#verifying-the-redelegation"},"verify the redelegation"),"."),(0,o.kt)("h2",{id:"bonding-compiled-wasm"},"Method 2: Redelegating with Compiled Wasm"),(0,o.kt)("p",null,"Another way to send a redelegation is to compile the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate.wasm")," and send it to the network via a deploy. To compile the Wasm yourself, ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/delegate#building-the-delegation-wasm"},"build the casper-node contracts")," that will include the redelegation Wasm."),(0,o.kt)("h3",{id:"sending-the-redelegation-deploy"},"Sending the redelegation request"),(0,o.kt)("p",null,"We recommend testing the following steps on the official Testnet before performing them in a live environment like the Casper Mainnet."),(0,o.kt)("p",null,"This example uses the Casper client to send a deploy containing the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate.wasm")," to the network to initiate the redelegation process."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path /redelegate.wasm \\\n--session-arg \"delegator:public_key=''\" \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"new_validator:public_key=''\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the ",(0,o.kt)("inlineCode",{parentName:"li"},"redelegate.wasm")," on your computer")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate.wasm")," expects four arguments:"),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"delegator:public_key"),": The hexadecimal public key of the account submitting the redelegate request. This key must match the secret key that signs the deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"validator:public_key"),": The hexadecimal public key of the validator from whom the tokens will be undelegated"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"amount"),": The amount to be redelegated to the new validator"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"new_validator:public_key"),": The hexadecimal public key of the validator to whom the tokens will be delegated")),(0,o.kt)("p",null,"Save the returned ",(0,o.kt)("em",{parentName:"p"},"deploy_hash")," from the output to ",(0,o.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#querying-deploys"},"query information")," about the redelegation Deploy."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Running the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate.wasm")," is a more expensive operation than calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate")," entrypoint from the system auction contract.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"This example uses a private network running ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," version 1.5. The payment amount specified is 8 CSPR. You must modify the payment and other values in the deploy based on the network's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://3.143.158.19:7777 \\\n--chain-name integration-test \\\n--secret-key ~/KEYS/integration/Test_secret_key.pem \\\n--payment-amount 8000000000 \\\n--session-path ~/redelegate.wasm \\\n--session-arg \"validator:public_key='017fec504c642f2b321b8591f1c3008348c57a81acafceb5a392cf8416a5fb4a3c'\" \\\n--session-arg \"amount:u512='500000000000'\" \\\n--session-arg \"delegator:public_key='01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986'\" \\\n--session-arg \"new_validator:public_key='019e7b8bdec03ba83be4f5443d9f7f9111c77fec984ce9bb5bb7eb3da1e689c02d'\"\n")),(0,o.kt)("h2",{id:"verifying-the-redelegation"},"Verifying the Redelegation"),(0,o.kt)("p",null,"The redelegation process includes an unbonding delay before the tokens are redelegated to a new validator. In contrast, initial delegation occurs when a Casper network finalizes the associated Deploy."),(0,o.kt)("p",null,"Due to this delay, the new validator may become inactive before the redelegation completes. If this happens, the tokens will be returned to the delegator."),(0,o.kt)("p",null,"Once the redelegation Deploy has been processed, you can query the auction to confirm the redelegation. This process is the same as ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/delegate#confirming-the-delegation"},"verifying a delegation request")," using the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client get-auction-info")," command."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a6f4e53a.8ba03a22.js b/assets/js/a6f4e53a.8ba03a22.js new file mode 100644 index 0000000000..73883c712f --- /dev/null +++ b/assets/js/a6f4e53a.8ba03a22.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9989],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(n),u=i,m=c["".concat(s,".").concat(u)]||c[u]||h[u]||o;return n?a.createElement(m,r(r({ref:t},p),{},{components:n})):a.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,r[1]=l;for(var d=2;d \\\n--secret-key \\\n--chain-name \\\n--payment-amount 2500000000 \\\n--session-hash \\\n--session-entry-point redelegate \\\n--session-arg \"delegator:public_key=''\" \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"new_validator:public_key=''\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entrypoint that will be used when calling the contract")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate")," entry point expects four arguments:"),(0,o.kt)("ol",{start:7},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"delegator:public_key"),": The hexadecimal public key of the account submitting the redelegate request. This key must match the secret key that signs the deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"validator:public_key"),": The hexadecimal public key of the validator from whom the tokens will be undelegated"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"amount"),": The amount to be redelegated to the new validator"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"new_validator:public_key"),": The hexadecimal public key of the validator to whom the tokens will be delegated")),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate")," entry point on the auction contract has a fixed cost of 2.5 CSPR and there is a minimum delegation amount of 500 CSPR that also applies to redelegations.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"This example uses a private network running ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," version 1.5. The payment amount specified is 2.5 CSPR. You must modify the payment and other values in the deploy based on the network's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://3.143.158.19:7777 \\\n--chain-name integration-test \\\n--secret-key ~/KEYS/integration/Test_secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-hash hash-e22d38bcf3454a93face78a353feaccbf1d637d1ef9ef2e061a655728ff59bbe \\\n--session-entry-point redelegate \\\n--session-arg \"validator:public_key='017fec504c642f2b321b8591f1c3008348c57a81acafceb5a392cf8416a5fb4a3c'\" \\\n--session-arg \"amount:u512='500000000000'\" \\\n--session-arg \"delegator:public_key='01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986'\" \\\n--session-arg \"new_validator:public_key='019e7b8bdec03ba83be4f5443d9f7f9111c77fec984ce9bb5bb7eb3da1e689c02d'\"\n")),(0,o.kt)("p",null,"Next, ",(0,o.kt)("a",{parentName:"p",href:"#verifying-the-redelegation"},"verify the redelegation"),"."),(0,o.kt)("h2",{id:"bonding-compiled-wasm"},"Method 2: Redelegating with Compiled Wasm"),(0,o.kt)("p",null,"Another way to send a redelegation is to compile the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate.wasm")," and send it to the network via a deploy. To compile the Wasm yourself, ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/delegate#building-the-delegation-wasm"},"build the casper-node contracts")," that will include the redelegation Wasm."),(0,o.kt)("h3",{id:"sending-the-redelegation-deploy"},"Sending the redelegation request"),(0,o.kt)("p",null,"We recommend testing the following steps on the official Testnet before performing them in a live environment like the Casper Mainnet."),(0,o.kt)("p",null,"This example uses the Casper client to send a deploy containing the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate.wasm")," to the network to initiate the redelegation process."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path /redelegate.wasm \\\n--session-arg \"delegator:public_key=''\" \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"new_validator:public_key=''\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the ",(0,o.kt)("inlineCode",{parentName:"li"},"redelegate.wasm")," on your computer")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate.wasm")," expects four arguments:"),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"delegator:public_key"),": The hexadecimal public key of the account submitting the redelegate request. This key must match the secret key that signs the deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"validator:public_key"),": The hexadecimal public key of the validator from whom the tokens will be undelegated"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"amount"),": The amount to be redelegated to the new validator"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"new_validator:public_key"),": The hexadecimal public key of the validator to whom the tokens will be delegated")),(0,o.kt)("p",null,"Save the returned ",(0,o.kt)("em",{parentName:"p"},"deploy_hash")," from the output to ",(0,o.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#querying-deploys"},"query information")," about the redelegation Deploy."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Running the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate.wasm")," is a more expensive operation than calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"redelegate")," entrypoint from the system auction contract.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"This example uses a private network running ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-node")," version 1.5. The payment amount specified is 8 CSPR. You must modify the payment and other values in the deploy based on the network's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://3.143.158.19:7777 \\\n--chain-name integration-test \\\n--secret-key ~/KEYS/integration/Test_secret_key.pem \\\n--payment-amount 8000000000 \\\n--session-path ~/redelegate.wasm \\\n--session-arg \"validator:public_key='017fec504c642f2b321b8591f1c3008348c57a81acafceb5a392cf8416a5fb4a3c'\" \\\n--session-arg \"amount:u512='500000000000'\" \\\n--session-arg \"delegator:public_key='01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986'\" \\\n--session-arg \"new_validator:public_key='019e7b8bdec03ba83be4f5443d9f7f9111c77fec984ce9bb5bb7eb3da1e689c02d'\"\n")),(0,o.kt)("h2",{id:"verifying-the-redelegation"},"Verifying the Redelegation"),(0,o.kt)("p",null,"The redelegation process includes an unbonding delay before the tokens are redelegated to a new validator. In contrast, initial delegation occurs when a Casper network finalizes the associated Deploy."),(0,o.kt)("p",null,"Due to this delay, the new validator may become inactive before the redelegation completes. If this happens, the tokens will be returned to the delegator."),(0,o.kt)("p",null,"Once the redelegation Deploy has been processed, you can query the auction to confirm the redelegation. This process is the same as ",(0,o.kt)("a",{parentName:"p",href:"/developers/cli/delegate#confirming-the-delegation"},"verifying a delegation request")," using the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client get-auction-info")," command."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a71eff7a.5141f7ca.js b/assets/js/a71eff7a.5141f7ca.js new file mode 100644 index 0000000000..56dfe63f9c --- /dev/null +++ b/assets/js/a71eff7a.5141f7ca.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6988],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function s(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,s=e.mdxType,r=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),h=s,m=u["".concat(i,".").concat(h)]||u[h]||d[h]||r;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var r=n.length,o=new Array(r);o[0]=h;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[u]="string"==typeof e?e:s,o[1]=l;for(var c=2;c=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,s=e.mdxType,r=e.originalType,i=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),h=s,m=u["".concat(i,".").concat(h)]||u[h]||d[h]||r;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var r=n.length,o=new Array(r);o[0]=h;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[u]="string"==typeof e?e:s,o[1]=l;for(var c=2;c=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=u(r),m=o,f=p["".concat(l,".").concat(m)]||p[m]||d[m]||a;return r?n.createElement(f,i(i({ref:t},c),{},{components:r})):n.createElement(f,i({ref:t},c))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var u=2;u=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),u=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=u(r),m=o,f=p["".concat(l,".").concat(m)]||p[m]||d[m]||a;return r?n.createElement(f,i(i({ref:t},c),{},{components:r})):n.createElement(f,i({ref:t},c))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=n.createContext({}),s=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=s(e.components);return n.createElement(u.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,u=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=s(r),g=a,f=p["".concat(u,".").concat(g)]||p[g]||c[g]||i;return r?n.createElement(f,o(o({ref:t},d),{},{components:r})):n.createElement(f,o({ref:t},d))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=g;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[p]="string"==typeof e?e:a,o[1]=l;for(var s=2;s=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=n.createContext({}),s=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=s(e.components);return n.createElement(u.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,u=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=s(r),g=a,f=p["".concat(u,".").concat(g)]||p[g]||c[g]||i;return r?n.createElement(f,o(o({ref:t},d),{},{components:r})):n.createElement(f,o({ref:t},d))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=g;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[p]="string"==typeof e?e:a,o[1]=l;for(var s=2;s=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=o.createContext({}),d=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=d(e.components);return o.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,i=e.mdxType,s=e.originalType,c=e.parentName,l=r(e,["components","mdxType","originalType","parentName"]),p=d(n),h=i,m=p["".concat(c,".").concat(h)]||p[h]||u[h]||s;return n?o.createElement(m,a(a({ref:t},l),{},{components:n})):o.createElement(m,a({ref:t},l))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var s=n.length,a=new Array(s);a[0]=h;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[p]="string"==typeof e?e:i,a[1]=r;for(var d=2;d=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=o.createContext({}),d=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=d(e.components);return o.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,i=e.mdxType,s=e.originalType,c=e.parentName,l=r(e,["components","mdxType","originalType","parentName"]),p=d(n),h=i,m=p["".concat(c,".").concat(h)]||p[h]||u[h]||s;return n?o.createElement(m,a(a({ref:t},l),{},{components:n})):o.createElement(m,a({ref:t},l))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var s=n.length,a=new Array(s);a[0]=h;var r={};for(var c in t)hasOwnProperty.call(t,c)&&(r[c]=t[c]);r.originalType=e,r[p]="string"==typeof e?e:i,a[1]=r;for(var d=2;d=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var s=a.createContext({}),c=function(t){var e=a.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},d=function(t){var e=c(t.components);return a.createElement(s.Provider,{value:e},t.children)},p="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},m=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,i=t.originalType,s=t.parentName,d=l(t,["components","mdxType","originalType","parentName"]),p=c(n),m=r,g=p["".concat(s,".").concat(m)]||p[m]||u[m]||i;return n?a.createElement(g,o(o({ref:e},d),{},{components:n})):a.createElement(g,o({ref:e},d))}));function g(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in e)hasOwnProperty.call(e,s)&&(l[s]=e[s]);l.originalType=t,l[p]="string"==typeof t?t:r,o[1]=l;for(var c=2;c=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var s=a.createContext({}),c=function(t){var e=a.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},d=function(t){var e=c(t.components);return a.createElement(s.Provider,{value:e},t.children)},p="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},m=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,i=t.originalType,s=t.parentName,d=l(t,["components","mdxType","originalType","parentName"]),p=c(n),m=r,g=p["".concat(s,".").concat(m)]||p[m]||u[m]||i;return n?a.createElement(g,o(o({ref:e},d),{},{components:n})):a.createElement(g,o({ref:e},d))}));function g(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in e)hasOwnProperty.call(e,s)&&(l[s]=e[s]);l.originalType=t,l[p]="string"==typeof t?t:r,o[1]=l;for(var c=2;c=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||u[y]||o;return r?n.createElement(m,s(s({ref:t},i),{},{components:r})):n.createElement(m,s({ref:t},i))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||u[y]||o;return r?n.createElement(m,s(s({ref:t},i),{},{components:r})):n.createElement(m,s({ref:t},i))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=r,h=u["".concat(s,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:r,i[1]=l;for(var p=2;p child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:u(n);return function(e){var t=(0,p.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function h(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,o=(0,l.k6)(),i=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,s._X)(i),(0,r.useCallback)((function(e){if(i){var t=new URLSearchParams(o.location.search);t.set(i,e),o.replace(Object.assign({},o.location,{search:t.toString()}))}}),[i,o])]}function f(e){var t,n,a,o,i=e.defaultValue,l=e.queryString,s=void 0!==l&&l,p=e.groupId,u=d(e),f=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:i,tabValues:u})})),g=f[0],b=f[1],y=h({queryString:s,groupId:p}),k=y[0],v=y[1],w=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:p}.groupId),n=(0,c.Nk)(t),a=n[0],o=n[1],[a,(0,r.useCallback)((function(e){t&&o.set(e)}),[t,o])]),C=w[0],N=w[1],T=function(){var e=null!=k?k:C;return m({value:e,tabValues:u})?e:null}();return(0,r.useLayoutEffect)((function(){T&&b(T)}),[T]),{selectedValue:g,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:u}))throw new Error("Can't select invalid tab value="+e);b(e),v(e),N(e)}),[v,N,u]),tabValues:u}}var g=n(2389),b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function y(e){var t=e.className,n=e.block,l=e.selectedValue,s=e.selectValue,p=e.tabValues,c=[],u=(0,i.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,n=c.indexOf(t),a=p[n].value;a!==l&&(u(t),s(a))},m=function(e){var t,n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var a,r=c.indexOf(e.currentTarget)+1;n=null!=(a=c[r])?a:c[0];break;case"ArrowLeft":var o,i=c.indexOf(e.currentTarget)-1;n=null!=(o=c[i])?o:c[c.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":n},t)},p.map((function(e){var t=e.value,n=e.label,i=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:l===t?0:-1,"aria-selected":l===t,key:t,ref:function(e){return c.push(e)},onKeyDown:m,onClick:d},i,{className:(0,o.Z)("tabs__item",b.tabItem,null==i?void 0:i.className,{"tabs__item--active":l===t})}),null!=n?n:t)})))}function k(e){var t=e.lazy,n=e.children,a=e.selectedValue,o=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var i=o.find((function(e){return e.props.value===a}));return i?(0,r.cloneElement)(i,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},o.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function v(e){var t=f(e);return r.createElement("div",{className:(0,o.Z)("tabs-container",b.tabList)},r.createElement(y,(0,a.Z)({},e,t)),r.createElement(k,(0,a.Z)({},e,t)))}function w(e){var t=(0,g.Z)();return r.createElement(v,(0,a.Z)({key:String(t)},e))}},4095:function(e,t,n){n.r(t),n.d(t,{assets:function(){return c},contentTitle:function(){return s},default:function(){return h},frontMatter:function(){return l},metadata:function(){return p},toc:function(){return u}});var a=n(7462),r=n(3366),o=(n(7294),n(3905)),i=(n(4866),n(5162),["components"]),l={title:"Front-end in React"},s="Front-end Template with React",p={unversionedId:"developers/dapps/template-frontend",id:"developers/dapps/template-frontend",title:"Front-end in React",description:"For building web applications, it is most common to use the Casper JS SDK with React. This is a popular solution among developers, but you may use any front-end library or framework, including none at all, to interact with a Casper network via the Casper JS SDK.",source:"@site/source/docs/casper/developers/dapps/template-frontend.md",sourceDirName:"developers/dapps",slug:"/developers/dapps/template-frontend",permalink:"/developers/dapps/template-frontend",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/dapps/template-frontend.md",tags:[],version:"current",lastUpdatedAt:1707837031,formattedLastUpdatedAt:"Feb 13, 2024",frontMatter:{title:"Front-end in React"},sidebar:"developers",previous:{title:"dApp Technology Stack",permalink:"/developers/dapps/technology-stack"},next:{title:"URef Access Rights",permalink:"/developers/dapps/uref-security"}},c={},u=[{value:"Get Started",id:"get-started",level:2},{value:"Casper Wallet Integration",id:"casper-wallet-integration",level:2},{value:"Disconnect the Casper Wallet",id:"disconnect-the-casper-wallet",level:3},{value:"Call a Smart Contract",id:"call-a-smart-contract",level:2},{value:"Query a Smart Contract",id:"query-a-smart-contract",level:2},{value:"Test Application",id:"test-application",level:2},{value:"Build for Production",id:"build-for-production",level:2}],d={toc:u},m="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)(m,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"front-end-template-with-react"},"Front-end Template with React"),(0,o.kt)("p",null,"For building web applications, it is most common to use the Casper JS SDK with React. This is a popular solution among developers, but you may use any front-end library or framework, including none at all, to interact with a Casper network via the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/casper-js-sdk"},"Casper JS SDK"),"."),(0,o.kt)("p",null,"This guide will walk you through setting up and developing a React application with ",(0,o.kt)("a",{parentName:"p",href:"https://vitejs.dev/"},"Vite")," that communicates with a Casper network. Experience with Vite is not required; however, if you have never built a React app, you should begin by ",(0,o.kt)("a",{parentName:"p",href:"https://reactjs.org/docs/getting-started.html"},"reading the React documentation"),"."),(0,o.kt)("h2",{id:"get-started"},"Get Started"),(0,o.kt)("p",null,"Begin by opening a terminal and running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"node -v\n")),(0,o.kt)("p",null,"To get your Node.js version."),(0,o.kt)("p",null,"To ensure compatibility, you should be running Node.js version 18 or above. Upgrade to version 18 using the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/nvm-sh/nvm"},"Node Version Manager")," or another tool if you are running an earlier version."),(0,o.kt)("p",null,"Using ",(0,o.kt)("a",{parentName:"p",href:"https://www.npmjs.com/"},"npm"),", create a new Vite project by running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm install -g vite\nnpm create vite@latest\n")),(0,o.kt)("p",null,'Name your project, select "React", then choose your preferred language. In this example, we will use JavaScript.'),(0,o.kt)("p",null,"Head into your new project directory, replacing ",(0,o.kt)("inlineCode",{parentName:"p"},"vite-project")," with your project name:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd vite-project/\n")),(0,o.kt)("p",null,"Run the following command to test the server:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm install\nvite dev\n")),(0,o.kt)("p",null,"Quit the server by pressing ",(0,o.kt)("inlineCode",{parentName:"p"},"q"),". Install the Casper JS SDK by running the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm install casper-js-sdk\n")),(0,o.kt)("p",null,"This guide will use ",(0,o.kt)("a",{parentName:"p",href:"https://axios-http.com/"},"axios")," to communicate with the backend; install it by running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm install axios\n")),(0,o.kt)("h2",{id:"casper-wallet-integration"},"Casper Wallet Integration"),(0,o.kt)("p",null,"The Casper Wallet extension content script injects the SDK into your website's global scope. Provider class and event types can be accessed with ",(0,o.kt)("inlineCode",{parentName:"p"},"window.CasperWalletProvider")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"window.CasperWalletEventTypes"),". If the value of these variables is ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined")," the Casper Wallet is not installed."),(0,o.kt)("p",null,"Start with a helper for getting the provider instance:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"touch src/casper-wallet.js\n")),(0,o.kt)("p",null,"Fill the file with the following content:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// Timeout (in ms) for requests to the extension [DEFAULT: 30 min]\nconst REQUESTS_TIMEOUT_MS = 30 * 60 * 1000;\n\nexport const getProvider = () => {\n let providerConstructor = window.CasperWalletProvider;\n if (providerConstructor === undefined) {\n alert("Casper Wallet extension is not installed!");\n return;\n }\n let provider = providerConstructor({\n timeout: REQUESTS_TIMEOUT_MS,\n });\n return provider;\n};\n')),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"For complete integration details, refer to ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/make-software/casper-wallet-sdk/#readme"},"README of Casper Wallet SDK"),".")),(0,o.kt)("p",null,"To ensure that a user's public key will be available to all necessary components, create a React state variable in ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx")," or another parent component that encapsulates the components that should have access to this public key:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import React from "react";\nimport Connect from "./Connect";\nimport "./App.css";\n\nfunction App() {\n const [publicKey, setPublicKey] = React.useState(null);\n return (\n <>\n \n
\n {publicKey !== null && (\n <>\n Wallet connected: {publicKey}\n
\n \n )}\n
\n \n );\n}\n\nexport default App;\n')),(0,o.kt)("p",null,"This is an example of ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx")," that imports and displays the ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," component that is described next. The ",(0,o.kt)("inlineCode",{parentName:"p"},"setPublicKey")," function is passed to the ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," component as a ",(0,o.kt)("a",{parentName:"p",href:"https://legacy.reactjs.org/docs/components-and-props.html"},"prop")," so that it may set the public key and make it available to all of ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx"),". This way, when more components are added to ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx"),", they may utilize the ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," variable."),(0,o.kt)("p",null,"To connect to the Casper Wallet within your React app, create the ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," component and import the ",(0,o.kt)("inlineCode",{parentName:"p"},"getProvider")," helper."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"touch src/Connect.jsx\n")),(0,o.kt)("p",null,"Open the file and write:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import { getProvider } from "./casper-wallet";\n\nconst provider = getProvider();\n\nconst Connect = (props) => {\n return (\n <>\n \n {/* Place for disconnect button */}\n \n );\n};\n\nexport default Connect;\n')),(0,o.kt)("p",null,"Notice that ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," accepts props, and forwards them to the ",(0,o.kt)("inlineCode",{parentName:"p"},"connectToWallet")," function described below. This function is called when the button is clicked, allowing it to set the public key within ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx")," using ",(0,o.kt)("inlineCode",{parentName:"p"},"props.setPublicKey()"),"."),(0,o.kt)("p",null,"Write the ",(0,o.kt)("inlineCode",{parentName:"p"},"connectToWallet")," function under the ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," function component:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'const connectToWallet = (props) => {\n provider\n .requestConnection()\n .then((connected) => {\n if (!connected) {\n alert("Couldn\'t connect to wallet");\n } else {\n provider\n .getActivePublicKey()\n .then((publicKey) => {\n props.setPublicKey(publicKey);\n })\n .catch((error) => {\n alert(error.message);\n });\n }\n })\n .catch((error) => {\n alert(error.message);\n });\n};\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"connectToWallet()")," function calls ",(0,o.kt)("inlineCode",{parentName:"p"},"provider.isConnected()")," to check if the Casper Wallet is already connected. If it is, it gets the public key of the selected account; if it's not, it opens up a connection request within the Wallet. ",(0,o.kt)("inlineCode",{parentName:"p"},"provider.isConnected()")," will throw an error if the Wallet is not installed as an extension or if it is locked."),(0,o.kt)("h3",{id:"disconnect-the-casper-wallet"},"Disconnect the Casper Wallet"),(0,o.kt)("p",null,"To request that the Casper Wallet disconnect from a website, add the following function call to ",(0,o.kt)("em",{parentName:"p"},"src/Connect.jsx"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'const disconnect = (props) => {\n provider\n .disconnectFromSite()\n .then((disconnected) => {\n if (disconnected) {\n props.setPublicKey(null);\n alert("Disconnected");\n }\n })\n .catch((error) => {\n alert(error.message);\n });\n};\n')),(0,o.kt)("p",null,"Then connect it to a button:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},"const Connect = (props) => {\n return (\n <>\n \n // highlight-next-line-green\n \n \n );\n};\n")),(0,o.kt)("h2",{id:"call-a-smart-contract"},"Call a Smart Contract"),(0,o.kt)("p",null,'For this example, we\'ll call a hypothetical "hello world" contract containing a single entrypoint "update_message". We\'ll call the "update_message" entrypoint with text entered by the user in an HTML ',(0,o.kt)("inlineCode",{parentName:"p"},"input")," field."),(0,o.kt)("p",null,"When calling smart contracts from React, you'll need to implement the logic within a function accessible from a React component. You can obtain user-entered data from the DOM using elements like ",(0,o.kt)("inlineCode",{parentName:"p"},"input"),", then grab the value within the smart-contract-calling function."),(0,o.kt)("p",null,"Create a new component:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"touch src/UpdateMessage.jsx\n")),(0,o.kt)("p",null,"Open the file and write:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import { useState } from "react";\nimport { Contracts, CasperClient, RuntimeArgs, CLValueBuilder, CLPublicKey, DeployUtil } from "casper-js-sdk";\nimport axios from "axios";\nimport { getProvider } from "./casper-wallet";\n\nconst provider = getProvider();\n\nconst UpdateMessage = (props) => {\n const [message, setMessage] = useState("");\n\n return (\n <>\n {\n setMessage(e.target.value);\n }}\n />\n \n \n );\n};\n\nexport default UpdateMessage;\n')),(0,o.kt)("p",null,"On the front-end you'll need to build the deploy and forward it to the Casper Wallet to be signed. In most cases, you will be calling smart contract entrypoints. This example deploy shows the calling of entrypoint \"update_message\" which will update the chain's global state to reflect the new data. You'll need the user's active public key to prepare the deploy, and you may retrieve this from the ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," variable passed in as a prop from ",(0,o.kt)("inlineCode",{parentName:"p"},"src/App.jsx"),". Write this function under your ",(0,o.kt)("inlineCode",{parentName:"p"},"UpdateMessage")," component function."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'const NODE_URL = "http://65.108.127.242:7777/rpc";\nconst NETWORK_NAME = "casper-test"; // "casper" for mainnet\nconst CONTRACT_HASH = "hash-75143aa708275b7dead20ac2cc06c1c3eccff4ffcf1eb9aebb8cce7c35cea041";\n\nconst updateMessage = (props, message) => {\n const casperClient = new CasperClient(NODE_URL);\n const contract = new Contracts.Contract(casperClient);\n contract.setContractHash(CONTRACT_HASH);\n const runtimeArguments = RuntimeArgs.fromMap({\n message: CLValueBuilder.string(message),\n });\n const deploy = contract.callEntrypoint(\n "update_message",\n runtimeArguments,\n CLPublicKey.fromHex(props.publicKey),\n NETWORK_NAME,\n "1000000000", // 1 CSPR (10^9 Motes)\n );\n const deployJSON = DeployUtil.deployToJson(deploy);\n provider\n .sign(JSON.stringify(deployJSON), props.publicKey)\n .then((signedDeploy) => {\n // Initiates sign request\n axios\n .post("/sendDeploy", signedDeploy, {\n headers: {\n "Content-Type": "application/json",\n },\n })\n .then((response) => {\n alert(response.data);\n })\n .catch((error) => {\n console.error(error.message);\n });\n })\n .catch((error) => {\n console.error(error.message);\n });\n};\n')),(0,o.kt)("p",null,"In this example, ",(0,o.kt)("inlineCode",{parentName:"p"},"updateMessage")," builds a deploy and forwards it to the Casper Wallet to be signed by the user. Once it's been signed, ",(0,o.kt)("inlineCode",{parentName:"p"},"signedDeploy")," is forwarded to the backend at the ",(0,o.kt)("inlineCode",{parentName:"p"},"/sendDeploy")," endpoint using ",(0,o.kt)("inlineCode",{parentName:"p"},"axios.post")," before being sent off to a Casper node. If an error occurs, or the user rejects the signature request, it will be logged to ",(0,o.kt)("inlineCode",{parentName:"p"},"stderr"),". In this particular example, the result of this deployment will be presented to the user in the form of a JavaScript ",(0,o.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/API/Window/alert"},"alert"),"; however, you may do with the response data as you wish."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"The backend endpoint ",(0,o.kt)("inlineCode",{parentName:"p"},"/sendDeploy")," should handle signed deployment by simply passing it to a Casper node."),(0,o.kt)("p",{parentName:"admonition"},"In Casper node ",(0,o.kt)("inlineCode",{parentName:"p"},"v1.5.0"),", which sets up appropriate CORS headers, it will also be possible to send deployments directly from the browser, without relying on a backend server. This is useful for prototyping, however it is advised that you operate your own node.")),(0,o.kt)("p",null,"Now that this component is created, render it to the user interface in ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx"),", passing along the ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," as a prop:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import React from "react";\nimport Connect from "./Connect";\n// highlight-next-line-green\nimport UpdateMessage from "./UpdateMessage";\nimport "./App.css";\n\nfunction App() {\n const [publicKey, setPublicKey] = React.useState(null);\n return (\n <>\n \n
\n {publicKey !== null && (\n <>\n Wallet connected: {publicKey}\n
\n // highlight-next-line-green\n \n \n )}\n
\n \n );\n}\n')),(0,o.kt)("h2",{id:"query-a-smart-contract"},"Query a Smart Contract"),(0,o.kt)("p",null,"Consider that the message written to the chain during the ",(0,o.kt)("inlineCode",{parentName:"p"},"update_message")," entrypoint invocation is stored in the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/D#dictionary"},"dictionary")," ",(0,o.kt)("inlineCode",{parentName:"p"},"messages")," in the contract. Further consider that each account may write its own message and that the messages are stored under the account's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/A#account-hash"},"account hash")," as the dictionary key. Querying this kind of data is essential in any dApp; here is how to communicate contract data to and from the front-end."),(0,o.kt)("p",null,"Create a new component:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"touch src/Query.jsx\n")),(0,o.kt)("p",null,"Open the file and write:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import axios from "axios";\nimport { CLPublicKey } from "casper-js-sdk";\n\nconst Query = (props) => {\n return ;\n};\n\nconst query = (props) => {\n const accountHash = CLPublicKey.fromHex(props.publicKey).toAccountHashStr().substring(13);\n axios\n .get("/queryMessage?accountHash=" + accountHash)\n .then((response) => {\n alert(response.data);\n })\n .catch((error) => {\n console.error(error.message);\n });\n};\n\nexport default Query;\n')),(0,o.kt)("p",null,"All this component does is render an HTML ",(0,o.kt)("inlineCode",{parentName:"p"},"button")," element that, when pressed, performs a ",(0,o.kt)("inlineCode",{parentName:"p"},"GET")," request to the backend that includes the user's active account hash. The account hash is derived from the active public key, and is used to look up the message stored by the current user."),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"The ",(0,o.kt)("inlineCode",{parentName:"p"},"toAccountHashStr"),' method produces a string that is prepended by the text "account-hash-". In this case, this text is not needed, so it is discarded by chaining on the ',(0,o.kt)("inlineCode",{parentName:"p"},"substring(13)")," method.")),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"This functionality relies on the ",(0,o.kt)("inlineCode",{parentName:"p"},"/queryMessage")," endpoint, which should be implemented in your backend.")),(0,o.kt)("p",null,"Now add this component to ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx"),", making available the ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," state variable via a prop:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import React from "react";\nimport Connect from "./Connect";\nimport UpdateMessage from "./UpdateMessage";\n// highlight-next-line-green\nimport Query from "./Query";\nimport "./App.css";\n\nfunction App() {\n const [publicKey, setPublicKey] = React.useState(null);\n return (\n <>\n \n
\n {publicKey !== null && (\n <>\n Wallet connected: {publicKey}\n
\n \n // highlight-next-line-green\n \n \n )}\n
\n \n );\n}\n')),(0,o.kt)("h2",{id:"test-application"},"Test Application"),(0,o.kt)("p",null,"Test your application by running the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"vite dev\n")),(0,o.kt)("p",null,"Your application will start locally, and a URL will be shown where you can visit your application. Alternatively, press ",(0,o.kt)("inlineCode",{parentName:"p"},"h"),", then ",(0,o.kt)("inlineCode",{parentName:"p"},"o")," to open the app in a browser."),(0,o.kt)("h2",{id:"build-for-production"},"Build for Production"),(0,o.kt)("p",null,"When you're ready to release your application, you'll want to compile it to pure JavaScript and serve it from a web server. Do so by running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"vite build\n")),(0,o.kt)("p",null,"Once this is complete, you can preview your production build by running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"vite preview\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ae44828e.f3054247.js b/assets/js/ae44828e.f3054247.js deleted file mode 100644 index 215249d8ab..0000000000 --- a/assets/js/ae44828e.f3054247.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5779],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=r,h=u["".concat(s,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:r,i[1]=l;for(var p=2;p child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:u(n);return function(e){var t=(0,p.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function h(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,o=(0,l.k6)(),i=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,s._X)(i),(0,r.useCallback)((function(e){if(i){var t=new URLSearchParams(o.location.search);t.set(i,e),o.replace(Object.assign({},o.location,{search:t.toString()}))}}),[i,o])]}function f(e){var t,n,a,o,i=e.defaultValue,l=e.queryString,s=void 0!==l&&l,p=e.groupId,u=d(e),f=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:i,tabValues:u})})),g=f[0],b=f[1],y=h({queryString:s,groupId:p}),k=y[0],v=y[1],w=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:p}.groupId),n=(0,c.Nk)(t),a=n[0],o=n[1],[a,(0,r.useCallback)((function(e){t&&o.set(e)}),[t,o])]),C=w[0],N=w[1],T=function(){var e=null!=k?k:C;return m({value:e,tabValues:u})?e:null}();return(0,r.useLayoutEffect)((function(){T&&b(T)}),[T]),{selectedValue:g,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:u}))throw new Error("Can't select invalid tab value="+e);b(e),v(e),N(e)}),[v,N,u]),tabValues:u}}var g=n(2389),b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function y(e){var t=e.className,n=e.block,l=e.selectedValue,s=e.selectValue,p=e.tabValues,c=[],u=(0,i.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,n=c.indexOf(t),a=p[n].value;a!==l&&(u(t),s(a))},m=function(e){var t,n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var a,r=c.indexOf(e.currentTarget)+1;n=null!=(a=c[r])?a:c[0];break;case"ArrowLeft":var o,i=c.indexOf(e.currentTarget)-1;n=null!=(o=c[i])?o:c[c.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":n},t)},p.map((function(e){var t=e.value,n=e.label,i=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:l===t?0:-1,"aria-selected":l===t,key:t,ref:function(e){return c.push(e)},onKeyDown:m,onClick:d},i,{className:(0,o.Z)("tabs__item",b.tabItem,null==i?void 0:i.className,{"tabs__item--active":l===t})}),null!=n?n:t)})))}function k(e){var t=e.lazy,n=e.children,a=e.selectedValue,o=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var i=o.find((function(e){return e.props.value===a}));return i?(0,r.cloneElement)(i,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},o.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function v(e){var t=f(e);return r.createElement("div",{className:(0,o.Z)("tabs-container",b.tabList)},r.createElement(y,(0,a.Z)({},e,t)),r.createElement(k,(0,a.Z)({},e,t)))}function w(e){var t=(0,g.Z)();return r.createElement(v,(0,a.Z)({key:String(t)},e))}},4095:function(e,t,n){n.r(t),n.d(t,{assets:function(){return c},contentTitle:function(){return s},default:function(){return h},frontMatter:function(){return l},metadata:function(){return p},toc:function(){return u}});var a=n(7462),r=n(3366),o=(n(7294),n(3905)),i=(n(4866),n(5162),["components"]),l={title:"Front-end in React"},s="Front-end Template with React",p={unversionedId:"developers/dapps/template-frontend",id:"developers/dapps/template-frontend",title:"Front-end in React",description:"For building web applications, it is most common to use the Casper JS SDK with React. This is a popular solution among developers, but you may use any front-end library or framework, including none at all, to interact with a Casper network via the Casper JS SDK.",source:"@site/source/docs/casper/developers/dapps/template-frontend.md",sourceDirName:"developers/dapps",slug:"/developers/dapps/template-frontend",permalink:"/developers/dapps/template-frontend",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/dapps/template-frontend.md",tags:[],version:"current",lastUpdatedAt:1707229568,formattedLastUpdatedAt:"Feb 6, 2024",frontMatter:{title:"Front-end in React"},sidebar:"developers",previous:{title:"dApp Technology Stack",permalink:"/developers/dapps/technology-stack"},next:{title:"URef Access Rights",permalink:"/developers/dapps/uref-security"}},c={},u=[{value:"Get Started",id:"get-started",level:2},{value:"Casper Wallet Integration",id:"casper-wallet-integration",level:2},{value:"Disconnect the Casper Wallet",id:"disconnect-the-casper-wallet",level:3},{value:"Call a Smart Contract",id:"call-a-smart-contract",level:2},{value:"Query a Smart Contract",id:"query-a-smart-contract",level:2},{value:"Test Application",id:"test-application",level:2},{value:"Build for Production",id:"build-for-production",level:2}],d={toc:u},m="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)(m,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"front-end-template-with-react"},"Front-end Template with React"),(0,o.kt)("p",null,"For building web applications, it is most common to use the Casper JS SDK with React. This is a popular solution among developers, but you may use any front-end library or framework, including none at all, to interact with a Casper network via the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/casper-js-sdk"},"Casper JS SDK"),"."),(0,o.kt)("p",null,"This guide will walk you through setting up and developing a React application with ",(0,o.kt)("a",{parentName:"p",href:"https://vitejs.dev/"},"Vite")," that communicates with a Casper network. Experience with Vite is not required; however, if you have never built a React app, you should begin by ",(0,o.kt)("a",{parentName:"p",href:"https://reactjs.org/docs/getting-started.html"},"reading the React documentation"),"."),(0,o.kt)("h2",{id:"get-started"},"Get Started"),(0,o.kt)("p",null,"Begin by opening a terminal and running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"node -v\n")),(0,o.kt)("p",null,"To get your Node.js version."),(0,o.kt)("p",null,"To ensure compatibility, you should be running Node.js version 18 or above. Upgrade to version 18 using the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/nvm-sh/nvm"},"Node Version Manager")," or another tool if you are running an earlier version."),(0,o.kt)("p",null,"Using ",(0,o.kt)("a",{parentName:"p",href:"https://www.npmjs.com/"},"npm"),", create a new Vite project by running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm install -g vite\nnpm create vite@latest\n")),(0,o.kt)("p",null,'Name your project, select "React", then choose your preferred language. In this example, we will use JavaScript.'),(0,o.kt)("p",null,"Head into your new project directory, replacing ",(0,o.kt)("inlineCode",{parentName:"p"},"vite-project")," with your project name:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd vite-project/\n")),(0,o.kt)("p",null,"Run the following command to test the server:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm install\nvite dev\n")),(0,o.kt)("p",null,"Quit the server by pressing ",(0,o.kt)("inlineCode",{parentName:"p"},"q"),". Install the Casper JS SDK by running the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm install casper-js-sdk\n")),(0,o.kt)("p",null,"This guide will use ",(0,o.kt)("a",{parentName:"p",href:"https://axios-http.com/"},"axios")," to communicate with the backend; install it by running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm install axios\n")),(0,o.kt)("h2",{id:"casper-wallet-integration"},"Casper Wallet Integration"),(0,o.kt)("p",null,"The Casper Wallet extension content script injects the SDK into your website's global scope. Provider class and event types can be accessed with ",(0,o.kt)("inlineCode",{parentName:"p"},"window.CasperWalletProvider")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"window.CasperWalletEventTypes"),". If the value of these variables is ",(0,o.kt)("inlineCode",{parentName:"p"},"undefined")," the Casper Wallet is not installed."),(0,o.kt)("p",null,"Start with a helper for getting the provider instance:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"touch src/casper-wallet.js\n")),(0,o.kt)("p",null,"Fill the file with the following content:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},'// Timeout (in ms) for requests to the extension [DEFAULT: 30 min]\nconst REQUESTS_TIMEOUT_MS = 30 * 60 * 1000;\n\nexport const getProvider = () => {\n let providerConstructor = window.CasperWalletProvider;\n if (providerConstructor === undefined) {\n alert("Casper Wallet extension is not installed!");\n return;\n }\n let provider = providerConstructor({\n timeout: REQUESTS_TIMEOUT_MS,\n });\n return provider;\n};\n')),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"For complete integration details, refer to ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/make-software/casper-wallet-sdk/#readme"},"README of Casper Wallet SDK"),".")),(0,o.kt)("p",null,"To ensure that a user's public key will be available to all necessary components, create a React state variable in ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx")," or another parent component that encapsulates the components that should have access to this public key:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import React from "react";\nimport Connect from "./Connect";\nimport "./App.css";\n\nfunction App() {\n const [publicKey, setPublicKey] = React.useState(null);\n return (\n <>\n \n
\n {publicKey !== null && (\n <>\n Wallet connected: {publicKey}\n
\n \n )}\n
\n \n );\n}\n\nexport default App;\n')),(0,o.kt)("p",null,"This is an example of ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx")," that imports and displays the ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," component that is described next. The ",(0,o.kt)("inlineCode",{parentName:"p"},"setPublicKey")," function is passed to the ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," component as a ",(0,o.kt)("a",{parentName:"p",href:"https://legacy.reactjs.org/docs/components-and-props.html"},"prop")," so that it may set the public key and make it available to all of ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx"),". This way, when more components are added to ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx"),", they may utilize the ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," variable."),(0,o.kt)("p",null,"To connect to the Casper Wallet within your React app, create the ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," component and import the ",(0,o.kt)("inlineCode",{parentName:"p"},"getProvider")," helper."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"touch src/Connect.jsx\n")),(0,o.kt)("p",null,"Open the file and write:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import { getProvider } from "./casper-wallet";\n\nconst provider = getProvider();\n\nconst Connect = (props) => {\n return (\n <>\n \n {/* Place for disconnect button */}\n \n );\n};\n\nexport default Connect;\n')),(0,o.kt)("p",null,"Notice that ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," accepts props, and forwards them to the ",(0,o.kt)("inlineCode",{parentName:"p"},"connectToWallet")," function described below. This function is called when the button is clicked, allowing it to set the public key within ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx")," using ",(0,o.kt)("inlineCode",{parentName:"p"},"props.setPublicKey()"),"."),(0,o.kt)("p",null,"Write the ",(0,o.kt)("inlineCode",{parentName:"p"},"connectToWallet")," function under the ",(0,o.kt)("inlineCode",{parentName:"p"},"Connect")," function component:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'const connectToWallet = (props) => {\n provider\n .requestConnection()\n .then((connected) => {\n if (!connected) {\n alert("Couldn\'t connect to wallet");\n } else {\n provider\n .getActivePublicKey()\n .then((publicKey) => {\n props.setPublicKey(publicKey);\n })\n .catch((error) => {\n alert(error.message);\n });\n }\n })\n .catch((error) => {\n alert(error.message);\n });\n};\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"connectToWallet()")," function calls ",(0,o.kt)("inlineCode",{parentName:"p"},"provider.isConnected()")," to check if the Casper Wallet is already connected. If it is, it gets the public key of the selected account; if it's not, it opens up a connection request within the Wallet. ",(0,o.kt)("inlineCode",{parentName:"p"},"provider.isConnected()")," will throw an error if the Wallet is not installed as an extension or if it is locked."),(0,o.kt)("h3",{id:"disconnect-the-casper-wallet"},"Disconnect the Casper Wallet"),(0,o.kt)("p",null,"To request that the Casper Wallet disconnect from a website, add the following function call to ",(0,o.kt)("em",{parentName:"p"},"src/Connect.jsx"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'const disconnect = (props) => {\n provider\n .disconnectFromSite()\n .then((disconnected) => {\n if (disconnected) {\n props.setPublicKey(null);\n alert("Disconnected");\n }\n })\n .catch((error) => {\n alert(error.message);\n });\n};\n')),(0,o.kt)("p",null,"Then connect it to a button:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},"const Connect = (props) => {\n return (\n <>\n \n // highlight-next-line-green\n \n \n );\n};\n")),(0,o.kt)("h2",{id:"call-a-smart-contract"},"Call a Smart Contract"),(0,o.kt)("p",null,'For this example, we\'ll call a hypothetical "hello world" contract containing a single entrypoint "update_message". We\'ll call the "update_message" entrypoint with text entered by the user in an HTML ',(0,o.kt)("inlineCode",{parentName:"p"},"input")," field."),(0,o.kt)("p",null,"When calling smart contracts from React, you'll need to implement the logic within a function accessible from a React component. You can obtain user-entered data from the DOM using elements like ",(0,o.kt)("inlineCode",{parentName:"p"},"input"),", then grab the value within the smart-contract-calling function."),(0,o.kt)("p",null,"Create a new component:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"touch src/UpdateMessage.jsx\n")),(0,o.kt)("p",null,"Open the file and write:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import { useState } from "react";\nimport { Contracts, CasperClient, RuntimeArgs, CLValueBuilder, CLPublicKey, DeployUtil } from "casper-js-sdk";\nimport axios from "axios";\nimport { getProvider } from "./casper-wallet";\n\nconst provider = getProvider();\n\nconst UpdateMessage = (props) => {\n const [message, setMessage] = useState("");\n\n return (\n <>\n {\n setMessage(e.target.value);\n }}\n />\n \n \n );\n};\n\nexport default UpdateMessage;\n')),(0,o.kt)("p",null,"On the front-end you'll need to build the deploy and forward it to the Casper Wallet to be signed. In most cases, you will be calling smart contract entrypoints. This example deploy shows the calling of entrypoint \"update_message\" which will update the chain's global state to reflect the new data. You'll need the user's active public key to prepare the deploy, and you may retrieve this from the ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," variable passed in as a prop from ",(0,o.kt)("inlineCode",{parentName:"p"},"src/App.jsx"),". Write this function under your ",(0,o.kt)("inlineCode",{parentName:"p"},"UpdateMessage")," component function."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'const NODE_URL = "http://65.108.127.242:7777/rpc";\nconst NETWORK_NAME = "casper-test"; // "casper" for mainnet\nconst CONTRACT_HASH = "hash-75143aa708275b7dead20ac2cc06c1c3eccff4ffcf1eb9aebb8cce7c35cea041";\n\nconst updateMessage = (props, message) => {\n const casperClient = new CasperClient(NODE_URL);\n const contract = new Contracts.Contract(casperClient);\n contract.setContractHash(CONTRACT_HASH);\n const runtimeArguments = RuntimeArgs.fromMap({\n message: CLValueBuilder.string(message),\n });\n const deploy = contract.callEntrypoint(\n "update_message",\n runtimeArguments,\n CLPublicKey.fromHex(props.publicKey),\n NETWORK_NAME,\n "1000000000", // 1 CSPR (10^9 Motes)\n );\n const deployJSON = DeployUtil.deployToJson(deploy);\n provider\n .sign(JSON.stringify(deployJSON), props.publicKey)\n .then((signedDeploy) => {\n // Initiates sign request\n axios\n .post("/sendDeploy", signedDeploy, {\n headers: {\n "Content-Type": "application/json",\n },\n })\n .then((response) => {\n alert(response.data);\n })\n .catch((error) => {\n console.error(error.message);\n });\n })\n .catch((error) => {\n console.error(error.message);\n });\n};\n')),(0,o.kt)("p",null,"In this example, ",(0,o.kt)("inlineCode",{parentName:"p"},"updateMessage")," builds a deploy and forwards it to the Casper Wallet to be signed by the user. Once it's been signed, ",(0,o.kt)("inlineCode",{parentName:"p"},"signedDeploy")," is forwarded to the backend at the ",(0,o.kt)("inlineCode",{parentName:"p"},"/sendDeploy")," endpoint using ",(0,o.kt)("inlineCode",{parentName:"p"},"axios.post")," before being sent off to a Casper node. If an error occurs, or the user rejects the signature request, it will be logged to ",(0,o.kt)("inlineCode",{parentName:"p"},"stderr"),". In this particular example, the result of this deployment will be presented to the user in the form of a JavaScript ",(0,o.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/API/Window/alert"},"alert"),"; however, you may do with the response data as you wish."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"The backend endpoint ",(0,o.kt)("inlineCode",{parentName:"p"},"/sendDeploy")," should handle signed deployment by simply passing it to a Casper node."),(0,o.kt)("p",{parentName:"admonition"},"In Casper node ",(0,o.kt)("inlineCode",{parentName:"p"},"v1.5.0"),", which sets up appropriate CORS headers, it will also be possible to send deployments directly from the browser, without relying on a backend server. This is useful for prototyping, however it is advised that you operate your own node.")),(0,o.kt)("p",null,"Now that this component is created, render it to the user interface in ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx"),", passing along the ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," as a prop:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import React from "react";\nimport Connect from "./Connect";\n// highlight-next-line-green\nimport UpdateMessage from "./UpdateMessage";\nimport "./App.css";\n\nfunction App() {\n const [publicKey, setPublicKey] = React.useState(null);\n return (\n <>\n \n
\n {publicKey !== null && (\n <>\n Wallet connected: {publicKey}\n
\n // highlight-next-line-green\n \n \n )}\n
\n \n );\n}\n')),(0,o.kt)("h2",{id:"query-a-smart-contract"},"Query a Smart Contract"),(0,o.kt)("p",null,"Consider that the message written to the chain during the ",(0,o.kt)("inlineCode",{parentName:"p"},"update_message")," entrypoint invocation is stored in the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/D#dictionary"},"dictionary")," ",(0,o.kt)("inlineCode",{parentName:"p"},"messages")," in the contract. Further consider that each account may write its own message and that the messages are stored under the account's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/A#account-hash"},"account hash")," as the dictionary key. Querying this kind of data is essential in any dApp; here is how to communicate contract data to and from the front-end."),(0,o.kt)("p",null,"Create a new component:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"touch src/Query.jsx\n")),(0,o.kt)("p",null,"Open the file and write:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import axios from "axios";\nimport { CLPublicKey } from "casper-js-sdk";\n\nconst Query = (props) => {\n return ;\n};\n\nconst query = (props) => {\n const accountHash = CLPublicKey.fromHex(props.publicKey).toAccountHashStr().substring(13);\n axios\n .get("/queryMessage?accountHash=" + accountHash)\n .then((response) => {\n alert(response.data);\n })\n .catch((error) => {\n console.error(error.message);\n });\n};\n\nexport default Query;\n')),(0,o.kt)("p",null,"All this component does is render an HTML ",(0,o.kt)("inlineCode",{parentName:"p"},"button")," element that, when pressed, performs a ",(0,o.kt)("inlineCode",{parentName:"p"},"GET")," request to the backend that includes the user's active account hash. The account hash is derived from the active public key, and is used to look up the message stored by the current user."),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"The ",(0,o.kt)("inlineCode",{parentName:"p"},"toAccountHashStr"),' method produces a string that is prepended by the text "account-hash-". In this case, this text is not needed, so it is discarded by chaining on the ',(0,o.kt)("inlineCode",{parentName:"p"},"substring(13)")," method.")),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"This functionality relies on the ",(0,o.kt)("inlineCode",{parentName:"p"},"/queryMessage")," endpoint, which should be implemented in your backend.")),(0,o.kt)("p",null,"Now add this component to ",(0,o.kt)("em",{parentName:"p"},"src/App.jsx"),", making available the ",(0,o.kt)("inlineCode",{parentName:"p"},"publicKey")," state variable via a prop:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-jsx"},'import React from "react";\nimport Connect from "./Connect";\nimport UpdateMessage from "./UpdateMessage";\n// highlight-next-line-green\nimport Query from "./Query";\nimport "./App.css";\n\nfunction App() {\n const [publicKey, setPublicKey] = React.useState(null);\n return (\n <>\n \n
\n {publicKey !== null && (\n <>\n Wallet connected: {publicKey}\n
\n \n // highlight-next-line-green\n \n \n )}\n
\n \n );\n}\n')),(0,o.kt)("h2",{id:"test-application"},"Test Application"),(0,o.kt)("p",null,"Test your application by running the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"vite dev\n")),(0,o.kt)("p",null,"Your application will start locally, and a URL will be shown where you can visit your application. Alternatively, press ",(0,o.kt)("inlineCode",{parentName:"p"},"h"),", then ",(0,o.kt)("inlineCode",{parentName:"p"},"o")," to open the app in a browser."),(0,o.kt)("h2",{id:"build-for-production"},"Build for Production"),(0,o.kt)("p",null,"When you're ready to release your application, you'll want to compile it to pure JavaScript and serve it from a web server. Do so by running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"vite build\n")),(0,o.kt)("p",null,"Once this is complete, you can preview your production build by running:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"vite preview\n")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b0120e2d.d0f04cdc.js b/assets/js/b0120e2d.d0f04cdc.js deleted file mode 100644 index 549da00617..0000000000 --- a/assets/js/b0120e2d.d0f04cdc.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1636],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return h}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,i=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),f=o,h=p["".concat(i,".").concat(f)]||p[f]||u[f]||r;return n?a.createElement(h,s(s({ref:t},d),{},{components:n})):a.createElement(h,s({ref:t},d))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,s=new Array(r);s[0]=f;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[p]="string"==typeof e?e:o,s[1]=l;for(var c=2;c/events/deploys")),(0,r.kt)("p",null,"With the following command, you can start watching the event stream for DeployAccepted events. Note the event ID recorded when you send the Deploy in the next section."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://65.21.235.219:9999/events/deploys\n")),(0,r.kt)("h2",{id:"sending-the-deploy"},"Sending a Deploy to the Network"),(0,r.kt)("p",null,"You can call the Casper client's ",(0,r.kt)("inlineCode",{parentName:"p"},"put-deploy")," command to put the compiled contract on the chain. In this example, the Deploy will execute in the account's context. See the ",(0,r.kt)("a",{parentName:"p",href:"#advanced-features"},"advanced features")," section for key delegation."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n --node-address \\\n --chain-name casper-test \\\n --secret-key \\\n --payment-amount \\\n --session-path \n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777. You can find a list of trusted peers in network's configuration file, ",(0,r.kt)("inlineCode",{parentName:"li"},"config.toml"),". Here is an ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/dev/resources/production/config-example.toml#L131"},"example"),". You may send deploys to one of the trusted nodes or use them to query other online nodes."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test"),". As you can see, this example uses the Testnet"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This example uses 2.5 CSPR, but you need to modify this for your contract. See the ",(0,r.kt)("a",{parentName:"li",href:"#a-note-about-gas-price"},"note")," below"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the contract Wasm, which should point to wherever you compiled the contract (.wasm file) on your computer")),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's execution results. Sending the deploy and receiving the deploy hash does not mean the deploy was processed successfully. Therefore, you must check the deploy execution using the deploy hash. See the deploy lifecycle for more details."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note"),": Each Deploy gets a unique hash, which is part of the cryptographic security of blockchain technology. No two deploys will ever return the same hash."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Sample put-deploy result"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": -6958186952964949950,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.5",\n "deploy_hash": "34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496"\n }\n}\n'))),(0,r.kt)("p",null,"Verify the deploy details with the ",(0,r.kt)("inlineCode",{parentName:"p"},"get-deploy")," command and the ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," received above."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --node-address \n")),(0,r.kt)("p",null,"If the Deploy succeeded, the ",(0,r.kt)("inlineCode",{parentName:"p"},"get-deploy")," command would return a JSON object with the full deploy details."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Sample get-deploy result"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": -3532286620275982221,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.5",\n "deploy": {\n "approvals": [\n {\n "signature": "015a7b0178e144fbf5ce52147c44a3e6bd6aae898ec6bb47c97b5802f3bcb6cd26331f7db18464cd1e51764c14ceb24b7ab9c4e3595505c32465fc0702e8d5510b",\n "signer": "01e76e0279a08b96d9d68e6b86c618de24a0c324d7d0c1fa8c035f0bc2af1a396d"\n }\n ],\n "hash": "34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496",\n "header": {\n "account": "01e76e0279a08b96d9d68e6b86c618de24a0c324d7d0c1fa8c035f0bc2af1a396d",\n "body_hash": "b1956600be3c11d7555ada11426ab1a8bdf36102f59838d6bf69cec321111a22",\n "chain_name": "casper-test",\n "dependencies": [],\n "gas_price": 1,\n "timestamp": "2022-03-24T12:05:57.579Z",\n "ttl": "30m"\n },\n "payment": {\n "ModuleBytes": {\n "args": [\n [\n "amount",\n {\n "bytes": "05000c774203",\n "cl_type": "U512",\n "parsed": "14000000000"\n }\n ]\n ],\n "module_bytes": ""\n }\n },\n "session": {\n "ModuleBytes": {\n "args": [],\n "module_bytes": "[94478 hex chars]"\n }\n }\n },\n "execution_results": [\n {\n "block_hash": "098b618878a2413393925e1fbf6d3cf92f1208f4f8662a904e86b49b0c4ab9f0",\n "result": {\n "Success": {\n "cost": "13327900740",\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-3a61ed9a3b472f35f4cf1e241d674fad8a5f9509c97a56d62bb03f7bcc4b8474",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-3a61ed9a3b472f35f4cf1e241d674fad8a5f9509c97a56d62bb03f7bcc4b8474",\n "transform": {\n "WriteCLValue": {\n "bytes": "0500279bd1ca",\n "cl_type": "U512",\n "parsed": "871100000000"\n }\n }\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "AddUInt512": "14000000000"\n }\n },\n {\n "key": "uref-82a7b5713f2b9b3f9e1b4f2d1f312a5fec7c3a0bed6fa897501913951729dbbf-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "00000000",\n "cl_type": "I32",\n "parsed": 0\n }\n }\n },\n {\n "key": "uref-ea022d75ff618533baf46040cc57692fb7f7840774c979c9dec0b5c3ddcec7e9-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "",\n "cl_type": "Unit",\n "parsed": null\n }\n }\n },\n {\n "key": "hash-4d0e2bfb5d243ea567e9b37aa8229d2b8b01de838c4bd7ca570a178e012d6b82",\n "transform": "WriteContractPackage"\n },\n {\n "key": "hash-4d0e2bfb5d243ea567e9b37aa8229d2b8b01de838c4bd7ca570a178e012d6b82",\n "transform": "Identity"\n },\n {\n "key": "hash-3b69bafcc13b4541dddd7d5492e4754feee41c636990aeb6bf78d58fdd39fc43",\n "transform": "WriteContractWasm"\n },\n {\n "key": "hash-c39dd923df84c637e46e46a8a3326fcf85e43c60814878f44a08efd0074cb523",\n "transform": "WriteContract"\n },\n {\n "key": "hash-4d0e2bfb5d243ea567e9b37aa8229d2b8b01de838c4bd7ca570a178e012d6b82",\n "transform": "WriteContractPackage"\n },\n {\n "key": "account-hash-f407926760b91c2ce3af8bda7448841b3aa68c6e98053331d10819ef2d0a808e",\n "transform": {\n "AddKeys": [\n {\n "key": "hash-c39dd923df84c637e46e46a8a3326fcf85e43c60814878f44a08efd0074cb523",\n "name": "counter"\n }\n ]\n }\n },\n {\n "key": "deploy-34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496",\n "from": "account-hash-f407926760b91c2ce3af8bda7448841b3aa68c6e98053331d10819ef2d0a808e",\n "gas": "13327900740",\n "source": "uref-3a61ed9a3b472f35f4cf1e241d674fad8a5f9509c97a56d62bb03f7bcc4b8474-007",\n "transfers": []\n }\n }\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-0a24ef56971d46bfefbd5590afe20e5f3482299aba74e1a0fc33a55008cf9453",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "WriteCLValue": {\n "bytes": "00",\n "cl_type": "U512",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-0a24ef56971d46bfefbd5590afe20e5f3482299aba74e1a0fc33a55008cf9453",\n "transform": {\n "AddUInt512": "14000000000"\n }\n }\n ]\n },\n "transfers": []\n }\n }\n }\n ]\n }\n}\n'))),(0,r.kt)("p",null,"We want to draw your attention to a few properties in the example output:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Execution cost 13327900740 motes, yet we paid 14000000000 motes. See the ",(0,r.kt)("a",{parentName:"li",href:"#a-note-about-gas-price"},"note about gas price")),(0,r.kt)("li",{parentName:"ul"},'The contract returned no errors. If you see an "Out of gas error", you did not specify a high enough value in the ',(0,r.kt)("inlineCode",{parentName:"li"},"--payment-amount")," arg"),(0,r.kt)("li",{parentName:"ul"},"The time-to-live was 30 minutes")),(0,r.kt)("p",null,"It is also possible to get a summary of the deploy's information by performing a ",(0,r.kt)("inlineCode",{parentName:"p"},"query-global-state")," command using the Casper client and providing a state root hash or a block hash from a block at or after the one in which the deploy was executed."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address \n\ncasper-client query-global-state --node-address \\\n --key deploy- \\\n --state-root-hash \n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state --node-address \\\n --key deploy-\n --block-hash \n")),(0,r.kt)("p",null,"Run the help command for ",(0,r.kt)("inlineCode",{parentName:"p"},"query-global-state")," to see its usage."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state --help\n")),(0,r.kt)("h3",{id:"ttl"},"Time-to-live"),(0,r.kt)("p",null,"Time-to-live is the parameter that determines how long a deploy will wait for execution. The acceptable maximum ",(0,r.kt)("inlineCode",{parentName:"p"},"ttl")," is configurable by chain, with the Casper Mainnet maximum set to ",(0,r.kt)("inlineCode",{parentName:"p"},"18hours"),". If you are sending a deploy to a different network, you will need to check ",(0,r.kt)("inlineCode",{parentName:"p"},"chainspec.toml")," for that network to determine the acceptable maximum. The minimum is theoretically zero, but this will result in an immediate expiration and an invalid deploy."),(0,r.kt)("p",null,"In the event of a network outage or other event that prevents execution within the ",(0,r.kt)("inlineCode",{parentName:"p"},"ttl"),", the solution is to resend the deploy in question."),(0,r.kt)("p",null,"Should the deploy's ",(0,r.kt)("inlineCode",{parentName:"p"},"ttl")," exceed the allowable limit, or if the deploy expires, the network's deploy acceptor will find the deploy invalid and return a warning."),(0,r.kt)("h3",{id:"deploy-payments"},"Deploy Payments"),(0,r.kt)("p",null,"Dependent upon the complexity and needs of the Deploy in question, several options exist to allow users to pay for smart contract execution."),(0,r.kt)("p",null,"The simplest way to pay for a Deploy on the Casper blockchain is to use the host side standard payment functionality. This can be done using an ",(0,r.kt)("strong",{parentName:"p"},"empty")," ",(0,r.kt)("inlineCode",{parentName:"p"},"ModuleBytes")," as your payment code. However, you must specify the amount within a runtime argument. ",(0,r.kt)("inlineCode",{parentName:"p"},"ModuleBytes")," can also serve as a custom payment contract if it is not empty, but any additional Wasm ran within will come at an additional cost on top of the payment. This includes invalid Wasm, which will still result in additional cost."),(0,r.kt)("p",null,"You may find the host side functionality of standard payment insufficient for your purposes. In this event, Casper provides the following options for custom payment code:"),(0,r.kt)("p",null,"\u2022 ",(0,r.kt)("inlineCode",{parentName:"p"},"StoredContractByHash")),(0,r.kt)("p",null,"\u2022 ",(0,r.kt)("inlineCode",{parentName:"p"},"StoredContractByName")),(0,r.kt)("p",null,"\u2022 ",(0,r.kt)("inlineCode",{parentName:"p"},"StoredVersionContractByHash")),(0,r.kt)("p",null,"\u2022 ",(0,r.kt)("inlineCode",{parentName:"p"},"StoredVersionContractByName")),(0,r.kt)("h2",{id:"using-arguments-with-deploys"},"Using Arguments with Deploys"),(0,r.kt)("p",null,"The session Wasm (or payment Wasm if you choose to ",(0,r.kt)("em",{parentName:"p"},"not"),' use the standard payment) of a Deploy often requires arguments to be passed to it when executed. These "runtime args" should be provided by using the ',(0,r.kt)("inlineCode",{parentName:"p"},"--session-arg")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"--payment-arg")," options, once for each arg required. The Casper client provides some examples of how to do this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy --show-arg-examples\n")),(0,r.kt)("h2",{id:"advanced-features"},"Advanced Features"),(0,r.kt)("p",null,"Casper networks support complex deploys using multiple signatures. ",(0,r.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Casper Accounts")," use a powerful permissions model that enables a multi-signature scheme for deploys."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"put-deploy")," command performs multiple actions under the hood, optimizing the typical use case. It creates a deploy, signs it, and sends the Deploy to the network without allowing multiple signatures. However, it is possible to call the following three commands and separate key management from account creation:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"make-deploy")," - Creates a Deploy and outputs it to a file or stdout. As a file, the deploy can subsequently be signed by other parties using the ",(0,r.kt)("inlineCode",{parentName:"li"},"sign-deploy")," subcommand and then sent to the network for execution using the ",(0,r.kt)("inlineCode",{parentName:"li"},"send-deploy")," subcommand"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sign-deploy")," - Reads a previously-saved Deploy from a file, cryptographically signs it, and outputs it to a file or stdout"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"send-deploy")," - Reads a previously-saved Deploy from a file and sends it to the network for execution")),(0,r.kt)("p",null,"To sign a Deploy with multiple keys, create the Deploy with the ",(0,r.kt)("inlineCode",{parentName:"p"},"make-deploy")," command. The generated deploy file can be sent to the other signers, who then sign it with their keys by calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"sign-deploy")," for each key. Signatures need to be gathered on the Deploy one after another until all required parties have signed the Deploy. Finally, the signed Deploy is sent to the network with the ",(0,r.kt)("inlineCode",{parentName:"p"},"send-deploy")," command for processing."),(0,r.kt)("p",null,"For a step-by-step workflow, visit the ",(0,r.kt)("a",{parentName:"p",href:"/developers/cli/transfers/multisig-deploy-transfer"},"Two-Party Multi-Signature Deploy")," guide. This workflow describes how a trivial two-party multi-signature scheme for signing and sending deploys can be enforced for an account on a Casper network."),(0,r.kt)("h2",{id:"a-note-about-gas-price"},"A Note about Gas Price"),(0,r.kt)("p",null,'A common question frequently arises: "How do I know what the payment amount (gas cost) should be?"'),(0,r.kt)("p",null,"We recommend installing your contracts in a test environment, making sure the cost tables match those of the production Casper network to which you want to send the deploy. If you plan on sending a deploy to ",(0,r.kt)("a",{parentName:"p",href:"https://cspr.live/"},"Mainnet"),", you can use the ",(0,r.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"Testnet")," to estimate the payment amount needed for the deploy."),(0,r.kt)("p",null,"If your test configuration matches your production ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),", you can check the deploy status and roughly see how much it would cost. You can estimate the costs in this way and then add a small buffer to be sure. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/runtime#gas-allocation"},"runtime economics")," section for more details about gas usage and fees."),(0,r.kt)("p",null,"Please be aware that sending a deploy always requires payment. This is true regardless of the validity of included Wasm."),(0,r.kt)("p",null,"If the deploy failure occurs after session execution begins, the penalty payment of 2.5 CSPR is included in the gas costs of the ",(0,r.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#executionresult-executionresult"},"failed execution"),"."),(0,r.kt)("p",null,"However, if the failure occurs prior to session execution, the penalty payment will not appear within the gas cost of the deploy. Instead, the system automatically deducts the 2.5 CSPR from the sending account's main purse."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b0120e2d.d0f70710.js b/assets/js/b0120e2d.d0f70710.js new file mode 100644 index 0000000000..39eb5c1157 --- /dev/null +++ b/assets/js/b0120e2d.d0f70710.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1636],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return h}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,i=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),f=o,h=p["".concat(i,".").concat(f)]||p[f]||u[f]||r;return n?a.createElement(h,s(s({ref:t},d),{},{components:n})):a.createElement(h,s({ref:t},d))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,s=new Array(r);s[0]=f;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[p]="string"==typeof e?e:o,s[1]=l;for(var c=2;c/events/deploys")),(0,r.kt)("p",null,"With the following command, you can start watching the event stream for DeployAccepted events. Note the event ID recorded when you send the Deploy in the next section."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://65.21.235.219:9999/events/deploys\n")),(0,r.kt)("h2",{id:"sending-the-deploy"},"Sending a Deploy to the Network"),(0,r.kt)("p",null,"You can call the Casper client's ",(0,r.kt)("inlineCode",{parentName:"p"},"put-deploy")," command to put the compiled contract on the chain. In this example, the Deploy will execute in the account's context. See the ",(0,r.kt)("a",{parentName:"p",href:"#advanced-features"},"advanced features")," section for key delegation."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n --node-address \\\n --chain-name casper-test \\\n --secret-key \\\n --payment-amount \\\n --session-path \n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777. You can find a list of trusted peers in network's configuration file, ",(0,r.kt)("inlineCode",{parentName:"li"},"config.toml"),". Here is an ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/dev/resources/production/config-example.toml#L131"},"example"),". You may send deploys to one of the trusted nodes or use them to query other online nodes."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test"),". As you can see, this example uses the Testnet"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This example uses 2.5 CSPR, but you need to modify this for your contract. See the ",(0,r.kt)("a",{parentName:"li",href:"#a-note-about-gas-price"},"note")," below"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the contract Wasm, which should point to wherever you compiled the contract (.wasm file) on your computer")),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's execution results. Sending the deploy and receiving the deploy hash does not mean the deploy was processed successfully. Therefore, you must check the deploy execution using the deploy hash. See the deploy lifecycle for more details."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note"),": Each Deploy gets a unique hash, which is part of the cryptographic security of blockchain technology. No two deploys will ever return the same hash."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Sample put-deploy result"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": -6958186952964949950,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.5",\n "deploy_hash": "34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496"\n }\n}\n'))),(0,r.kt)("p",null,"Verify the deploy details with the ",(0,r.kt)("inlineCode",{parentName:"p"},"get-deploy")," command and the ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," received above."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy \\\n --node-address \n")),(0,r.kt)("p",null,"If the Deploy succeeded, the ",(0,r.kt)("inlineCode",{parentName:"p"},"get-deploy")," command would return a JSON object with the full deploy details."),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Sample get-deploy result"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": -3532286620275982221,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.5",\n "deploy": {\n "approvals": [\n {\n "signature": "015a7b0178e144fbf5ce52147c44a3e6bd6aae898ec6bb47c97b5802f3bcb6cd26331f7db18464cd1e51764c14ceb24b7ab9c4e3595505c32465fc0702e8d5510b",\n "signer": "01e76e0279a08b96d9d68e6b86c618de24a0c324d7d0c1fa8c035f0bc2af1a396d"\n }\n ],\n "hash": "34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496",\n "header": {\n "account": "01e76e0279a08b96d9d68e6b86c618de24a0c324d7d0c1fa8c035f0bc2af1a396d",\n "body_hash": "b1956600be3c11d7555ada11426ab1a8bdf36102f59838d6bf69cec321111a22",\n "chain_name": "casper-test",\n "dependencies": [],\n "gas_price": 1,\n "timestamp": "2022-03-24T12:05:57.579Z",\n "ttl": "30m"\n },\n "payment": {\n "ModuleBytes": {\n "args": [\n [\n "amount",\n {\n "bytes": "05000c774203",\n "cl_type": "U512",\n "parsed": "14000000000"\n }\n ]\n ],\n "module_bytes": ""\n }\n },\n "session": {\n "ModuleBytes": {\n "args": [],\n "module_bytes": "[94478 hex chars]"\n }\n }\n },\n "execution_results": [\n {\n "block_hash": "098b618878a2413393925e1fbf6d3cf92f1208f4f8662a904e86b49b0c4ab9f0",\n "result": {\n "Success": {\n "cost": "13327900740",\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-3a61ed9a3b472f35f4cf1e241d674fad8a5f9509c97a56d62bb03f7bcc4b8474",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-3a61ed9a3b472f35f4cf1e241d674fad8a5f9509c97a56d62bb03f7bcc4b8474",\n "transform": {\n "WriteCLValue": {\n "bytes": "0500279bd1ca",\n "cl_type": "U512",\n "parsed": "871100000000"\n }\n }\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "AddUInt512": "14000000000"\n }\n },\n {\n "key": "uref-82a7b5713f2b9b3f9e1b4f2d1f312a5fec7c3a0bed6fa897501913951729dbbf-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "00000000",\n "cl_type": "I32",\n "parsed": 0\n }\n }\n },\n {\n "key": "uref-ea022d75ff618533baf46040cc57692fb7f7840774c979c9dec0b5c3ddcec7e9-000",\n "transform": {\n "WriteCLValue": {\n "bytes": "",\n "cl_type": "Unit",\n "parsed": null\n }\n }\n },\n {\n "key": "hash-4d0e2bfb5d243ea567e9b37aa8229d2b8b01de838c4bd7ca570a178e012d6b82",\n "transform": "WriteContractPackage"\n },\n {\n "key": "hash-4d0e2bfb5d243ea567e9b37aa8229d2b8b01de838c4bd7ca570a178e012d6b82",\n "transform": "Identity"\n },\n {\n "key": "hash-3b69bafcc13b4541dddd7d5492e4754feee41c636990aeb6bf78d58fdd39fc43",\n "transform": "WriteContractWasm"\n },\n {\n "key": "hash-c39dd923df84c637e46e46a8a3326fcf85e43c60814878f44a08efd0074cb523",\n "transform": "WriteContract"\n },\n {\n "key": "hash-4d0e2bfb5d243ea567e9b37aa8229d2b8b01de838c4bd7ca570a178e012d6b82",\n "transform": "WriteContractPackage"\n },\n {\n "key": "account-hash-f407926760b91c2ce3af8bda7448841b3aa68c6e98053331d10819ef2d0a808e",\n "transform": {\n "AddKeys": [\n {\n "key": "hash-c39dd923df84c637e46e46a8a3326fcf85e43c60814878f44a08efd0074cb523",\n "name": "counter"\n }\n ]\n }\n },\n {\n "key": "deploy-34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496",\n "from": "account-hash-f407926760b91c2ce3af8bda7448841b3aa68c6e98053331d10819ef2d0a808e",\n "gas": "13327900740",\n "source": "uref-3a61ed9a3b472f35f4cf1e241d674fad8a5f9509c97a56d62bb03f7bcc4b8474-007",\n "transfers": []\n }\n }\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",\n "transform": "Identity"\n },\n {\n "key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",\n "transform": "Identity"\n },\n {\n "key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": "Identity"\n },\n {\n "key": "balance-0a24ef56971d46bfefbd5590afe20e5f3482299aba74e1a0fc33a55008cf9453",\n "transform": "Identity"\n },\n {\n "key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",\n "transform": {\n "WriteCLValue": {\n "bytes": "00",\n "cl_type": "U512",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-0a24ef56971d46bfefbd5590afe20e5f3482299aba74e1a0fc33a55008cf9453",\n "transform": {\n "AddUInt512": "14000000000"\n }\n }\n ]\n },\n "transfers": []\n }\n }\n }\n ]\n }\n}\n'))),(0,r.kt)("p",null,"We want to draw your attention to a few properties in the example output:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Execution cost 13327900740 motes, yet we paid 14000000000 motes. See the ",(0,r.kt)("a",{parentName:"li",href:"#a-note-about-gas-price"},"note about gas price")),(0,r.kt)("li",{parentName:"ul"},'The contract returned no errors. If you see an "Out of gas error", you did not specify a high enough value in the ',(0,r.kt)("inlineCode",{parentName:"li"},"--payment-amount")," arg"),(0,r.kt)("li",{parentName:"ul"},"The time-to-live was 30 minutes")),(0,r.kt)("p",null,"It is also possible to get a summary of the deploy's information by performing a ",(0,r.kt)("inlineCode",{parentName:"p"},"query-global-state")," command using the Casper client and providing a state root hash or a block hash from a block at or after the one in which the deploy was executed."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address \n\ncasper-client query-global-state --node-address \\\n --key deploy- \\\n --state-root-hash \n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state --node-address \\\n --key deploy-\n --block-hash \n")),(0,r.kt)("p",null,"Run the help command for ",(0,r.kt)("inlineCode",{parentName:"p"},"query-global-state")," to see its usage."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state --help\n")),(0,r.kt)("h3",{id:"ttl"},"Time-to-live"),(0,r.kt)("p",null,"Time-to-live is the parameter that determines how long a deploy will wait for execution. The acceptable maximum ",(0,r.kt)("inlineCode",{parentName:"p"},"ttl")," is configurable by chain, with the Casper Mainnet maximum set to ",(0,r.kt)("inlineCode",{parentName:"p"},"18hours"),". If you are sending a deploy to a different network, you will need to check ",(0,r.kt)("inlineCode",{parentName:"p"},"chainspec.toml")," for that network to determine the acceptable maximum. The minimum is theoretically zero, but this will result in an immediate expiration and an invalid deploy."),(0,r.kt)("p",null,"In the event of a network outage or other event that prevents execution within the ",(0,r.kt)("inlineCode",{parentName:"p"},"ttl"),", the solution is to resend the deploy in question."),(0,r.kt)("p",null,"Should the deploy's ",(0,r.kt)("inlineCode",{parentName:"p"},"ttl")," exceed the allowable limit, or if the deploy expires, the network's deploy acceptor will find the deploy invalid and return a warning."),(0,r.kt)("h3",{id:"deploy-payments"},"Deploy Payments"),(0,r.kt)("p",null,"Dependent upon the complexity and needs of the Deploy in question, several options exist to allow users to pay for smart contract execution."),(0,r.kt)("p",null,"The simplest way to pay for a Deploy on the Casper blockchain is to use the host side standard payment functionality. This can be done using an ",(0,r.kt)("strong",{parentName:"p"},"empty")," ",(0,r.kt)("inlineCode",{parentName:"p"},"ModuleBytes")," as your payment code. However, you must specify the amount within a runtime argument. ",(0,r.kt)("inlineCode",{parentName:"p"},"ModuleBytes")," can also serve as a custom payment contract if it is not empty, but any additional Wasm ran within will come at an additional cost on top of the payment. This includes invalid Wasm, which will still result in additional cost."),(0,r.kt)("p",null,"You may find the host side functionality of standard payment insufficient for your purposes. In this event, Casper provides the following options for custom payment code:"),(0,r.kt)("p",null,"\u2022 ",(0,r.kt)("inlineCode",{parentName:"p"},"StoredContractByHash")),(0,r.kt)("p",null,"\u2022 ",(0,r.kt)("inlineCode",{parentName:"p"},"StoredContractByName")),(0,r.kt)("p",null,"\u2022 ",(0,r.kt)("inlineCode",{parentName:"p"},"StoredVersionContractByHash")),(0,r.kt)("p",null,"\u2022 ",(0,r.kt)("inlineCode",{parentName:"p"},"StoredVersionContractByName")),(0,r.kt)("h2",{id:"using-arguments-with-deploys"},"Using Arguments with Deploys"),(0,r.kt)("p",null,"The session Wasm (or payment Wasm if you choose to ",(0,r.kt)("em",{parentName:"p"},"not"),' use the standard payment) of a Deploy often requires arguments to be passed to it when executed. These "runtime args" should be provided by using the ',(0,r.kt)("inlineCode",{parentName:"p"},"--session-arg")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"--payment-arg")," options, once for each arg required. The Casper client provides some examples of how to do this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy --show-arg-examples\n")),(0,r.kt)("h2",{id:"advanced-features"},"Advanced Features"),(0,r.kt)("p",null,"Casper networks support complex deploys using multiple signatures. ",(0,r.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Casper Accounts")," use a powerful permissions model that enables a multi-signature scheme for deploys."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"put-deploy")," command performs multiple actions under the hood, optimizing the typical use case. It creates a deploy, signs it, and sends the Deploy to the network without allowing multiple signatures. However, it is possible to call the following three commands and separate key management from account creation:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"make-deploy")," - Creates a Deploy and outputs it to a file or stdout. As a file, the deploy can subsequently be signed by other parties using the ",(0,r.kt)("inlineCode",{parentName:"li"},"sign-deploy")," subcommand and then sent to the network for execution using the ",(0,r.kt)("inlineCode",{parentName:"li"},"send-deploy")," subcommand"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"sign-deploy")," - Reads a previously-saved Deploy from a file, cryptographically signs it, and outputs it to a file or stdout"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"send-deploy")," - Reads a previously-saved Deploy from a file and sends it to the network for execution")),(0,r.kt)("p",null,"To sign a Deploy with multiple keys, create the Deploy with the ",(0,r.kt)("inlineCode",{parentName:"p"},"make-deploy")," command. The generated deploy file can be sent to the other signers, who then sign it with their keys by calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"sign-deploy")," for each key. Signatures need to be gathered on the Deploy one after another until all required parties have signed the Deploy. Finally, the signed Deploy is sent to the network with the ",(0,r.kt)("inlineCode",{parentName:"p"},"send-deploy")," command for processing."),(0,r.kt)("p",null,"For a step-by-step workflow, visit the ",(0,r.kt)("a",{parentName:"p",href:"/developers/cli/transfers/multisig-deploy-transfer"},"Two-Party Multi-Signature Deploy")," guide. This workflow describes how a trivial two-party multi-signature scheme for signing and sending deploys can be enforced for an account on a Casper network."),(0,r.kt)("h2",{id:"a-note-about-gas-price"},"A Note about Gas Price"),(0,r.kt)("p",null,'A common question frequently arises: "How do I know what the payment amount (gas cost) should be?"'),(0,r.kt)("p",null,"We recommend installing your contracts in a test environment, making sure the cost tables match those of the production Casper network to which you want to send the deploy. If you plan on sending a deploy to ",(0,r.kt)("a",{parentName:"p",href:"https://cspr.live/"},"Mainnet"),", you can use the ",(0,r.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"Testnet")," to estimate the payment amount needed for the deploy."),(0,r.kt)("p",null,"If your test configuration matches your production ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),", you can check the deploy status and roughly see how much it would cost. You can estimate the costs in this way and then add a small buffer to be sure. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/runtime#gas-allocation"},"runtime economics")," section for more details about gas usage and fees."),(0,r.kt)("p",null,"Please be aware that sending a deploy always requires payment. This is true regardless of the validity of included Wasm."),(0,r.kt)("p",null,"If the deploy failure occurs after session execution begins, the penalty payment of 2.5 CSPR is included in the gas costs of the ",(0,r.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#executionresult-executionresult"},"failed execution"),"."),(0,r.kt)("p",null,"However, if the failure occurs prior to session execution, the penalty payment will not appear within the gas cost of the deploy. Instead, the system automatically deducts the 2.5 CSPR from the sending account's main purse."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b161625a.6fb73e78.js b/assets/js/b161625a.6fb73e78.js deleted file mode 100644 index 2c68595640..0000000000 --- a/assets/js/b161625a.6fb73e78.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[420],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return m}});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=l(n),h=r,m=p["".concat(c,".").concat(h)]||p[h]||u[h]||a;return n?o.createElement(m,i(i({ref:t},d),{},{components:n})):o.createElement(m,i({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,c=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=l(n),h=r,m=p["".concat(c,".").concat(h)]||p[h]||u[h]||a;return n?o.createElement(m,i(i({ref:t},d),{},{components:n})):o.createElement(m,i({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,i=new Array(a);i[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=l(n),h=a,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||r;return n?o.createElement(m,s(s({ref:t},p),{},{components:n})):o.createElement(m,s({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,s=new Array(r);s[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:a,s[1]=i;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=o.createContext({}),l=function(e){var t=o.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=l(e.components);return o.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},h=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=l(n),h=a,m=u["".concat(c,".").concat(h)]||u[h]||d[h]||r;return n?o.createElement(m,s(s({ref:t},p),{},{components:n})):o.createElement(m,s({ref:t},p))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,s=new Array(r);s[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:a,s[1]=i;for(var l=2;l=0||(r[e]=t[e]);return r}(t,a);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,e)&&(r[e]=t[e])}return r}var s=n.createContext({}),m=function(t){var a=n.useContext(s),e=a;return t&&(e="function"==typeof t?t(a):p(p({},a),t)),e},d=function(t){var a=m(t.components);return n.createElement(s.Provider,{value:a},t.children)},o="mdxType",u={inlineCode:"code",wrapper:function(t){var a=t.children;return n.createElement(n.Fragment,{},a)}},k=n.forwardRef((function(t,a){var e=t.components,r=t.mdxType,l=t.originalType,s=t.parentName,d=i(t,["components","mdxType","originalType","parentName"]),o=m(e),k=r,c=o["".concat(s,".").concat(k)]||o[k]||u[k]||l;return e?n.createElement(c,p(p({ref:a},d),{},{components:e})):n.createElement(c,p({ref:a},d))}));function c(t,a){var e=arguments,r=a&&a.mdxType;if("string"==typeof t||r){var l=e.length,p=new Array(l);p[0]=k;var i={};for(var s in a)hasOwnProperty.call(a,s)&&(i[s]=a[s]);i.originalType=t,i[o]="string"==typeof t?t:r,p[1]=i;for(var m=2;m=0||(r[e]=t[e]);return r}(t,a);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,e)&&(r[e]=t[e])}return r}var s=n.createContext({}),m=function(t){var a=n.useContext(s),e=a;return t&&(e="function"==typeof t?t(a):p(p({},a),t)),e},d=function(t){var a=m(t.components);return n.createElement(s.Provider,{value:a},t.children)},o="mdxType",u={inlineCode:"code",wrapper:function(t){var a=t.children;return n.createElement(n.Fragment,{},a)}},k=n.forwardRef((function(t,a){var e=t.components,r=t.mdxType,l=t.originalType,s=t.parentName,d=i(t,["components","mdxType","originalType","parentName"]),o=m(e),k=r,c=o["".concat(s,".").concat(k)]||o[k]||u[k]||l;return e?n.createElement(c,p(p({ref:a},d),{},{components:e})):n.createElement(c,p({ref:a},d))}));function c(t,a){var e=arguments,r=a&&a.mdxType;if("string"==typeof t||r){var l=e.length,p=new Array(l);p[0]=k;var i={};for(var s in a)hasOwnProperty.call(a,s)&&(i[s]=a[s]);i.originalType=t,i[o]="string"==typeof t?t:r,p[1]=i;for(var m=2;m=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=p(a),m=r,y=d["".concat(s,".").concat(m)]||d[m]||u[m]||l;return a?n.createElement(y,i(i({ref:t},c),{},{components:a})):n.createElement(y,i({ref:t},c))}));function y(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,i=new Array(l);i[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:r,i[1]=o;for(var p=2;p=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=p(a),m=r,y=d["".concat(s,".").concat(m)]||d[m]||u[m]||l;return a?n.createElement(y,i(i({ref:t},c),{},{components:a})):n.createElement(y,i({ref:t},c))}));function y(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,i=new Array(l);i[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:r,i[1]=o;for(var p=2;p=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=l(n),m=a,h=u["".concat(c,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(h,s(s({ref:t},p),{},{components:n})):r.createElement(h,s({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:a,s[1]=i;for(var l=2;lCargo.toml",id:"dependencies-in-cargotoml",level:3},{value:"Updating the main.rs File",id:"updating-the-mainrs-file",level:3},{value:"Example 2: Calling a Contract with Session Code",id:"calling-contracts-with-session-code",level:2},{value:"Example 3: Transfers using Session Code",id:"transfers-using-session-code",level:2},{value:"Compiling Session Code",id:"compiling-session-code",level:2},{value:"Executing Session Code",id:"executing-session-code",level:2},{value:"Video Walkthrough",id:"video-walkthrough",level:2},{value:"What's Next?",id:"whats-next",level:2}],d={toc:u},m="wrapper";function h(e){var t=e.components,n=(0,a.Z)(e,s);return(0,o.kt)(m,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"writing-session-code"},"Writing Session Code"),(0,o.kt)("p",null,"This section explains how to write session code. To review the definition of session code and the differences between session code and contract code, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"Comparing Session Code and Contract Code"),". Session code can be written in any programming language that compiles to Wasm. However, the examples in this topic use Rust."),(0,o.kt)("h2",{id:"directory-structure"},"Creating the Directory Structure"),(0,o.kt)("p",null,"For writing session code, we use the same project structure used for writing contracts, described ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract#directory-structure"},"here"),"."),(0,o.kt)("h2",{id:"writing-session-code"},"Example 1: Writing Session Code"),(0,o.kt)("p",null,"The following steps illustrate the process of writing session code using an example repository containing sample session code for configuring an account: ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/"},"https://github.com/casper-ecosystem/two-party-multi-sig/"),". The sample code adds an associated key to the account and updates the action thresholds. Remember that an ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Account")," on a Casper network can add associated accounts and set up a multi-signature scheme for deploys. To follow along, clone the repository."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-ecosystem/two-party-multi-sig/\n")),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Before executing session code, ensure that you know exactly what the session code is doing. If you don't know what it is meant for, it could be doing something malicious.")),(0,o.kt)("h3",{id:"dependencies-in-cargotoml"},"Dependencies in ",(0,o.kt)("inlineCode",{parentName:"h3"},"Cargo.toml")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file includes the dependencies and versions the session code requires. At a minimum, you need to import the latest versions of the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/"},"casper-contract")," and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/"},"casper-types")," crates. The following dependencies and version numbers are only examples and must be adjusted based on your requirements."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'casper-contract = "1.4.4"')," - Provides the SDK for the execution engine (EE). The latest version of the crate is published ",(0,o.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-contract"},"here"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'casper-types = "1.5.0"')," - Includes types shared by many Casper crates for use on a Casper network. This crate is necessary for the EE to understand and interpret the session code. The latest version of the crate is published ",(0,o.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-types"},"here"),".")),(0,o.kt)("h3",{id:"updating-the-mainrs-file"},"Updating the ",(0,o.kt)("inlineCode",{parentName:"h3"},"main.rs")," File"),(0,o.kt)("p",null,"Open the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract/src/main.rs")," file that contains the sample session code. Notice these directives at the top of the file:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"#![no_std]")," - Specifies not to import the standard library."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"#![no_main]")," - Indicates the ",(0,o.kt)("inlineCode",{parentName:"li"},"main")," function is not required since the session code has only one entry point as the ",(0,o.kt)("inlineCode",{parentName:"li"},"call")," function.")),(0,o.kt)("p",null,"Next, review the imported crates and other required libraries."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"#![no_std]\n#![no_main]\n\nuse casper_contract::contract_api::{account, runtime};\nuse casper_contract::unwrap_or_revert::UnwrapOrRevert;\nuse casper_types::account::{AccountHash, ActionType, Weight};\n")),(0,o.kt)("p",null,"After the imported libraries, we usually find the constants."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'const ASSOCIATED_ACCOUNT: &str = "deployment-account";\n')),(0,o.kt)("p",null,"Next, we see the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function, the only entry point in this example session code. The ",(0,o.kt)("inlineCode",{parentName:"p"},"#[no_mangle]")," flag ensures that the function name is retained as a string in the Wasm binary. For session code, this flag retains the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," string and marks the entry point for the execution engine. Explore the call function details by opening the cloned project."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n // Open the repository for details\n}\n')),(0,o.kt)("p",null,"When compiled, the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function could be used from another library. For example, a C library could link to the resulting Wasm."),(0,o.kt)("h2",{id:"calling-contracts-with-session-code"},"Example 2: Calling a Contract with Session Code"),(0,o.kt)("p",null,"Another example of session code is the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/counter-call/src/main.rs"},"counter-call/src/main.rs")," file, in the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter"},"counter")," repository. This example shows how we commonly use session code to invoke logic stored within a smart contract. To follow along, clone the repository."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-ecosystem/counter/\n")),(0,o.kt)("p",null,"Observe how the project is set up and review the dependencies in the ",(0,o.kt)("inlineCode",{parentName:"p"},"counter/counter-call/Cargo.toml")," file. Then, open the ",(0,o.kt)("inlineCode",{parentName:"p"},"counter/counter-call/src/main.rs")," file containing the session code. Notice the directives at the top of the file, the required dependencies, and the declared constants."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function interacts with the contract's ",(0,o.kt)("inlineCode",{parentName:"p"},"counter_inc")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"counter_get")," entry points. This is how the session's ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point triggers the logic stored inside the counter contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"}," // Call the counter to get the current value.\n let current_counter_value: u32 =\n runtime::call_contract(contract_hash, COUNTER_GET, RuntimeArgs::new());\n\n // Call the counter to increment the value.\n let _: () = runtime::call_contract(contract_hash, COUNTER_INC, RuntimeArgs::new());\n")),(0,o.kt)("h2",{id:"transfers-using-session-code"},"Example 3: Transfers using Session Code"),(0,o.kt)("p",null,"In this example, we use session code to perform a transfer using the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_from_purse_to_purse.html"},"transfer_from_purse_to_purse")," system function. The entire session code is available in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/67c9c9bb84fdfc3f2d12103e25f0058104342bc0/smart_contracts/contracts/bench/transfer-to-purse/src/main.rs#L14"},"GitHub"),", but this is the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n let target_purse: URef = runtime::get_named_arg(ARG_TARGET_PURSE);\n let amount: U512 = runtime::get_named_arg(ARG_AMOUNT);\n\n let source_purse = account::get_main_purse();\n\n system::transfer_from_purse_to_purse(source_purse, target_purse, amount, None)\n .unwrap_or_revert();\n}\n')),(0,o.kt)("p",null,"Another system function is ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_to_public_key.html"},"transfer_to_public_key"),". The full session code example is on ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/67c9c9bb84fdfc3f2d12103e25f0058104342bc0/smart_contracts/contracts/client/transfer-to-public-key/src/main.rs#L16"},"GitHub"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n let account_hash: PublicKey = runtime::get_named_arg(ARG_TARGET);\n let transfer_amount: U512 = runtime::get_named_arg(ARG_AMOUNT);\n system::transfer_to_public_key(account_hash, transfer_amount, None).unwrap_or_revert();\n}\n')),(0,o.kt)("p",null,"Other transfer functions are available here:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_to_account.html"},"transfer_to_account")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_from_purse_to_account.html"},"transfer_from_purse_to_account")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_from_purse_to_public_key.html"},"transfer_from_purse_to_public_key"))),(0,o.kt)("h2",{id:"compiling-session-code"},"Compiling Session Code"),(0,o.kt)("p",null,"Before running session code to interact with a contract or other entities on the network, you must compile it to Wasm. Run the following command in the directory hosting the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file and ",(0,o.kt)("inlineCode",{parentName:"p"},"src")," folder."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cargo build --release --target wasm32-unknown-unknown\n")),(0,o.kt)("p",null,"For the examples above, you may use the Makefiles provided:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"make build-contract\n")),(0,o.kt)("h2",{id:"executing-session-code"},"Executing Session Code"),(0,o.kt)("p",null,"Before running session code on a live Casper network, test it as described ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/testing-session-code"},"here"),". You can also set up a local network using ",(0,o.kt)("a",{parentName:"p",href:"/developers/dapps/setup-nctl"},"NCTL")," for additional tests."),(0,o.kt)("p",null,"Session code can execute on a Casper network via a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/D#deploy"},"Deploy"),". All deploys can be broadly categorized as some unit of work that, when executed and committed, affects change to the network's global state."),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#the-casper-command-line-client"},"Casper command-line client")," and its ",(0,o.kt)("inlineCode",{parentName:"p"},"put-deploy")," command provide one way to execute session code."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address \\\n --chain-name \\\n --secret-key \\\n --payment-amount \\\n --session-path \\\n --session-arg <"NAME:TYPE=\'VALUE\'" OR "NAME:TYPE=null">\n')),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port for JSON-RPC servers on Mainnet and Testnet is 7777."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the deploy."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The network where the deploy should be sent. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - Payment for the deploy in motes. The payment amount varies based on the deploy and network ",(0,o.kt)("a",{parentName:"li",href:"/concepts/glossary/C#chainspec"},"chainspec"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"session-path")," - Path to the contract Wasm, pointing to the compiled contract."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"session-arg")," - A named and typed argument passed to the Wasm code.")),(0,o.kt)("p",null,"Use the ",(0,o.kt)("inlineCode",{parentName:"p"},"--help")," option to view an updated list of supported arguments."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy --help\n")),(0,o.kt)("h2",{id:"video-walkthrough"},"Video Walkthrough"),(0,o.kt)("p",null,"The following brief video describes ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/"},"sample session code")," for configuring an account."),(0,o.kt)("p",{align:"center"},(0,o.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed?v=sUg0nh3K3iQ&list=PL8oWxbJ-csEqi5FP87EJZViE2aLz6X1Mj&index=4",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,o.kt)("h2",{id:"whats-next"},"What's Next?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Learn to ",(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/testing-session-code"},"test session code")," using the Casper testing framework.")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b5850dcd.f0924895.js b/assets/js/b5850dcd.f0924895.js deleted file mode 100644 index 2d6ca62133..0000000000 --- a/assets/js/b5850dcd.f0924895.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9352],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return h}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=l(n),m=a,h=u["".concat(c,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(h,s(s({ref:t},p),{},{components:n})):r.createElement(h,s({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:a,s[1]=i;for(var l=2;lCargo.toml",id:"dependencies-in-cargotoml",level:3},{value:"Updating the main.rs File",id:"updating-the-mainrs-file",level:3},{value:"Example 2: Calling a Contract with Session Code",id:"calling-contracts-with-session-code",level:2},{value:"Example 3: Transfers using Session Code",id:"transfers-using-session-code",level:2},{value:"Compiling Session Code",id:"compiling-session-code",level:2},{value:"Executing Session Code",id:"executing-session-code",level:2},{value:"Video Walkthrough",id:"video-walkthrough",level:2},{value:"What's Next?",id:"whats-next",level:2}],d={toc:u},m="wrapper";function h(e){var t=e.components,n=(0,a.Z)(e,s);return(0,o.kt)(m,(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"writing-session-code"},"Writing Session Code"),(0,o.kt)("p",null,"This section explains how to write session code. To review the definition of session code and the differences between session code and contract code, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/contract-vs-session#what-is-session-code"},"Comparing Session Code and Contract Code"),". Session code can be written in any programming language that compiles to Wasm. However, the examples in this topic use Rust."),(0,o.kt)("h2",{id:"directory-structure"},"Creating the Directory Structure"),(0,o.kt)("p",null,"For writing session code, we use the same project structure used for writing contracts, described ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/simple-contract#directory-structure"},"here"),"."),(0,o.kt)("h2",{id:"writing-session-code"},"Example 1: Writing Session Code"),(0,o.kt)("p",null,"The following steps illustrate the process of writing session code using an example repository containing sample session code for configuring an account: ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/"},"https://github.com/casper-ecosystem/two-party-multi-sig/"),". The sample code adds an associated key to the account and updates the action thresholds. Remember that an ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"Account")," on a Casper network can add associated accounts and set up a multi-signature scheme for deploys. To follow along, clone the repository."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-ecosystem/two-party-multi-sig/\n")),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Before executing session code, ensure that you know exactly what the session code is doing. If you don't know what it is meant for, it could be doing something malicious.")),(0,o.kt)("h3",{id:"dependencies-in-cargotoml"},"Dependencies in ",(0,o.kt)("inlineCode",{parentName:"h3"},"Cargo.toml")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file includes the dependencies and versions the session code requires. At a minimum, you need to import the latest versions of the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/"},"casper-contract")," and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-types/latest/casper_types/"},"casper-types")," crates. The following dependencies and version numbers are only examples and must be adjusted based on your requirements."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'casper-contract = "1.4.4"')," - Provides the SDK for the execution engine (EE). The latest version of the crate is published ",(0,o.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-contract"},"here"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},'casper-types = "1.5.0"')," - Includes types shared by many Casper crates for use on a Casper network. This crate is necessary for the EE to understand and interpret the session code. The latest version of the crate is published ",(0,o.kt)("a",{parentName:"li",href:"https://crates.io/crates/casper-types"},"here"),".")),(0,o.kt)("h3",{id:"updating-the-mainrs-file"},"Updating the ",(0,o.kt)("inlineCode",{parentName:"h3"},"main.rs")," File"),(0,o.kt)("p",null,"Open the ",(0,o.kt)("inlineCode",{parentName:"p"},"contract/src/main.rs")," file that contains the sample session code. Notice these directives at the top of the file:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"#![no_std]")," - Specifies not to import the standard library."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"#![no_main]")," - Indicates the ",(0,o.kt)("inlineCode",{parentName:"li"},"main")," function is not required since the session code has only one entry point as the ",(0,o.kt)("inlineCode",{parentName:"li"},"call")," function.")),(0,o.kt)("p",null,"Next, review the imported crates and other required libraries."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"#![no_std]\n#![no_main]\n\nuse casper_contract::contract_api::{account, runtime};\nuse casper_contract::unwrap_or_revert::UnwrapOrRevert;\nuse casper_types::account::{AccountHash, ActionType, Weight};\n")),(0,o.kt)("p",null,"After the imported libraries, we usually find the constants."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'const ASSOCIATED_ACCOUNT: &str = "deployment-account";\n')),(0,o.kt)("p",null,"Next, we see the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function, the only entry point in this example session code. The ",(0,o.kt)("inlineCode",{parentName:"p"},"#[no_mangle]")," flag ensures that the function name is retained as a string in the Wasm binary. For session code, this flag retains the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," string and marks the entry point for the execution engine. Explore the call function details by opening the cloned project."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n // Open the repository for details\n}\n')),(0,o.kt)("p",null,"When compiled, the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function could be used from another library. For example, a C library could link to the resulting Wasm."),(0,o.kt)("h2",{id:"calling-contracts-with-session-code"},"Example 2: Calling a Contract with Session Code"),(0,o.kt)("p",null,"Another example of session code is the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter/blob/master/counter-call/src/main.rs"},"counter-call/src/main.rs")," file, in the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/counter"},"counter")," repository. This example shows how we commonly use session code to invoke logic stored within a smart contract. To follow along, clone the repository."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-ecosystem/counter/\n")),(0,o.kt)("p",null,"Observe how the project is set up and review the dependencies in the ",(0,o.kt)("inlineCode",{parentName:"p"},"counter/counter-call/Cargo.toml")," file. Then, open the ",(0,o.kt)("inlineCode",{parentName:"p"},"counter/counter-call/src/main.rs")," file containing the session code. Notice the directives at the top of the file, the required dependencies, and the declared constants."),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function interacts with the contract's ",(0,o.kt)("inlineCode",{parentName:"p"},"counter_inc")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"counter_get")," entry points. This is how the session's ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," entry point triggers the logic stored inside the counter contract."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"}," // Call the counter to get the current value.\n let current_counter_value: u32 =\n runtime::call_contract(contract_hash, COUNTER_GET, RuntimeArgs::new());\n\n // Call the counter to increment the value.\n let _: () = runtime::call_contract(contract_hash, COUNTER_INC, RuntimeArgs::new());\n")),(0,o.kt)("h2",{id:"transfers-using-session-code"},"Example 3: Transfers using Session Code"),(0,o.kt)("p",null,"In this example, we use session code to perform a transfer using the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_from_purse_to_purse.html"},"transfer_from_purse_to_purse")," system function. The entire session code is available in ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/67c9c9bb84fdfc3f2d12103e25f0058104342bc0/smart_contracts/contracts/bench/transfer-to-purse/src/main.rs#L14"},"GitHub"),", but this is the ",(0,o.kt)("inlineCode",{parentName:"p"},"call")," function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n let target_purse: URef = runtime::get_named_arg(ARG_TARGET_PURSE);\n let amount: U512 = runtime::get_named_arg(ARG_AMOUNT);\n\n let source_purse = account::get_main_purse();\n\n system::transfer_from_purse_to_purse(source_purse, target_purse, amount, None)\n .unwrap_or_revert();\n}\n')),(0,o.kt)("p",null,"Another system function is ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_to_public_key.html"},"transfer_to_public_key"),". The full session code example is on ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/67c9c9bb84fdfc3f2d12103e25f0058104342bc0/smart_contracts/contracts/client/transfer-to-public-key/src/main.rs#L16"},"GitHub"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},'#[no_mangle]\npub extern "C" fn call() {\n let account_hash: PublicKey = runtime::get_named_arg(ARG_TARGET);\n let transfer_amount: U512 = runtime::get_named_arg(ARG_AMOUNT);\n system::transfer_to_public_key(account_hash, transfer_amount, None).unwrap_or_revert();\n}\n')),(0,o.kt)("p",null,"Other transfer functions are available here:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_to_account.html"},"transfer_to_account")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_from_purse_to_account.html"},"transfer_from_purse_to_account")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/system/fn.transfer_from_purse_to_public_key.html"},"transfer_from_purse_to_public_key"))),(0,o.kt)("h2",{id:"compiling-session-code"},"Compiling Session Code"),(0,o.kt)("p",null,"Before running session code to interact with a contract or other entities on the network, you must compile it to Wasm. Run the following command in the directory hosting the ",(0,o.kt)("inlineCode",{parentName:"p"},"Cargo.toml")," file and ",(0,o.kt)("inlineCode",{parentName:"p"},"src")," folder."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cargo build --release --target wasm32-unknown-unknown\n")),(0,o.kt)("p",null,"For the examples above, you may use the Makefiles provided:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"make build-contract\n")),(0,o.kt)("h2",{id:"executing-session-code"},"Executing Session Code"),(0,o.kt)("p",null,"Before running session code on a live Casper network, test it as described ",(0,o.kt)("a",{parentName:"p",href:"/developers/writing-onchain-code/testing-session-code"},"here"),". You can also set up a local network using ",(0,o.kt)("a",{parentName:"p",href:"/developers/dapps/setup-nctl"},"NCTL")," for additional tests."),(0,o.kt)("p",null,"Session code can execute on a Casper network via a ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/D#deploy"},"Deploy"),". All deploys can be broadly categorized as some unit of work that, when executed and committed, affects change to the network's global state."),(0,o.kt)("p",null,"The ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#the-casper-command-line-client"},"Casper command-line client")," and its ",(0,o.kt)("inlineCode",{parentName:"p"},"put-deploy")," command provide one way to execute session code."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy \\\n --node-address \\\n --chain-name \\\n --secret-key \\\n --payment-amount \\\n --session-path \\\n --session-arg <"NAME:TYPE=\'VALUE\'" OR "NAME:TYPE=null">\n')),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port for JSON-RPC servers on Mainnet and Testnet is 7777."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the deploy."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The network where the deploy should be sent. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - Payment for the deploy in motes. The payment amount varies based on the deploy and network ",(0,o.kt)("a",{parentName:"li",href:"/concepts/glossary/C#chainspec"},"chainspec"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"session-path")," - Path to the contract Wasm, pointing to the compiled contract."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"session-arg")," - A named and typed argument passed to the Wasm code.")),(0,o.kt)("p",null,"Use the ",(0,o.kt)("inlineCode",{parentName:"p"},"--help")," option to view an updated list of supported arguments."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy --help\n")),(0,o.kt)("h2",{id:"video-walkthrough"},"Video Walkthrough"),(0,o.kt)("p",null,"The following brief video describes ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/casper-ecosystem/two-party-multi-sig/"},"sample session code")," for configuring an account."),(0,o.kt)("p",{align:"center"},(0,o.kt)("iframe",{width:"400",height:"225",src:"https://www.youtube.com/embed?v=sUg0nh3K3iQ&list=PL8oWxbJ-csEqi5FP87EJZViE2aLz6X1Mj&index=4",frameborder:"0",allow:"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0})),(0,o.kt)("h2",{id:"whats-next"},"What's Next?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Learn to ",(0,o.kt)("a",{parentName:"li",href:"/developers/writing-onchain-code/testing-session-code"},"test session code")," using the Casper testing framework.")))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b643e154.6b17dc67.js b/assets/js/b643e154.6b17dc67.js new file mode 100644 index 0000000000..e43a07854b --- /dev/null +++ b/assets/js/b643e154.6b17dc67.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6776],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return g}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),h=o,g=u["".concat(l,".").concat(h)]||u[h]||d[h]||i;return n?a.createElement(g,r(r({ref:t},p),{},{components:n})):a.createElement(g,r({ref:t},p))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:o,r[1]=s;for(var c=2;c=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),h=o,g=u["".concat(l,".").concat(h)]||u[h]||d[h]||i;return n?a.createElement(g,r(r({ref:t},p),{},{components:n})):a.createElement(g,r({ref:t},p))}));function g(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:o,r[1]=s;for(var c=2;c=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),u=p(n),m=r,h=u["".concat(l,".").concat(m)]||u[m]||c[m]||o;return n?a.createElement(h,s(s({ref:t},d),{},{components:n})):a.createElement(h,s({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:r,s[1]=i;for(var p=2;p:8888/metrics\n")),(0,o.kt)("p",null,"You can check the node's status using this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status\n")),(0,o.kt)("p",null,"The status endpoint provides a JSON response that can be parsed with ",(0,o.kt)("inlineCode",{parentName:"p"},"jq"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status | jq\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Sample response"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "api_version": "1.4.15",\n "chainspec_name": "casper-test",\n "starting_state_root_hash": "4c3856bd6a95b566301b9da61aaf84589a51ee2980f3cc7bbef78e7745386955",\n "peers": [\n {\n "node_id": "tls:007e..e14b",\n "address": "89.58.52.245:35000"\n },\n {\n "node_id": "tls:00eb..ac11",\n "address": "65.109.17.120:35000"\n },\n ...{\n "node_id": "tls:ffc0..555b",\n "address": "95.217.228.224:35000"\n }\n ],\n "last_added_block_info": {\n "hash": "7acd2f48b573704e96eab54322f7e91a0624252baca3583ad2aae38229fe1715",\n "timestamp": "2023-05-10T09:20:10.752Z",\n "era_id": 9085,\n "height": 1711254,\n "state_root_hash": "1ac74071c1e76937c372c8d2ae22ea036a77578aad03821ec98021fdc1c5d06b",\n "creator": "0106ca7c39cd272dbf21a86eeb3b36b7c26e2e9b94af64292419f7862936bca2ca"\n },\n "our_public_signing_key": "0107cba5b4826a87ddbe0ba8cda8064881b75882f05094c1a5f95e957512a3450e",\n "round_length": "32s 768ms",\n "next_upgrade": null,\n "build_version": "1.4.15-039d438f2-casper-mainnet",\n "uptime": "5days 13h 46m 54s 520ms"\n}\n'))),(0,o.kt)("p",null,"You can filter the result with dot notation, specifying one of the following parameters:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"api_version")," - The RPC API version"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"chainspec_name")," - The chainspec name, used to identify the currently connected network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"starting_state_root_hash")," - The state root hash used at the start of the current session"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"peers")," - The node ID and network address of each connected peer"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"last_added_block_info")," - The minimal info of the last Block from the linear chain"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"our_public_signing_key")," - Our public signing key"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"round_length")," - The next round length if this node is a validator."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"next_upgrade")," - Information about the next scheduled upgrade"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"build_version")," - The compiled node version"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"uptime")," - Time that has passed since the node has started.")),(0,o.kt)("p",null,"Here is an example command for retrieving general network information:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status | jq -r '.api_version, .last_added_block_info, .build_version, .uptime'\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Sample response"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'"1.4.15"\n{\n "hash": "dca9959b21df52633f85cd373a8117fe8e89629dd2a0455781484a439f7d9f62",\n "timestamp": "2023-05-10T09:26:43.968Z",\n "era_id": 9085,\n "height": 1711266,\n "state_root_hash": "5f374529e747a06ec825e07a030df7b9d80d1f7ffac9156779b4466620721872",\n "creator": "0107cba5b4826a87ddbe0ba8cda8064881b75882f05094c1a5f95e957512a3450e"\n}\n"1.4.15-039d438f2-casper-mainnet"\n"5days 13h 53m 10s 763ms"\n'))),(0,o.kt)("p",null,"To get information about the next upgrade, use:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status | jq .next_upgrade\n")),(0,o.kt)("p",null,"To get information about the last added block, use:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status | jq .last_added_block_info\n")),(0,o.kt)("p",null,"To monitor the downloading of blocks to your node:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"watch -n 15 'curl -s http://:8888/status | jq \".peers | length\"; curl -s http://:8888/status | jq .last_added_block_info'\n")),(0,o.kt)("p",null,"To monitor local block height as well as RPC port status:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"watch -n 15 'curl -s http://:8888/status | jq \".peers | length\"; curl -s http://:8888/status | jq .last_added_block_info; casper-client get-block -n http://:8888/status'\n")),(0,o.kt)("h2",{id:"9999"},"Default SSE HTTP Event Stream Server Port: 9999"),(0,o.kt)("p",null,"The configuration options for the SSE HTTP event stream server are listed under the ",(0,o.kt)("inlineCode",{parentName:"p"},"event_stream_server")," section of the ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," file. The ",(0,o.kt)("inlineCode",{parentName:"p"},"address")," listing port 9999 is the listening address for the SSE HTTP event stream server."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-md"},"address = '0.0.0.0:9999'\n")),(0,o.kt)("p",null,"If this port is closed, the requests coming to this port will not be served, but the node remains unaffected. For details and useful commands, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/dapps/monitor-and-consume-events"},"Monitoring and Consuming Events"),"."),(0,o.kt)("h2",{id:"setting-up-firewall-rules"},"Setting up Firewall Rules"),(0,o.kt)("p",null,"To limit inbound traffic to the node\u2019s endpoints, you can set firewall rules similar to the ",(0,o.kt)("inlineCode",{parentName:"p"},"ufw")," commands below:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install ufw -y\nsudo ufw disable\nsudo ufw reset\nsudo ufw default allow outgoing\nsudo ufw default deny incoming\nsudo ufw limit ssh\nsudo ufw limit 7777/tcp\nsudo ufw limit 8888/tcp\nsudo ufw limit 35000/tcp\nsudo ufw enable\n")),(0,o.kt)("p",null,"These commands will limit requests to the available ports of your node. Port 35000 should be left open, although you can limit traffic, as it is crucial for node-to-node communication."),(0,o.kt)("p",null,"If you have any concerns, questions, or issues, please ",(0,o.kt)("a",{parentName:"p",href:"https://support.casperlabs.io/hc/en-gb/requests/new"},"submit a request")," to the Casper support team."),(0,o.kt)("h2",{id:"restricting-access-for-private-networks"},"Restricting Access for Private Networks"),(0,o.kt)("p",null,"Any node can join Mainnet and Testnet and communicate with the nodes in the network. Private networks may wish to restrict access for new nodes joining the network as described ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup-network/create-private#network-access-control"},"here"),"."),(0,o.kt)("h2",{id:"summary-of-related-links"},"Summary of Related Links"),(0,o.kt)("p",null,"Here is a summary of the links mentioned on this page:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/install-node#network-requirements"},"Network requirements")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/concepts/design/p2p"},"Network communication")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/basic-node-configuration#config-file"},"The node configuration file")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/developers/json-rpc/"},"Interacting with the Casper JSON-RPC API")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/developers/cli/"},"Interacting with the network using CLI")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/becoming-a-validator/bonding#example-bonding-transaction"},"Bonding")," or ",(0,o.kt)("a",{parentName:"li",href:"/operators/becoming-a-validator/unbonding"},"unbonding")," as a validator"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/basic-node-configuration#trusted-hash-for-synchronizing"},"Getting a trusted node hash")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/upgrade#verifying-successful-staging"},"Verifying successful staging")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/joining#step-7-confirm-the-node-is-synchronized"},"Confirming that the node is synchronized")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/developers/dapps/monitor-and-consume-events"},"Monitoring and consuming events")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup-network/create-private#network-access-control"},"Private network access control")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://support.casperlabs.io/hc/en-gb/sections/6960448246683-Node-Operation-FAQ"},"FAQs for a basic validator node ")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.cspr.community/docs/faq-validator.html"},"External FAQs on Mainnet and Testnet validator node setup"))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b74af8d8.eed0a88b.js b/assets/js/b74af8d8.eed0a88b.js new file mode 100644 index 0000000000..63f75a41ea --- /dev/null +++ b/assets/js/b74af8d8.eed0a88b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1942],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),u=p(n),m=r,h=u["".concat(l,".").concat(m)]||u[m]||c[m]||o;return n?a.createElement(h,s(s({ref:t},d),{},{components:n})):a.createElement(h,s({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:r,s[1]=i;for(var p=2;p:8888/metrics\n")),(0,o.kt)("p",null,"You can check the node's status using this command:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status\n")),(0,o.kt)("p",null,"The status endpoint provides a JSON response that can be parsed with ",(0,o.kt)("inlineCode",{parentName:"p"},"jq"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status | jq\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Sample response"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "api_version": "1.4.15",\n "chainspec_name": "casper-test",\n "starting_state_root_hash": "4c3856bd6a95b566301b9da61aaf84589a51ee2980f3cc7bbef78e7745386955",\n "peers": [\n {\n "node_id": "tls:007e..e14b",\n "address": "89.58.52.245:35000"\n },\n {\n "node_id": "tls:00eb..ac11",\n "address": "65.109.17.120:35000"\n },\n ...{\n "node_id": "tls:ffc0..555b",\n "address": "95.217.228.224:35000"\n }\n ],\n "last_added_block_info": {\n "hash": "7acd2f48b573704e96eab54322f7e91a0624252baca3583ad2aae38229fe1715",\n "timestamp": "2023-05-10T09:20:10.752Z",\n "era_id": 9085,\n "height": 1711254,\n "state_root_hash": "1ac74071c1e76937c372c8d2ae22ea036a77578aad03821ec98021fdc1c5d06b",\n "creator": "0106ca7c39cd272dbf21a86eeb3b36b7c26e2e9b94af64292419f7862936bca2ca"\n },\n "our_public_signing_key": "0107cba5b4826a87ddbe0ba8cda8064881b75882f05094c1a5f95e957512a3450e",\n "round_length": "32s 768ms",\n "next_upgrade": null,\n "build_version": "1.4.15-039d438f2-casper-mainnet",\n "uptime": "5days 13h 46m 54s 520ms"\n}\n'))),(0,o.kt)("p",null,"You can filter the result with dot notation, specifying one of the following parameters:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"api_version")," - The RPC API version"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"chainspec_name")," - The chainspec name, used to identify the currently connected network"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"starting_state_root_hash")," - The state root hash used at the start of the current session"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"peers")," - The node ID and network address of each connected peer"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"last_added_block_info")," - The minimal info of the last Block from the linear chain"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"our_public_signing_key")," - Our public signing key"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"round_length")," - The next round length if this node is a validator."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"next_upgrade")," - Information about the next scheduled upgrade"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"build_version")," - The compiled node version"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"uptime")," - Time that has passed since the node has started.")),(0,o.kt)("p",null,"Here is an example command for retrieving general network information:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status | jq -r '.api_version, .last_added_block_info, .build_version, .uptime'\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Sample response"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'"1.4.15"\n{\n "hash": "dca9959b21df52633f85cd373a8117fe8e89629dd2a0455781484a439f7d9f62",\n "timestamp": "2023-05-10T09:26:43.968Z",\n "era_id": 9085,\n "height": 1711266,\n "state_root_hash": "5f374529e747a06ec825e07a030df7b9d80d1f7ffac9156779b4466620721872",\n "creator": "0107cba5b4826a87ddbe0ba8cda8064881b75882f05094c1a5f95e957512a3450e"\n}\n"1.4.15-039d438f2-casper-mainnet"\n"5days 13h 53m 10s 763ms"\n'))),(0,o.kt)("p",null,"To get information about the next upgrade, use:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status | jq .next_upgrade\n")),(0,o.kt)("p",null,"To get information about the last added block, use:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"curl -s http://:8888/status | jq .last_added_block_info\n")),(0,o.kt)("p",null,"To monitor the downloading of blocks to your node:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"watch -n 15 'curl -s http://:8888/status | jq \".peers | length\"; curl -s http://:8888/status | jq .last_added_block_info'\n")),(0,o.kt)("p",null,"To monitor local block height as well as RPC port status:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"watch -n 15 'curl -s http://:8888/status | jq \".peers | length\"; curl -s http://:8888/status | jq .last_added_block_info; casper-client get-block -n http://:8888/status'\n")),(0,o.kt)("h2",{id:"9999"},"Default SSE HTTP Event Stream Server Port: 9999"),(0,o.kt)("p",null,"The configuration options for the SSE HTTP event stream server are listed under the ",(0,o.kt)("inlineCode",{parentName:"p"},"event_stream_server")," section of the ",(0,o.kt)("inlineCode",{parentName:"p"},"config.toml")," file. The ",(0,o.kt)("inlineCode",{parentName:"p"},"address")," listing port 9999 is the listening address for the SSE HTTP event stream server."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-md"},"address = '0.0.0.0:9999'\n")),(0,o.kt)("p",null,"If this port is closed, the requests coming to this port will not be served, but the node remains unaffected. For details and useful commands, see ",(0,o.kt)("a",{parentName:"p",href:"/developers/dapps/monitor-and-consume-events"},"Monitoring and Consuming Events"),"."),(0,o.kt)("h2",{id:"setting-up-firewall-rules"},"Setting up Firewall Rules"),(0,o.kt)("p",null,"To limit inbound traffic to the node\u2019s endpoints, you can set firewall rules similar to the ",(0,o.kt)("inlineCode",{parentName:"p"},"ufw")," commands below:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install ufw -y\nsudo ufw disable\nsudo ufw reset\nsudo ufw default allow outgoing\nsudo ufw default deny incoming\nsudo ufw limit ssh\nsudo ufw limit 7777/tcp\nsudo ufw limit 8888/tcp\nsudo ufw limit 35000/tcp\nsudo ufw enable\n")),(0,o.kt)("p",null,"These commands will limit requests to the available ports of your node. Port 35000 should be left open, although you can limit traffic, as it is crucial for node-to-node communication."),(0,o.kt)("p",null,"If you have any concerns, questions, or issues, please ",(0,o.kt)("a",{parentName:"p",href:"https://support.casperlabs.io/hc/en-gb/requests/new"},"submit a request")," to the Casper support team."),(0,o.kt)("h2",{id:"restricting-access-for-private-networks"},"Restricting Access for Private Networks"),(0,o.kt)("p",null,"Any node can join Mainnet and Testnet and communicate with the nodes in the network. Private networks may wish to restrict access for new nodes joining the network as described ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup-network/create-private#network-access-control"},"here"),"."),(0,o.kt)("h2",{id:"summary-of-related-links"},"Summary of Related Links"),(0,o.kt)("p",null,"Here is a summary of the links mentioned on this page:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/install-node#network-requirements"},"Network requirements")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/concepts/design/p2p"},"Network communication")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/basic-node-configuration#config-file"},"The node configuration file")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/developers/json-rpc/"},"Interacting with the Casper JSON-RPC API")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/developers/cli/"},"Interacting with the network using CLI")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/becoming-a-validator/bonding#example-bonding-transaction"},"Bonding")," or ",(0,o.kt)("a",{parentName:"li",href:"/operators/becoming-a-validator/unbonding"},"unbonding")," as a validator"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/basic-node-configuration#trusted-hash-for-synchronizing"},"Getting a trusted node hash")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/upgrade#verifying-successful-staging"},"Verifying successful staging")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup/joining#step-7-confirm-the-node-is-synchronized"},"Confirming that the node is synchronized")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/developers/dapps/monitor-and-consume-events"},"Monitoring and consuming events")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"/operators/setup-network/create-private#network-access-control"},"Private network access control")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://support.casperlabs.io/hc/en-gb/sections/6960448246683-Node-Operation-FAQ"},"FAQs for a basic validator node ")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.cspr.community/docs/faq-validator.html"},"External FAQs on Mainnet and Testnet validator node setup"))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b9da5eb7.245a3758.js b/assets/js/b9da5eb7.245a3758.js new file mode 100644 index 0000000000..1939e21109 --- /dev/null +++ b/assets/js/b9da5eb7.245a3758.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2733],{3905:function(e,t,a){a.d(t,{Zo:function(){return p},kt:function(){return m}});var r=a(7294);function o(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function n(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function s(e){for(var t=1;t=0||(o[a]=e[a]);return o}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(o[a]=e[a])}return o}var i=r.createContext({}),l=function(e){var t=r.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},p=function(e){var t=l(e.components);return r.createElement(i.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var a=e.components,o=e.mdxType,n=e.originalType,i=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),h=l(a),f=o,m=h["".concat(i,".").concat(f)]||h[f]||u[f]||n;return a?r.createElement(m,s(s({ref:t},p),{},{components:a})):r.createElement(m,s({ref:t},p))}));function m(e,t){var a=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var n=a.length,s=new Array(n);s[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[h]="string"==typeof e?e:o,s[1]=c;for(var l=2;l=0||(o[a]=e[a]);return o}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(o[a]=e[a])}return o}var i=r.createContext({}),l=function(e){var t=r.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},p=function(e){var t=l(e.components);return r.createElement(i.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var a=e.components,o=e.mdxType,n=e.originalType,i=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),h=l(a),f=o,m=h["".concat(i,".").concat(f)]||h[f]||u[f]||n;return a?r.createElement(m,s(s({ref:t},p),{},{components:a})):r.createElement(m,s({ref:t},p))}));function m(e,t){var a=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var n=a.length,s=new Array(n);s[0]=f;var c={};for(var i in t)hasOwnProperty.call(t,i)&&(c[i]=t[i]);c.originalType=e,c[h]="string"==typeof e?e:o,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},f="mdxType",i={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),f=l(r),y=a,m=f["".concat(p,".").concat(y)]||f[y]||i[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[f]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),p=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(r),g=a,m=c["".concat(s,".").concat(g)]||c[g]||u[g]||i;return r?n.createElement(m,o(o({ref:t},d),{},{components:r})):n.createElement(m,o({ref:t},d))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=g;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var p=2;p=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),p=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(r),g=a,m=c["".concat(s,".").concat(g)]||c[g]||u[g]||i;return r?n.createElement(m,o(o({ref:t},d),{},{components:r})):n.createElement(m,o({ref:t},d))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=g;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:a,o[1]=l;for(var p=2;p=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},i="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),i=l(r),y=a,m=i["".concat(p,".").concat(y)]||i[y]||f[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[i]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},i="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},y=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),i=l(r),y=a,m=i["".concat(p,".").concat(y)]||i[y]||f[y]||o;return r?n.createElement(m,s(s({ref:t},u),{},{components:r})):n.createElement(m,s({ref:t},u))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=y;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[i]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},h=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),d=c(n),p=o,m=d["".concat(l,".").concat(p)]||d[p]||u[p]||i;return n?a.createElement(m,r(r({ref:t},h),{},{components:n})):a.createElement(m,r({ref:t},h))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:o,r[1]=s;for(var c=2;c=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},h=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},p=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,l=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),d=c(n),p=o,m=d["".concat(l,".").concat(p)]||d[p]||u[p]||i;return n?a.createElement(m,r(r({ref:t},h),{},{components:n})):a.createElement(m,r({ref:t},h))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=p;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:o,r[1]=s;for(var c=2;c=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,s=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=p(n),y=a,m=u["".concat(c,".").concat(y)]||u[y]||d[y]||s;return n?r.createElement(m,o(o({ref:t},l),{},{components:n})):r.createElement(m,o({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var s=n.length,o=new Array(s);o[0]=y;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:a,o[1]=i;for(var p=2;p {\n // Generating keys\n const edKeyPair = Keys.Ed25519.new();\n const { publicKey, privateKey } = edKeyPair;\n\n // Create a hexadecimal representation of the public key\n const accountAddress = publicKey.toHex();\n\n // Get the account hash (Uint8Array) from the public key\n const accountHash = publicKey.toAccountHash();\n\n // Store keys as PEM files\n const publicKeyInPem = edKeyPair.exportPublicKeyInPem();\n const privateKeyInPem = edKeyPair.exportPrivateKeyInPem();\n\n const folder = path.join("./", "casper_keys");\n\n if (!fs.existsSync(folder)) {\n const tempDir = fs.mkdirSync(folder);\n }\n\n fs.writeFileSync(folder + "/" + accountAddress + "_public.pem", publicKeyInPem);\n fs.writeFileSync(folder + "/" + accountAddress + "_private.pem", privateKeyInPem);\n\n return accountAddress;\n};\n\nconst newAccountAddress = createAccountKeys();\n')),(0,s.kt)("p",null,"After generating the keys with this code, you can add them to the ",(0,s.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/"},"Casper Wallet Chrome extension")," and use them to sign your transactions."),(0,s.kt)("h3",{id:"sending-a-transfer"},"Sending a Transfer"),(0,s.kt)("p",null,"This code block shows you how to define and send a transfer on a Casper network. Replace the ",(0,s.kt)("inlineCode",{parentName:"p"},"sender-public-key")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"recipient-public-key")," in the code below."),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"sendTransfer")," function below will return a ",(0,s.kt)("inlineCode",{parentName:"p"},"transfer-hash")," which you can check on ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"https://testnet.cspr.live/"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const fs = require("fs");\nconst path = require("path");\nconst axios = require("axios");\nconst casperClientSDK = require("casper-js-sdk");\n\nconst { Keys, CasperClient, CLPublicKey, DeployUtil } = require("casper-js-sdk");\n\nconst RPC_API = "http://159.65.203.12:7777/rpc";\nconst STATUS_API = "http://159.65.203.12:8888";\n\nconst sendTransfer = async ({ from, to, amount }) => {\n const casperClient = new CasperClient(RPC_API);\n\n const folder = path.join("./", "casper_keys");\n\n // Read keys from the structure created in #Generating keys\n const signKeyPair = Keys.Ed25519.parseKeyFiles(folder + "/" + from + "_public.pem", folder + "/" + from + "_private.pem");\n\n // networkName can be taken from the status api\n const response = await axios.get(STATUS_API + "/status");\n\n let networkName = null;\n\n if (response.status == 200) {\n networkName = response.data.chainspec_name;\n }\n\n // For native-transfers the payment price is fixed\n const paymentAmount = 100000000;\n\n // transfer_id field in the request to tag the transaction and to correlate it to your back-end storage\n const id = 187821;\n\n // gasPrice for native transfers can be set to 1\n const gasPrice = 1;\n\n // Time that the deploy will remain valid for, in milliseconds\n // The default value is 1800000 ms (30 minutes)\n const ttl = 1800000;\n\n let deployParams = new DeployUtil.DeployParams(signKeyPair.publicKey, networkName, gasPrice, ttl);\n\n // We create a hex representation of the public key with an added prefix\n const toPublicKey = CLPublicKey.fromHex(to);\n\n const session = DeployUtil.ExecutableDeployItem.newTransfer(amount, toPublicKey, null, id);\n\n const payment = DeployUtil.standardPayment(paymentAmount);\n const deploy = DeployUtil.makeDeploy(deployParams, session, payment);\n const signedDeploy = DeployUtil.signDeploy(deploy, signKeyPair);\n\n // Here we are sending the signed deploy\n return await casperClient.putDeploy(signedDeploy);\n};\n\nsendTransfer({\n // Put here the public key of the sender\'s main purse. Note that it needs to have a balance greater than 2.5 CSPR\n from: "",\n\n // Put here the public key of the recipient\'s main purse. This account doesn\'t need to exist. If the key is correctly formatted, the network will create the account when the deploy is sent\n to: "",\n\n // Minimal amount is 2.5 CSPR (1 CSPR = 1,000,000,000 motes)\n amount: 25000000000,\n});\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Note"),": At any moment, you can serialize the deploy from this example to JSON to accomplish whatever you want (store it, send it, etc.)."),(0,s.kt)("p",null,"Here is the code you can use to serialize the deploy:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},"const jsonFromDeploy = DeployUtil.deployToJson(signedDeploy);\n")),(0,s.kt)("p",null,"Then, you can reconstruct the deploy object using this function:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},"const deployFromJson = DeployUtil.deployFromJson(jsonFromDeploy);\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/bcd2a870.91f12037.js b/assets/js/bcd2a870.91f12037.js deleted file mode 100644 index 398f492fdd..0000000000 --- a/assets/js/bcd2a870.91f12037.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6099],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},y=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,s=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),u=p(n),y=a,m=u["".concat(c,".").concat(y)]||u[y]||d[y]||s;return n?r.createElement(m,o(o({ref:t},l),{},{components:n})):r.createElement(m,o({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var s=n.length,o=new Array(s);o[0]=y;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:a,o[1]=i;for(var p=2;p {\n // Generating keys\n const edKeyPair = Keys.Ed25519.new();\n const { publicKey, privateKey } = edKeyPair;\n\n // Create a hexadecimal representation of the public key\n const accountAddress = publicKey.toHex();\n\n // Get the account hash (Uint8Array) from the public key\n const accountHash = publicKey.toAccountHash();\n\n // Store keys as PEM files\n const publicKeyInPem = edKeyPair.exportPublicKeyInPem();\n const privateKeyInPem = edKeyPair.exportPrivateKeyInPem();\n\n const folder = path.join("./", "casper_keys");\n\n if (!fs.existsSync(folder)) {\n const tempDir = fs.mkdirSync(folder);\n }\n\n fs.writeFileSync(folder + "/" + accountAddress + "_public.pem", publicKeyInPem);\n fs.writeFileSync(folder + "/" + accountAddress + "_private.pem", privateKeyInPem);\n\n return accountAddress;\n};\n\nconst newAccountAddress = createAccountKeys();\n')),(0,s.kt)("p",null,"After generating the keys with this code, you can add them to the ",(0,s.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/"},"Casper Wallet Chrome extension")," and use them to sign your transactions."),(0,s.kt)("h3",{id:"sending-a-transfer"},"Sending a Transfer"),(0,s.kt)("p",null,"This code block shows you how to define and send a transfer on a Casper network. Replace the ",(0,s.kt)("inlineCode",{parentName:"p"},"sender-public-key")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"recipient-public-key")," in the code below."),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"sendTransfer")," function below will return a ",(0,s.kt)("inlineCode",{parentName:"p"},"transfer-hash")," which you can check on ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"https://testnet.cspr.live/"),"."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const fs = require("fs");\nconst path = require("path");\nconst axios = require("axios");\nconst casperClientSDK = require("casper-js-sdk");\n\nconst { Keys, CasperClient, CLPublicKey, DeployUtil } = require("casper-js-sdk");\n\nconst RPC_API = "http://159.65.203.12:7777/rpc";\nconst STATUS_API = "http://159.65.203.12:8888";\n\nconst sendTransfer = async ({ from, to, amount }) => {\n const casperClient = new CasperClient(RPC_API);\n\n const folder = path.join("./", "casper_keys");\n\n // Read keys from the structure created in #Generating keys\n const signKeyPair = Keys.Ed25519.parseKeyFiles(folder + "/" + from + "_public.pem", folder + "/" + from + "_private.pem");\n\n // networkName can be taken from the status api\n const response = await axios.get(STATUS_API + "/status");\n\n let networkName = null;\n\n if (response.status == 200) {\n networkName = response.data.chainspec_name;\n }\n\n // For native-transfers the payment price is fixed\n const paymentAmount = 100000000;\n\n // transfer_id field in the request to tag the transaction and to correlate it to your back-end storage\n const id = 187821;\n\n // gasPrice for native transfers can be set to 1\n const gasPrice = 1;\n\n // Time that the deploy will remain valid for, in milliseconds\n // The default value is 1800000 ms (30 minutes)\n const ttl = 1800000;\n\n let deployParams = new DeployUtil.DeployParams(signKeyPair.publicKey, networkName, gasPrice, ttl);\n\n // We create a hex representation of the public key with an added prefix\n const toPublicKey = CLPublicKey.fromHex(to);\n\n const session = DeployUtil.ExecutableDeployItem.newTransfer(amount, toPublicKey, null, id);\n\n const payment = DeployUtil.standardPayment(paymentAmount);\n const deploy = DeployUtil.makeDeploy(deployParams, session, payment);\n const signedDeploy = DeployUtil.signDeploy(deploy, signKeyPair);\n\n // Here we are sending the signed deploy\n return await casperClient.putDeploy(signedDeploy);\n};\n\nsendTransfer({\n // Put here the public key of the sender\'s main purse. Note that it needs to have a balance greater than 2.5 CSPR\n from: "",\n\n // Put here the public key of the recipient\'s main purse. This account doesn\'t need to exist. If the key is correctly formatted, the network will create the account when the deploy is sent\n to: "",\n\n // Minimal amount is 2.5 CSPR (1 CSPR = 1,000,000,000 motes)\n amount: 25000000000,\n});\n')),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Note"),": At any moment, you can serialize the deploy from this example to JSON to accomplish whatever you want (store it, send it, etc.)."),(0,s.kt)("p",null,"Here is the code you can use to serialize the deploy:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},"const jsonFromDeploy = DeployUtil.deployToJson(signedDeploy);\n")),(0,s.kt)("p",null,"Then, you can reconstruct the deploy object using this function:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},"const deployFromJson = DeployUtil.deployFromJson(jsonFromDeploy);\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/bd4f9aad.0d6ea978.js b/assets/js/bd4f9aad.0d6ea978.js new file mode 100644 index 0000000000..448fb71554 --- /dev/null +++ b/assets/js/bd4f9aad.0d6ea978.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9753],{3905:function(e,t,n){n.d(t,{Zo:function(){return d},kt:function(){return m}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=p(n),h=r,m=u["".concat(l,".").concat(h)]||u[h]||c[h]||o;return n?a.createElement(m,i(i({ref:t},d),{},{components:n})):a.createElement(m,i({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var p=2;p=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),u=p(n),h=r,m=u["".concat(l,".").concat(h)]||u[h]||c[h]||o;return n?a.createElement(m,i(i({ref:t},d),{},{components:n})):a.createElement(m,i({ref:t},d))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var p=2;p=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=o,m=u["".concat(c,".").concat(d)]||u[d]||f[d]||a;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,i[1]=s;for(var p=2;p=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(n),d=o,m=u["".concat(c,".").concat(d)]||u[d]||f[d]||a;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:o,i[1]=s;for(var p=2;p=0||(r[t]=e[t]);return r}(e,a);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var o=n.createContext({}),k=function(e){var a=n.useContext(o),t=a;return e&&(t="function"==typeof e?e(a):i(i({},a),e)),t},m=function(e){var a=k(e.components);return n.createElement(o.Provider,{value:a},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},s=n.forwardRef((function(e,a){var t=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,m=p(e,["components","mdxType","originalType","parentName"]),d=k(t),s=r,N=d["".concat(o,".").concat(s)]||d[s]||u[s]||l;return t?n.createElement(N,i(i({ref:a},m),{},{components:t})):n.createElement(N,i({ref:a},m))}));function N(e,a){var t=arguments,r=a&&a.mdxType;if("string"==typeof e||r){var l=t.length,i=new Array(l);i[0]=s;var p={};for(var o in a)hasOwnProperty.call(a,o)&&(p[o]=a[o]);p.originalType=e,p[d]="string"==typeof e?e:r,i[1]=p;for(var k=2;kModuleBytes",id:"modulebytes",level:3},{value:"StoredContractByHash",id:"storedcontractbyhash",level:3},{value:"StoredContractByName",id:"storedcontractbyname",level:3},{value:"StoredVersionContractByHash",id:"storedversioncontractbyhash",level:3},{value:"StoredVersionContractByName",id:"storedversioncontractbyname",level:3},{value:"Transfer",id:"transfer",level:3},{value:"ExecutionEffect",id:"executioneffect",level:2},{value:"ExecutionResult",id:"executionresult",level:2},{value:"FinalizedApprovals",id:"finalizedapprovals",level:2},{value:"GlobalStateIdentifier",id:"globalstateidentifier",level:2},{value:"Group",id:"group",level:2},{value:"Groups",id:"groups",level:3},{value:"JsonBid",id:"jsonbid",level:2},{value:"JsonBids",id:"jsonbids",level:2},{value:"JsonBlock",id:"jsonblock",level:2},{value:"JsonBlockBody",id:"jsonblockbody",level:2},{value:"JsonBlockHeader",id:"jsonblockheader",level:2},{value:"JsonDelegator",id:"jsondelegator",level:2},{value:"JsonEraEnd",id:"jsoneraend",level:2},{value:"JsonEraReport",id:"jsonerareport",level:2},{value:"JsonEraValidators",id:"jsoneravalidators",level:2},{value:"JsonExecutionResult",id:"jsonexecutionresult",level:2},{value:"JsonProof",id:"jsonproof",level:2},{value:"JsonValidatorChanges",id:"jsonvalidatorchanges",level:2},{value:"JsonValidatorStatusChange",id:"jsonvalidatorstatuschange",level:2},{value:"JsonValidatorsWeights",id:"jsonvalidatorweights",level:2},{value:"Merkle_Proof",id:"merkle-proof",level:2},{value:"MinimalBlockInfo",id:"minimalblockinfo",level:2},{value:"NamedArg",id:"namedarg",level:2},{value:"NamedKey",id:"namedkey",level:2},{value:"NextUpgrade",id:"nextupgrade",level:2},{value:"NewValidator",id:"newvalidator",level:2},{value:"Operation",id:"operation",level:2},{value:"OpKind",id:"opkind",level:2},{value:"Parameter",id:"parameter",level:2},{value:"PeerEntry",id:"peerentry",level:2},{value:"PeersMap",id:"peersmap",level:2},{value:"ProtocolVersion",id:"protocolversion",level:2},{value:"PublicKey",id:"publickey",level:2},{value:"PurseIdentifier",id:"purseidentifier",level:2},{value:"ReactorState",id:"reactorstate",level:2},{value:"Reward",id:"reward",level:2},{value:"RuntimeArgs",id:"runtimeargs",level:2},{value:"SeigniorageAllocation",id:"seigniorageallocation",level:2},{value:"Signature",id:"signature",level:2},{value:"StoredValue",id:"storedvalue",level:2},{value:"TimeDiff",id:"timediff",level:2},{value:"Timestamp",id:"timestamp",level:2},{value:"Transfer",id:"transfer",level:2},{value:"TransferAddr",id:"transferaddr",level:2},{value:"Transform",id:"transform",level:2},{value:"TransformEntry",id:"transformentry",level:2},{value:"U128",id:"u128",level:2},{value:"U256",id:"u256",level:2},{value:"U512",id:"u512",level:2},{value:"UnbondingPurse",id:"unbondingpurse",level:2},{value:"URef",id:"uref",level:2},{value:"ValidatorChange",id:"validatorchange",level:2},{value:"ValidatorWeight",id:"validatorweight",level:2},{value:"VestingSchedule",id:"vestingschedule",level:2},{value:"WithdrawPurse",id:"withdrawpurse",level:2}],u={toc:d},s="wrapper";function N(e){var a=e.components,t=(0,r.Z)(e,i);return(0,l.kt)(s,(0,n.Z)({},u,t,{components:a,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"types"},"Types"),(0,l.kt)("p",null,"The following definitions expand on parameters seen elsewhere within the SDK standard and are provided for clarity and completeness."),(0,l.kt)("h2",{id:"account"},"Account"),(0,l.kt)("p",null,"Structure representing a user's Account, stored in global state."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"account_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#actionthresholds"},(0,l.kt)("inlineCode",{parentName:"a"},"action_thresholds")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#associatedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"associated_keys")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"main_purse")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#namedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"named_keys"))))),(0,l.kt)("h2",{id:"accounthash"},"AccountHash"),(0,l.kt)("p",null,"The AccountHash is a 32-byte hash derived from a supported PublicKey. Its role is to standardize keys that can vary in length."),(0,l.kt)("h2",{id:"actionthresholds"},"ActionThresholds"),(0,l.kt)("p",null,"Thresholds that have to be met when executing an action of a certain type."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"deployment"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key_management")))),(0,l.kt)("h2",{id:"activationpoint"},"ActivationPoint"),(0,l.kt)("p",null,"The first era to which the associated protocol version applies."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timestamp"},(0,l.kt)("inlineCode",{parentName:"a"},"timestamp"))))),(0,l.kt)("h2",{id:"approval"},"Approval"),(0,l.kt)("p",null,"A struct containing a signature and the public key of the signer."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#signature"},(0,l.kt)("inlineCode",{parentName:"a"},"signature")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"signer"))))),(0,l.kt)("h2",{id:"associatedkey"},"AssociatedKey"),(0,l.kt)("p",null,"A key granted limited permissions to an Account, for purposes such as multisig."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"account_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"weight")))),(0,l.kt)("h2",{id:"auctionstate"},"AuctionState"),(0,l.kt)("p",null,"Data structure summarizing auction contract data."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonbids"},(0,l.kt)("inlineCode",{parentName:"a"},"bids"))," All bids contained within a vector.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"block_height")," Block height.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsoneravalidators"},(0,l.kt)("inlineCode",{parentName:"a"},"era_validators"))," Era validators.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"state_root_hash"))," Global state hash."))),(0,l.kt)("h2",{id:"availableblockrange"},"AvailableBlockRange"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"low")," The inclusive lower bound of the range.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"high")," The inclusive upper bound of the range."))),(0,l.kt)("h2",{id:"bid"},"Bid"),(0,l.kt)("p",null,"An entry in the validator map."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse"))," The purse that was used for bonding.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegation_rate")," The delegation rate.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#delegator"},(0,l.kt)("inlineCode",{parentName:"a"},"delegators"))," The validator's delegators, indexed by their public keys.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"inactive")," ",(0,l.kt)("inlineCode",{parentName:"p"},"true"),' if validator has been "evicted".')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"staked_amount"))," The amount of tokens staked by a validator (not including delegators).")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," Validator's public key."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#vestingschedule"},(0,l.kt)("inlineCode",{parentName:"a"},"vesting_schedule"))," Vesting schedule for a genesis validator. ",(0,l.kt)("inlineCode",{parentName:"li"},"None")," if non-genesis validator.")),(0,l.kt)("h2",{id:"blockhash"},"BlockHash"),(0,l.kt)("p",null,"A cryptographic hash identifying a ",(0,l.kt)("inlineCode",{parentName:"p"},"Block"),"."),(0,l.kt)("h2",{id:"blockidentifier"},"BlockIdentifier"),(0,l.kt)("p",null,"Identifier for possible ways to retrieve a Block."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"Hash"))," Identify and retrieve the Block with its hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Height")," Identify and retrieve the Block with its height."))),(0,l.kt)("h2",{id:"blocksynchronizerstatus"},"BlockSynchronizerStatus"),(0,l.kt)("p",null,"The status of the block synchronizer."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Historical")," The status of syncing a historical block, if any."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash-blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"block_hash"))," The block hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"block_height")," The height of the block, if known.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"acquisition_state")," The state of acquisition of the data associated with the block.")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Forward")," The status of syncing a forward block, if any."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash-blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"block_hash"))," The block hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"block_height")," The height of the block, if known.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"acquisition_state")," The state of acquisition of the data associated with the block."))))),(0,l.kt)("h2",{id:"chainspecrawbytes"},"ChainspecRawBytes"),(0,l.kt)("p",null,"The raw bytes of the chainspec.toml, genesis accounts.toml, and global_state.toml files."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"chainspec_bytes")," Hex-encoded raw bytes of the current chainspec.toml file.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"maybe_genesis_accounts_bytes")," Hex-encoded raw bytes of the current genesis accounts.toml file.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"maybe_global_state_bytes")," Hex-encoded raw bytes of the current global_state.toml file."))),(0,l.kt)("h2",{id:"contract"},"Contract"),(0,l.kt)("p",null,"A contract struct that can be serialized as a JSON object."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"#contractpackagehash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_package_hash"))),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"#contractwasmhash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_wasm_hash"))),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"#entrypoint"},(0,l.kt)("inlineCode",{parentName:"a"},"entry_points"))),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"#namedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"named_keys"))),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version")),(0,l.kt)("h2",{id:"contracthash"},"ContractHash"),(0,l.kt)("p",null,"The hash address of the contract."),(0,l.kt)("h2",{id:"contractpackge"},"ContractPackage"),(0,l.kt)("p",null,"Contract definition, metadata and security container."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"access_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#disabledversions"},(0,l.kt)("inlineCode",{parentName:"a"},"disabled_versions")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#groups"},(0,l.kt)("inlineCode",{parentName:"a"},"groups")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contractversion"},(0,l.kt)("inlineCode",{parentName:"a"},"versions"))))),(0,l.kt)("h2",{id:"contractpackagehash"},"ContractPackageHash"),(0,l.kt)("p",null,"The hash address of the contract package."),(0,l.kt)("h2",{id:"contractversion"},"ContractVersion"),(0,l.kt)("p",null,"The version of the contract."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contracthash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract_version"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version_major")))),(0,l.kt)("h2",{id:"contractwasmhash"},"ContractWasmHash"),(0,l.kt)("p",null,"The hash address of the contract Wasm."),(0,l.kt)("h2",{id:"delegator"},"Delegator"),(0,l.kt)("p",null,'Represents a party delegating their stake to a validator (or "delegatee").'),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"delegator_public_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"staked_amount")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#vestingschedule"},(0,l.kt)("inlineCode",{parentName:"a"},"vesting_schedule")))),(0,l.kt)("h2",{id:"deploy"},"Deploy"),(0,l.kt)("p",null,"A Deploy; an item containing a smart contract along with the requester's signature(s)."),(0,l.kt)("p",null,"Required properties:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#approval"},(0,l.kt)("inlineCode",{parentName:"a"},"approvals")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployheader"},(0,l.kt)("inlineCode",{parentName:"a"},"header")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executabledeployitem"},(0,l.kt)("inlineCode",{parentName:"a"},"payment")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executabledeployitem"},(0,l.kt)("inlineCode",{parentName:"a"},"sessions"))))),(0,l.kt)("h2",{id:"deployhash"},"DeployHash"),(0,l.kt)("p",null,"Hex-encoded Deploy hash."),(0,l.kt)("h2",{id:"deployheader"},"DeployHeader"),(0,l.kt)("p",null,"The header portion of a Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"account")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"body_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"chain_name")," A user defined string.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"dependencies")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"gas_price")," Defined as an integer in UInt64 format.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timestamp"},(0,l.kt)("inlineCode",{parentName:"a"},"timestamp")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timediff"},(0,l.kt)("inlineCode",{parentName:"a"},"ttl"))))),(0,l.kt)("h2",{id:"deployinfo"},"DeployInfo"),(0,l.kt)("p",null,"Information relating to the given Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"deploy_hash"))," The relevant Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"from"))," Account identifier of the creator of the Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"gas"))," Gas cost of executing the Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"source"))," Source purse used for payment of the Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transferaddr"},(0,l.kt)("inlineCode",{parentName:"a"},"transfers"))," Transfers performed by the Deploy."))),(0,l.kt)("h2",{id:"dictionaryidentifier"},"DictionaryIdentifier"),(0,l.kt)("p",null,"Options for dictionary item lookups."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AccountNamedKey")," Lookup a dictionary item via an Account's named keys."),(0,l.kt)("p",{parentName:"li"},"Required Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The Account key as a formatted string whose named keys contain dictionary_name."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_name")," The named key under which the dictionary seed URef is stored."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_item_key")," The dictionary item key formatted as a string.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"ContractNamedKey")," Lookup a dictionary item via a Contract's named keys."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The contract key as a formatted string whose named keys contains dictionary_name."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_name")," The named key under which the dictionary seed URef is stored."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_item_key")," The dictionary item key formatted as a string.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"URef")," Lookup a dictionary item via its seed URef."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"seed_uref")," The dictionary's seed URef."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_item_key")," The dictionary item key formatted as a string.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Dictionary")," Lookup a dictionary item via its unique key."))),(0,l.kt)("h2",{id:"digest"},"Digest"),(0,l.kt)("p",null,"Hex-encoded hash digest."),(0,l.kt)("h2",{id:"disabledversions"},"DisabledVersions"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract_version"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version_major")))),(0,l.kt)("h2",{id:"entrypoint"},"EntryPoint"),(0,l.kt)("p",null,"Metadata describing a callable entry point and its return value, if any. All required parameters should be declared, whereas all non-required parameters should not be declared. Non-required parameters should not be confused with optional parameters."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#entrypointaccess"},(0,l.kt)("inlineCode",{parentName:"a"},"access")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#parameter"},(0,l.kt)("inlineCode",{parentName:"a"},"args")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#entrypointtype"},(0,l.kt)("inlineCode",{parentName:"a"},"entry_point_type")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#cltype"},(0,l.kt)("inlineCode",{parentName:"a"},"ret"))))),(0,l.kt)("h2",{id:"entrypointaccess"},"EntryPointAccess"),(0,l.kt)("p",null,"Enum describing the possible access control options for a contract entry point."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Public")," A public entry point is callable by any caller.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#group"},(0,l.kt)("inlineCode",{parentName:"a"},"Groups"))," Only callers from the authorized, listed groups may call this entry point. Note: If this list is empty then this entry point is not callable from outside the contract."))),(0,l.kt)("h2",{id:"entrypointype"},"EntryPointType"),(0,l.kt)("p",null,"Context of an entry point execution."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"session")," Executes in the caller's context.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract")," Executes in the callee's context."))),(0,l.kt)("h2",{id:"eraid"},"EraID"),(0,l.kt)("p",null,"Era ID newtype."),(0,l.kt)("h2",{id:"erainfo"},"EraInfo"),(0,l.kt)("p",null,"Auction metadata. Intended to be recorded at each era."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#seigniorageallocation-seigniorageallocation"},(0,l.kt)("inlineCode",{parentName:"a"},"seigniorage_allocation"))," Information about a seigniorage allocation.")),(0,l.kt)("h2",{id:"erasummary"},"EraSummary"),(0,l.kt)("p",null,"The summary of an era."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"block_hash"))," The Block hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id"))," The era id.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#merkle-proof"},(0,l.kt)("inlineCode",{parentName:"a"},"merkle_proof"))," The merkle proof.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"state_root_hash"))," Hex-encoded hash of the state root.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#storedvalue"},(0,l.kt)("inlineCode",{parentName:"a"},"stored_value"))," The StoredValue containing era information."))),(0,l.kt)("h2",{id:"executabledeployitem"},"ExecutableDeployItem"),(0,l.kt)("p",null,"Represents possible variants of an executable Deploy."),(0,l.kt)("h3",{id:"modulebytes"},(0,l.kt)("inlineCode",{parentName:"h3"},"ModuleBytes")),(0,l.kt)("p",null,"Executable specified as raw bytes that represent Wasm code and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"module_bytes")," Hex-encoded raw Wasm bytes. There are some special cases around passing ",(0,l.kt)("inlineCode",{parentName:"li"},"module_bytes")," for payment code.")),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("h3",{id:"storedcontractbyhash"},(0,l.kt)("inlineCode",{parentName:"h3"},"StoredContractByHash")),(0,l.kt)("p",null,"Stored contract referenced by its ",(0,l.kt)("inlineCode",{parentName:"p"},"ContractHash"),", entry point and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point")," The name of an entry point.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"hash")," A hex-encoded hash."))),(0,l.kt)("h3",{id:"storedcontractbyname"},(0,l.kt)("inlineCode",{parentName:"h3"},"StoredContractByName")),(0,l.kt)("p",null,"Stored contract referenced by a named key existing in the signer's Account context, entry point and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point")," The name of an entry point.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," A named key."))),(0,l.kt)("h3",{id:"storedversioncontractbyhash"},(0,l.kt)("inlineCode",{parentName:"h3"},"StoredVersionContractByHash")),(0,l.kt)("p",null,"Stored versioned contract referenced by its ",(0,l.kt)("inlineCode",{parentName:"p"},"ContractPackageHash"),", entry point and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point")," The name of an entry point.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"hash")," A hex-encoded hash."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"version")," An optional version of the contract to call. It will default to the highest enabled version if no value is specified.")),(0,l.kt)("h3",{id:"storedversioncontractbyname"},(0,l.kt)("inlineCode",{parentName:"h3"},"StoredVersionContractByName")),(0,l.kt)("p",null,"Stored versioned contract referenced by a named key existing in the signer's Account context, entry point and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point")," The name of an entry point.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," A named key."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"version")," An optional version of the contract to call. It will default to the highest enabled version if no value is specified.")),(0,l.kt)("h3",{id:"transfer"},(0,l.kt)("inlineCode",{parentName:"h3"},"Transfer")),(0,l.kt)("p",null,"A native transfer which does not contain or reference a Wasm code."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args")))),(0,l.kt)("h2",{id:"executioneffect"},"ExecutionEffect"),(0,l.kt)("p",null,"The journal of execution transforms from a single Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#oepration"},(0,l.kt)("inlineCode",{parentName:"a"},"operations")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transformentry"},(0,l.kt)("inlineCode",{parentName:"a"},"transforms"))))),(0,l.kt)("h2",{id:"executionresult"},"ExecutionResult"),(0,l.kt)("p",null,"The result of executing a single Deploy."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Failure")," The result of a failed execution`"),(0,l.kt)("p",{parentName:"li"},"Required Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executioneffect"},(0,l.kt)("inlineCode",{parentName:"a"},"effect"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transferaddr"},(0,l.kt)("inlineCode",{parentName:"a"},"transfers"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"cost"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"error_message")," The error message associated with executing the Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Success")," The result of a successful execution."),(0,l.kt)("p",{parentName:"li"},"Required Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executioneffect"},(0,l.kt)("inlineCode",{parentName:"a"},"effect"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transferaddr"},(0,l.kt)("inlineCode",{parentName:"a"},"transfers"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"cost"))))),(0,l.kt)("h2",{id:"finalizedapprovals"},"FinalizedApprovals"),(0,l.kt)("p",null,"A boolean value that determines whether to return the deploy with the finalized approvals substituted. If ",(0,l.kt)("inlineCode",{parentName:"p"},"false")," or omitted, returns the deploy with the approvals that were originally received by the node."),(0,l.kt)("h2",{id:"globalstateidentifier"},"GlobalStateIdentifier"),(0,l.kt)("p",null,"Identifier for possible ways to query global state."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"BlockHash"))," Query using a Block hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"StateRootHash"))," Query using the state root hash."))),(0,l.kt)("h2",{id:"group"},"Group"),(0,l.kt)("p",null,'A (labelled) "user group". Each entry point of a versioned contract may be associated with one or more user groups which are allowed to call it.'),(0,l.kt)("h3",{id:"groups"},"Groups"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"group"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"keys"))))),(0,l.kt)("h2",{id:"jsonbid"},"JsonBid"),(0,l.kt)("p",null,"An entry in a founding validator map representing a bid."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse"))," The purse that was used for bonding.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegation_rate")," The delegation rate.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsondelegator"},(0,l.kt)("inlineCode",{parentName:"a"},"delegators"))," The delegators.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"inactive")," Is this an inactive validator.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"staked_amount"))," The amount of tokens staked by a validator (not including delegators)."))),(0,l.kt)("h2",{id:"jsonbids"},"JsonBids"),(0,l.kt)("p",null,"A Json representation of a single bid."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonbid"},(0,l.kt)("inlineCode",{parentName:"a"},"bid")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key"))))),(0,l.kt)("h2",{id:"jsonblock"},"JsonBlock"),(0,l.kt)("p",null,"A JSON-friendly representation of ",(0,l.kt)("inlineCode",{parentName:"p"},"Block"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonblockbody"},(0,l.kt)("inlineCode",{parentName:"a"},"body"))," JSON-friendly Block body.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"hash"))," BlockHash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonblockheader"},(0,l.kt)("inlineCode",{parentName:"a"},"header"))," JSON-friendly Block header.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonproof"},(0,l.kt)("inlineCode",{parentName:"a"},"proofs"))," JSON-friendly list of proofs for this Block."))),(0,l.kt)("h2",{id:"jsonblockbody"},"JsonBlockBody"),(0,l.kt)("p",null,"A JSON-friendly representation of ",(0,l.kt)("inlineCode",{parentName:"p"},"Body"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"deploy_hashes")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"proposer")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"transfer_hashes"))))),(0,l.kt)("h2",{id:"jsonblockheader"},"JsonBlockHeader"),(0,l.kt)("p",null,"JSON representation of a Block header."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"accumulated_seed"))," Accumulated seed.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"body_hash"))," The body hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id"))," The Block era id.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"height")," The Block height.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"parent_hash"))," The parent hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#protocolversion"},(0,l.kt)("inlineCode",{parentName:"a"},"protocol_version"))," The protocol version.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"random_bit")," Randomness bit.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"state_root_hash"))," The state root hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timestamp"},(0,l.kt)("inlineCode",{parentName:"a"},"timestamp"))," The Block timestamp."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#jsoneraend"},(0,l.kt)("inlineCode",{parentName:"a"},"era_end"))," The era end.")),(0,l.kt)("h2",{id:"jsondelegator"},"JsonDelegator"),(0,l.kt)("p",null,"A delegator associated with the given validator."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"delegatee")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"staked_amount"))))),(0,l.kt)("h2",{id:"jsoneraend"},"JsonEraEnd"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonerareport"},"`era_report"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#validatorweight"},(0,l.kt)("inlineCode",{parentName:"a"},"next_era_validator_weight"))))),(0,l.kt)("h2",{id:"jsonerareport"},"JsonEraReport"),(0,l.kt)("p",null,"Equivocation and reward information to be included in the terminal Block."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"equivocators")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"inactive_validators")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#reward"},(0,l.kt)("inlineCode",{parentName:"a"},"rewards"))))),(0,l.kt)("h2",{id:"jsoneravalidators"},"JsonEraValidators"),(0,l.kt)("p",null,"The validators for the given era."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonvalidatorsweights"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_weights"))))),(0,l.kt)("h2",{id:"jsonexecutionresult"},"JsonExecutionResult"),(0,l.kt)("p",null,"The execution result of a single Deploy."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"block_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executionresult"},(0,l.kt)("inlineCode",{parentName:"a"},"result"))))),(0,l.kt)("h2",{id:"jsonproof"},"JsonProof"),(0,l.kt)("p",null,"A JSON-friendly representation of a proof, i.e. a Block's finality signature."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#signature"},(0,l.kt)("inlineCode",{parentName:"a"},"signature"))))),(0,l.kt)("h2",{id:"jsonvalidatorchanges"},"JsonValidatorChanges"),(0,l.kt)("p",null,"The changes in a validator's status."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key"))," The public key of the validator.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonvalidatorstatuschange"},(0,l.kt)("inlineCode",{parentName:"a"},"status_changes"))," The set of changes to the validator's status."))),(0,l.kt)("h2",{id:"jsonvalidatorstatuschange"},"JsonValidatorStatusChange"),(0,l.kt)("p",null,"A single change to a validator's status in the given era."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id"))," The era in which the change occurred.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#validatorchange"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_change"))," The change in validator status."))),(0,l.kt)("h2",{id:"jsonvalidatorweights"},"JsonValidatorsWeights"),(0,l.kt)("p",null,"A validator's weight."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"weight"))))),(0,l.kt)("h2",{id:"merkle-proof"},"Merkle_Proof"),(0,l.kt)("p",null,"A merkle proof is a construction created using a merkle trie that allows verification of the associated hashes."),(0,l.kt)("h2",{id:"minimalblockinfo"},"MinimalBlockInfo"),(0,l.kt)("p",null,"Minimal info of a ",(0,l.kt)("inlineCode",{parentName:"p"},"Block"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"creator")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"height"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"state_root_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timestamp"},(0,l.kt)("inlineCode",{parentName:"a"},"timestamp"))))),(0,l.kt)("h2",{id:"namedarg"},"NamedArg"),(0,l.kt)("p",null,"Named arguments to a contract."),(0,l.kt)("h2",{id:"namedkey"},"NamedKey"),(0,l.kt)("p",null,"A named key."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The value of the entry: a casper ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," type.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," The name of the entry."))),(0,l.kt)("h2",{id:"nextupgrade"},"NextUpgrade"),(0,l.kt)("p",null,"Information about the next protocol upgrade."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#activationpoint"},(0,l.kt)("inlineCode",{parentName:"a"},"activation_point")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version")))),(0,l.kt)("h2",{id:"newvalidator"},"NewValidator"),(0,l.kt)("p",null,"The public key for the new validator in a redelegation using ",(0,l.kt)("a",{parentName:"p",href:"#unbondingpurse"},"UnbondingPurse"),"."),(0,l.kt)("h2",{id:"operation"},"Operation"),(0,l.kt)("p",null,"An operation performed while executing a Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The formatted string of the ",(0,l.kt)("inlineCode",{parentName:"p"},"Key"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#opkind"},(0,l.kt)("inlineCode",{parentName:"a"},"kind"))))),(0,l.kt)("h2",{id:"opkind"},"OpKind"),(0,l.kt)("p",null,"The type of operation performed while executing a Deploy."),(0,l.kt)("h2",{id:"parameter"},"Parameter"),(0,l.kt)("p",null,"Parameter to an entry point."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#cltype"},(0,l.kt)("inlineCode",{parentName:"a"},"cl_type")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")))),(0,l.kt)("h2",{id:"peerentry"},"PeerEntry"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"address"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"node_id")))),(0,l.kt)("h2",{id:"peersmap"},"PeersMap"),(0,l.kt)("p",null,"Map of peer IDs to network addresses."),(0,l.kt)("h2",{id:"protocolversion"},"ProtocolVersion"),(0,l.kt)("p",null,"Casper Platform protocol version."),(0,l.kt)("h2",{id:"publickey"},"PublicKey"),(0,l.kt)("p",null,"Hex-encoded cryptographic public key, including the algorithm tag prefix."),(0,l.kt)("h2",{id:"purseidentifier"},"PurseIdentifier"),(0,l.kt)("p",null,"The identifier to obtain the purse corresponding to a balance query. Valid identifiers include:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"main_purse_under_public_key")," The main purse under a provided ",(0,l.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"main_purse_under_account_hash")," The main purse under a provided ",(0,l.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"AccountHash")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"purse_uref")," A specific purse identified by the associated ",(0,l.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),"."))),(0,l.kt)("h2",{id:"reactorstate"},"ReactorState"),(0,l.kt)("p",null,"The state of the reactor, which will return one of the following:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Initialize")," Get all components and reactor state set up on start.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"CatchUp")," Orient to the network and attempt to catch up to tip.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Upgrading")," Running commit upgrade and creating immediate switch block.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"KeepUp")," Stay caught up with tip.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Validate")," Node is currently caught up and is an active validator.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"ShutdownForUpgrade")," Node should be shut down for upgrade."))),(0,l.kt)("h2",{id:"reward"},"Reward"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"amount"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator"))))),(0,l.kt)("h2",{id:"runtimeargs"},"RuntimeArgs"),(0,l.kt)("p",null,"Represents a collection of arguments passed to a smart contract."),(0,l.kt)("h2",{id:"seigniorageallocation"},"SeigniorageAllocation"),(0,l.kt)("p",null,"Information about a seigniorage allocation."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Validator")," Info about a seigniorage allocation for a validator."),(0,l.kt)("p",{parentName:"li"},"Required Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Allocated amount."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," Validator's public key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Delegator")," Info about a seigniorage allocation for a delegator."),(0,l.kt)("p",{parentName:"li"},"Require Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Allocated amount."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"delegator_public_key"))," Delegator's public key."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," Validator's public key."))),(0,l.kt)("h2",{id:"signature"},"Signature"),(0,l.kt)("p",null,"Hex-encoded cryptographic signature, including the algorithm tag prefix."),(0,l.kt)("h2",{id:"storedvalue"},"StoredValue"),(0,l.kt)("p",null,"Representation of a value stored in global state. ",(0,l.kt)("inlineCode",{parentName:"p"},"Account"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Contract")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"ContractPackage")," have their own ",(0,l.kt)("inlineCode",{parentName:"p"},"json_compatibility")," representation (see their docs for further info)."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#clvalue"},(0,l.kt)("inlineCode",{parentName:"a"},"CLValue"))," A Casper-specific value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#account"},(0,l.kt)("inlineCode",{parentName:"a"},"Account"))," An Account.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"ContractWasm")," A contract's Wasm.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contract"},(0,l.kt)("inlineCode",{parentName:"a"},"Contract"))," Entry points supported by a contract.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contractpackage"},(0,l.kt)("inlineCode",{parentName:"a"},"ContractPackage"))," A contract definition, metadata, and security container.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transfer"},(0,l.kt)("inlineCode",{parentName:"a"},"Transfer"))," A record of a transfer.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployinfo"},(0,l.kt)("inlineCode",{parentName:"a"},"DeployInfo"))," A record of a Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#erainfo"},(0,l.kt)("inlineCode",{parentName:"a"},"EraInfo"))," Auction metadata.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#bid-bid"},(0,l.kt)("inlineCode",{parentName:"a"},"Bid"))," A bid.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#unbondingpurse"},(0,l.kt)("inlineCode",{parentName:"a"},"Withdraw"))," A withdraw."))),(0,l.kt)("h2",{id:"timediff"},"TimeDiff"),(0,l.kt)("p",null,"Human-readable duration."),(0,l.kt)("h2",{id:"timestamp"},"Timestamp"),(0,l.kt)("p",null,"Timestamp formatted as per RFC 3339."),(0,l.kt)("h2",{id:"transfer"},"Transfer"),(0,l.kt)("p",null,"Represents a transfer from one purse to another."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Transfer amount.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"deploy_hash"))," Deploy that created the transfer.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"from"))," Account from which transfer was executed.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"gas")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"source"))," Source purse.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"target"))," Target purse."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"id")," User-defined ID.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"to"))," Account to which funds are transferred."))),(0,l.kt)("h2",{id:"transferaddr"},"TransferAddr"),(0,l.kt)("p",null,"Hex-encoded transfer address."),(0,l.kt)("h2",{id:"transform"},"Transform"),(0,l.kt)("p",null,"The actual transformation performed while executing a Deploy."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteCLValue")," Write the given ",(0,l.kt)("a",{parentName:"p",href:"#clvalue"},"CLValue")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteAccount")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#accounthash"},"Account")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteDeployInfo")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#deployinfo"},"DeployInfo")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteEraInfo")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#erainfo"},"EraInfo")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteTransfer")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#transfer"},"Transfer")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteBid")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#bid"},"Bid")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteWithdraw")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#unbondingpurse"},"Withdraw")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddInt32")," Adds the given ",(0,l.kt)("inlineCode",{parentName:"p"},"i32"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddUInt64")," Adds the given ",(0,l.kt)("inlineCode",{parentName:"p"},"u64"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddUInt128")," Adds the given ",(0,l.kt)("a",{parentName:"p",href:"#u128"},(0,l.kt)("inlineCode",{parentName:"a"},"U128")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddUInt256")," Adds the given ",(0,l.kt)("a",{parentName:"p",href:"#u256"},(0,l.kt)("inlineCode",{parentName:"a"},"U256")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddUInt512")," Adds the given ",(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddKeys")," Adds the given collection of ",(0,l.kt)("a",{parentName:"p",href:"#namedkey"},"named keys"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Failure")," A failed transformation, containing an error message."))),(0,l.kt)("h2",{id:"transformentry"},"TransformEntry"),(0,l.kt)("p",null,"A transformation performed while executing a Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The formatted string of the ",(0,l.kt)("inlineCode",{parentName:"p"},"Key"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transform"},(0,l.kt)("inlineCode",{parentName:"a"},"transforms"))," The transformation."))),(0,l.kt)("h2",{id:"u128"},"U128"),(0,l.kt)("p",null,"Decimal representation of a 128-bit integer."),(0,l.kt)("h2",{id:"u256"},"U256"),(0,l.kt)("p",null,"Decimal representation of a 256-bit integer."),(0,l.kt)("h2",{id:"u512"},"U512"),(0,l.kt)("p",null,"Decimal representation of a 512-bit integer."),(0,l.kt)("h2",{id:"unbondingpurse"},"UnbondingPurse"),(0,l.kt)("p",null,"Unbonding purse."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Unbonding amount.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse"))," Bonding purse.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_of_creation"))," Era in which the unbonding request was created.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"unbonder_public_key"))," Unbonder's public key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," The original validator's public key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#newvalidator"},(0,l.kt)("inlineCode",{parentName:"a"},"new_validator"))," The redelegated validator's public key."))),(0,l.kt)("h2",{id:"uref"},"URef"),(0,l.kt)("p",null,"Hex-encoded, formatted URef."),(0,l.kt)("h2",{id:"validatorchange"},"ValidatorChange"),(0,l.kt)("p",null,"A change to a validator's status between two eras."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Added"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Removed"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Banned"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"CannotPropose"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"SeenAsFaulty")))),(0,l.kt)("h2",{id:"validatorweight"},"ValidatorWeight"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"weight"))))),(0,l.kt)("h2",{id:"vestingschedule"},"VestingSchedule"),(0,l.kt)("p",null,"Vesting schedule for a genesis validator."),(0,l.kt)("h2",{id:"withdrawpurse"},"WithdrawPurse"),(0,l.kt)("p",null,"Withdraw purse, previously known as unbonding purse prior to 1.5. Withdraw purses remain as historical data."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Unbonding amount.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse"))," Bonding purse.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_of_creation"))," Era in which the unbonding request was created.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"unbonder_public_key"))," Unbonder's public key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," The original validator's public key."))))}N.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c2a85b60.71642d54.js b/assets/js/c2a85b60.71642d54.js deleted file mode 100644 index 8cd85fa677..0000000000 --- a/assets/js/c2a85b60.71642d54.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2614],{3905:function(e,a,t){t.d(a,{Zo:function(){return m},kt:function(){return N}});var n=t(7294);function r(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function l(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function i(e){for(var a=1;a=0||(r[t]=e[t]);return r}(e,a);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var o=n.createContext({}),k=function(e){var a=n.useContext(o),t=a;return e&&(t="function"==typeof e?e(a):i(i({},a),e)),t},m=function(e){var a=k(e.components);return n.createElement(o.Provider,{value:a},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},s=n.forwardRef((function(e,a){var t=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,m=p(e,["components","mdxType","originalType","parentName"]),d=k(t),s=r,N=d["".concat(o,".").concat(s)]||d[s]||u[s]||l;return t?n.createElement(N,i(i({ref:a},m),{},{components:t})):n.createElement(N,i({ref:a},m))}));function N(e,a){var t=arguments,r=a&&a.mdxType;if("string"==typeof e||r){var l=t.length,i=new Array(l);i[0]=s;var p={};for(var o in a)hasOwnProperty.call(a,o)&&(p[o]=a[o]);p.originalType=e,p[d]="string"==typeof e?e:r,i[1]=p;for(var k=2;kModuleBytes",id:"modulebytes",level:3},{value:"StoredContractByHash",id:"storedcontractbyhash",level:3},{value:"StoredContractByName",id:"storedcontractbyname",level:3},{value:"StoredVersionContractByHash",id:"storedversioncontractbyhash",level:3},{value:"StoredVersionContractByName",id:"storedversioncontractbyname",level:3},{value:"Transfer",id:"transfer",level:3},{value:"ExecutionEffect",id:"executioneffect",level:2},{value:"ExecutionResult",id:"executionresult",level:2},{value:"FinalizedApprovals",id:"finalizedapprovals",level:2},{value:"GlobalStateIdentifier",id:"globalstateidentifier",level:2},{value:"Group",id:"group",level:2},{value:"Groups",id:"groups",level:3},{value:"JsonBid",id:"jsonbid",level:2},{value:"JsonBids",id:"jsonbids",level:2},{value:"JsonBlock",id:"jsonblock",level:2},{value:"JsonBlockBody",id:"jsonblockbody",level:2},{value:"JsonBlockHeader",id:"jsonblockheader",level:2},{value:"JsonDelegator",id:"jsondelegator",level:2},{value:"JsonEraEnd",id:"jsoneraend",level:2},{value:"JsonEraReport",id:"jsonerareport",level:2},{value:"JsonEraValidators",id:"jsoneravalidators",level:2},{value:"JsonExecutionResult",id:"jsonexecutionresult",level:2},{value:"JsonProof",id:"jsonproof",level:2},{value:"JsonValidatorChanges",id:"jsonvalidatorchanges",level:2},{value:"JsonValidatorStatusChange",id:"jsonvalidatorstatuschange",level:2},{value:"JsonValidatorsWeights",id:"jsonvalidatorweights",level:2},{value:"Merkle_Proof",id:"merkle-proof",level:2},{value:"MinimalBlockInfo",id:"minimalblockinfo",level:2},{value:"NamedArg",id:"namedarg",level:2},{value:"NamedKey",id:"namedkey",level:2},{value:"NextUpgrade",id:"nextupgrade",level:2},{value:"NewValidator",id:"newvalidator",level:2},{value:"Operation",id:"operation",level:2},{value:"OpKind",id:"opkind",level:2},{value:"Parameter",id:"parameter",level:2},{value:"PeerEntry",id:"peerentry",level:2},{value:"PeersMap",id:"peersmap",level:2},{value:"ProtocolVersion",id:"protocolversion",level:2},{value:"PublicKey",id:"publickey",level:2},{value:"PurseIdentifier",id:"purseidentifier",level:2},{value:"ReactorState",id:"reactorstate",level:2},{value:"Reward",id:"reward",level:2},{value:"RuntimeArgs",id:"runtimeargs",level:2},{value:"SeigniorageAllocation",id:"seigniorageallocation",level:2},{value:"Signature",id:"signature",level:2},{value:"StoredValue",id:"storedvalue",level:2},{value:"TimeDiff",id:"timediff",level:2},{value:"Timestamp",id:"timestamp",level:2},{value:"Transfer",id:"transfer",level:2},{value:"TransferAddr",id:"transferaddr",level:2},{value:"Transform",id:"transform",level:2},{value:"TransformEntry",id:"transformentry",level:2},{value:"U128",id:"u128",level:2},{value:"U256",id:"u256",level:2},{value:"U512",id:"u512",level:2},{value:"UnbondingPurse",id:"unbondingpurse",level:2},{value:"URef",id:"uref",level:2},{value:"ValidatorChange",id:"validatorchange",level:2},{value:"ValidatorWeight",id:"validatorweight",level:2},{value:"VestingSchedule",id:"vestingschedule",level:2},{value:"WithdrawPurse",id:"withdrawpurse",level:2}],u={toc:d},s="wrapper";function N(e){var a=e.components,t=(0,r.Z)(e,i);return(0,l.kt)(s,(0,n.Z)({},u,t,{components:a,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"types"},"Types"),(0,l.kt)("p",null,"The following definitions expand on parameters seen elsewhere within the SDK standard and are provided for clarity and completeness."),(0,l.kt)("h2",{id:"account"},"Account"),(0,l.kt)("p",null,"Structure representing a user's Account, stored in global state."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"account_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#actionthresholds"},(0,l.kt)("inlineCode",{parentName:"a"},"action_thresholds")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#associatedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"associated_keys")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"main_purse")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#namedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"named_keys"))))),(0,l.kt)("h2",{id:"accounthash"},"AccountHash"),(0,l.kt)("p",null,"The AccountHash is a 32-byte hash derived from a supported PublicKey. Its role is to standardize keys that can vary in length."),(0,l.kt)("h2",{id:"actionthresholds"},"ActionThresholds"),(0,l.kt)("p",null,"Thresholds that have to be met when executing an action of a certain type."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"deployment"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key_management")))),(0,l.kt)("h2",{id:"activationpoint"},"ActivationPoint"),(0,l.kt)("p",null,"The first era to which the associated protocol version applies."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timestamp"},(0,l.kt)("inlineCode",{parentName:"a"},"timestamp"))))),(0,l.kt)("h2",{id:"approval"},"Approval"),(0,l.kt)("p",null,"A struct containing a signature and the public key of the signer."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#signature"},(0,l.kt)("inlineCode",{parentName:"a"},"signature")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"signer"))))),(0,l.kt)("h2",{id:"associatedkey"},"AssociatedKey"),(0,l.kt)("p",null,"A key granted limited permissions to an Account, for purposes such as multisig."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"account_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"weight")))),(0,l.kt)("h2",{id:"auctionstate"},"AuctionState"),(0,l.kt)("p",null,"Data structure summarizing auction contract data."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonbids"},(0,l.kt)("inlineCode",{parentName:"a"},"bids"))," All bids contained within a vector.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"block_height")," Block height.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsoneravalidators"},(0,l.kt)("inlineCode",{parentName:"a"},"era_validators"))," Era validators.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"state_root_hash"))," Global state hash."))),(0,l.kt)("h2",{id:"availableblockrange"},"AvailableBlockRange"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"low")," The inclusive lower bound of the range.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"high")," The inclusive upper bound of the range."))),(0,l.kt)("h2",{id:"bid"},"Bid"),(0,l.kt)("p",null,"An entry in the validator map."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse"))," The purse that was used for bonding.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegation_rate")," The delegation rate.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#delegator"},(0,l.kt)("inlineCode",{parentName:"a"},"delegators"))," The validator's delegators, indexed by their public keys.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"inactive")," ",(0,l.kt)("inlineCode",{parentName:"p"},"true"),' if validator has been "evicted".')),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"staked_amount"))," The amount of tokens staked by a validator (not including delegators).")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," Validator's public key."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#vestingschedule"},(0,l.kt)("inlineCode",{parentName:"a"},"vesting_schedule"))," Vesting schedule for a genesis validator. ",(0,l.kt)("inlineCode",{parentName:"li"},"None")," if non-genesis validator.")),(0,l.kt)("h2",{id:"blockhash"},"BlockHash"),(0,l.kt)("p",null,"A cryptographic hash identifying a ",(0,l.kt)("inlineCode",{parentName:"p"},"Block"),"."),(0,l.kt)("h2",{id:"blockidentifier"},"BlockIdentifier"),(0,l.kt)("p",null,"Identifier for possible ways to retrieve a Block."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"Hash"))," Identify and retrieve the Block with its hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Height")," Identify and retrieve the Block with its height."))),(0,l.kt)("h2",{id:"blocksynchronizerstatus"},"BlockSynchronizerStatus"),(0,l.kt)("p",null,"The status of the block synchronizer."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Historical")," The status of syncing a historical block, if any."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash-blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"block_hash"))," The block hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"block_height")," The height of the block, if known.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"acquisition_state")," The state of acquisition of the data associated with the block.")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Forward")," The status of syncing a forward block, if any."),(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash-blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"block_hash"))," The block hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"block_height")," The height of the block, if known.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"acquisition_state")," The state of acquisition of the data associated with the block."))))),(0,l.kt)("h2",{id:"chainspecrawbytes"},"ChainspecRawBytes"),(0,l.kt)("p",null,"The raw bytes of the chainspec.toml, genesis accounts.toml, and global_state.toml files."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"chainspec_bytes")," Hex-encoded raw bytes of the current chainspec.toml file.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"maybe_genesis_accounts_bytes")," Hex-encoded raw bytes of the current genesis accounts.toml file.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"maybe_global_state_bytes")," Hex-encoded raw bytes of the current global_state.toml file."))),(0,l.kt)("h2",{id:"contract"},"Contract"),(0,l.kt)("p",null,"A contract struct that can be serialized as a JSON object."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"#contractpackagehash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_package_hash"))),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"#contractwasmhash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_wasm_hash"))),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"#entrypoint"},(0,l.kt)("inlineCode",{parentName:"a"},"entry_points"))),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"#namedkey"},(0,l.kt)("inlineCode",{parentName:"a"},"named_keys"))),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version")),(0,l.kt)("h2",{id:"contracthash"},"ContractHash"),(0,l.kt)("p",null,"The hash address of the contract."),(0,l.kt)("h2",{id:"contractpackge"},"ContractPackage"),(0,l.kt)("p",null,"Contract definition, metadata and security container."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"access_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#disabledversions"},(0,l.kt)("inlineCode",{parentName:"a"},"disabled_versions")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#groups"},(0,l.kt)("inlineCode",{parentName:"a"},"groups")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contractversion"},(0,l.kt)("inlineCode",{parentName:"a"},"versions"))))),(0,l.kt)("h2",{id:"contractpackagehash"},"ContractPackageHash"),(0,l.kt)("p",null,"The hash address of the contract package."),(0,l.kt)("h2",{id:"contractversion"},"ContractVersion"),(0,l.kt)("p",null,"The version of the contract."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contracthash"},(0,l.kt)("inlineCode",{parentName:"a"},"contract_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract_version"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version_major")))),(0,l.kt)("h2",{id:"contractwasmhash"},"ContractWasmHash"),(0,l.kt)("p",null,"The hash address of the contract Wasm."),(0,l.kt)("h2",{id:"delegator"},"Delegator"),(0,l.kt)("p",null,'Represents a party delegating their stake to a validator (or "delegatee").'),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"delegator_public_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"staked_amount")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#vestingschedule"},(0,l.kt)("inlineCode",{parentName:"a"},"vesting_schedule")))),(0,l.kt)("h2",{id:"deploy"},"Deploy"),(0,l.kt)("p",null,"A Deploy; an item containing a smart contract along with the requester's signature(s)."),(0,l.kt)("p",null,"Required properties:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#approval"},(0,l.kt)("inlineCode",{parentName:"a"},"approvals")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployheader"},(0,l.kt)("inlineCode",{parentName:"a"},"header")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executabledeployitem"},(0,l.kt)("inlineCode",{parentName:"a"},"payment")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executabledeployitem"},(0,l.kt)("inlineCode",{parentName:"a"},"sessions"))))),(0,l.kt)("h2",{id:"deployhash"},"DeployHash"),(0,l.kt)("p",null,"Hex-encoded Deploy hash."),(0,l.kt)("h2",{id:"deployheader"},"DeployHeader"),(0,l.kt)("p",null,"The header portion of a Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"account")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"body_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"chain_name")," A user defined string.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"dependencies")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"gas_price")," Defined as an integer in UInt64 format.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timestamp"},(0,l.kt)("inlineCode",{parentName:"a"},"timestamp")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timediff"},(0,l.kt)("inlineCode",{parentName:"a"},"ttl"))))),(0,l.kt)("h2",{id:"deployinfo"},"DeployInfo"),(0,l.kt)("p",null,"Information relating to the given Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"deploy_hash"))," The relevant Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"from"))," Account identifier of the creator of the Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"gas"))," Gas cost of executing the Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"source"))," Source purse used for payment of the Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transferaddr"},(0,l.kt)("inlineCode",{parentName:"a"},"transfers"))," Transfers performed by the Deploy."))),(0,l.kt)("h2",{id:"dictionaryidentifier"},"DictionaryIdentifier"),(0,l.kt)("p",null,"Options for dictionary item lookups."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AccountNamedKey")," Lookup a dictionary item via an Account's named keys."),(0,l.kt)("p",{parentName:"li"},"Required Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The Account key as a formatted string whose named keys contain dictionary_name."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_name")," The named key under which the dictionary seed URef is stored."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_item_key")," The dictionary item key formatted as a string.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"ContractNamedKey")," Lookup a dictionary item via a Contract's named keys."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The contract key as a formatted string whose named keys contains dictionary_name."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_name")," The named key under which the dictionary seed URef is stored."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_item_key")," The dictionary item key formatted as a string.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"URef")," Lookup a dictionary item via its seed URef."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"seed_uref")," The dictionary's seed URef."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"dictionary_item_key")," The dictionary item key formatted as a string.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Dictionary")," Lookup a dictionary item via its unique key."))),(0,l.kt)("h2",{id:"digest"},"Digest"),(0,l.kt)("p",null,"Hex-encoded hash digest."),(0,l.kt)("h2",{id:"disabledversions"},"DisabledVersions"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract_version"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version_major")))),(0,l.kt)("h2",{id:"entrypoint"},"EntryPoint"),(0,l.kt)("p",null,"Metadata describing a callable entry point and its return value, if any. All required parameters should be declared, whereas all non-required parameters should not be declared. Non-required parameters should not be confused with optional parameters."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#entrypointaccess"},(0,l.kt)("inlineCode",{parentName:"a"},"access")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#parameter"},(0,l.kt)("inlineCode",{parentName:"a"},"args")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#entrypointtype"},(0,l.kt)("inlineCode",{parentName:"a"},"entry_point_type")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#cltype"},(0,l.kt)("inlineCode",{parentName:"a"},"ret"))))),(0,l.kt)("h2",{id:"entrypointaccess"},"EntryPointAccess"),(0,l.kt)("p",null,"Enum describing the possible access control options for a contract entry point."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Public")," A public entry point is callable by any caller.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#group"},(0,l.kt)("inlineCode",{parentName:"a"},"Groups"))," Only callers from the authorized, listed groups may call this entry point. Note: If this list is empty then this entry point is not callable from outside the contract."))),(0,l.kt)("h2",{id:"entrypointype"},"EntryPointType"),(0,l.kt)("p",null,"Context of an entry point execution."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"session")," Executes in the caller's context.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"contract")," Executes in the callee's context."))),(0,l.kt)("h2",{id:"eraid"},"EraID"),(0,l.kt)("p",null,"Era ID newtype."),(0,l.kt)("h2",{id:"erainfo"},"EraInfo"),(0,l.kt)("p",null,"Auction metadata. Intended to be recorded at each era."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#seigniorageallocation-seigniorageallocation"},(0,l.kt)("inlineCode",{parentName:"a"},"seigniorage_allocation"))," Information about a seigniorage allocation.")),(0,l.kt)("h2",{id:"erasummary"},"EraSummary"),(0,l.kt)("p",null,"The summary of an era."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"block_hash"))," The Block hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id"))," The era id.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#merkle-proof"},(0,l.kt)("inlineCode",{parentName:"a"},"merkle_proof"))," The merkle proof.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"state_root_hash"))," Hex-encoded hash of the state root.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#storedvalue"},(0,l.kt)("inlineCode",{parentName:"a"},"stored_value"))," The StoredValue containing era information."))),(0,l.kt)("h2",{id:"executabledeployitem"},"ExecutableDeployItem"),(0,l.kt)("p",null,"Represents possible variants of an executable Deploy."),(0,l.kt)("h3",{id:"modulebytes"},(0,l.kt)("inlineCode",{parentName:"h3"},"ModuleBytes")),(0,l.kt)("p",null,"Executable specified as raw bytes that represent Wasm code and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"module_bytes")," Hex-encoded raw Wasm bytes. There are some special cases around passing ",(0,l.kt)("inlineCode",{parentName:"li"},"module_bytes")," for payment code.")),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("h3",{id:"storedcontractbyhash"},(0,l.kt)("inlineCode",{parentName:"h3"},"StoredContractByHash")),(0,l.kt)("p",null,"Stored contract referenced by its ",(0,l.kt)("inlineCode",{parentName:"p"},"ContractHash"),", entry point and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point")," The name of an entry point.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"hash")," A hex-encoded hash."))),(0,l.kt)("h3",{id:"storedcontractbyname"},(0,l.kt)("inlineCode",{parentName:"h3"},"StoredContractByName")),(0,l.kt)("p",null,"Stored contract referenced by a named key existing in the signer's Account context, entry point and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point")," The name of an entry point.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," A named key."))),(0,l.kt)("h3",{id:"storedversioncontractbyhash"},(0,l.kt)("inlineCode",{parentName:"h3"},"StoredVersionContractByHash")),(0,l.kt)("p",null,"Stored versioned contract referenced by its ",(0,l.kt)("inlineCode",{parentName:"p"},"ContractPackageHash"),", entry point and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point")," The name of an entry point.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"hash")," A hex-encoded hash."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"version")," An optional version of the contract to call. It will default to the highest enabled version if no value is specified.")),(0,l.kt)("h3",{id:"storedversioncontractbyname"},(0,l.kt)("inlineCode",{parentName:"h3"},"StoredVersionContractByName")),(0,l.kt)("p",null,"Stored versioned contract referenced by a named key existing in the signer's Account context, entry point and an instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"RuntimeArgs"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args"))," Runtime arguments.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"entry_point")," The name of an entry point.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," A named key."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("inlineCode",{parentName:"li"},"version")," An optional version of the contract to call. It will default to the highest enabled version if no value is specified.")),(0,l.kt)("h3",{id:"transfer"},(0,l.kt)("inlineCode",{parentName:"h3"},"Transfer")),(0,l.kt)("p",null,"A native transfer which does not contain or reference a Wasm code."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#runtimeargs"},(0,l.kt)("inlineCode",{parentName:"a"},"args")))),(0,l.kt)("h2",{id:"executioneffect"},"ExecutionEffect"),(0,l.kt)("p",null,"The journal of execution transforms from a single Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#oepration"},(0,l.kt)("inlineCode",{parentName:"a"},"operations")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transformentry"},(0,l.kt)("inlineCode",{parentName:"a"},"transforms"))))),(0,l.kt)("h2",{id:"executionresult"},"ExecutionResult"),(0,l.kt)("p",null,"The result of executing a single Deploy."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Failure")," The result of a failed execution`"),(0,l.kt)("p",{parentName:"li"},"Required Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executioneffect"},(0,l.kt)("inlineCode",{parentName:"a"},"effect"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transferaddr"},(0,l.kt)("inlineCode",{parentName:"a"},"transfers"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"cost"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"error_message")," The error message associated with executing the Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Success")," The result of a successful execution."),(0,l.kt)("p",{parentName:"li"},"Required Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executioneffect"},(0,l.kt)("inlineCode",{parentName:"a"},"effect"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transferaddr"},(0,l.kt)("inlineCode",{parentName:"a"},"transfers"))),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"cost"))))),(0,l.kt)("h2",{id:"finalizedapprovals"},"FinalizedApprovals"),(0,l.kt)("p",null,"A boolean value that determines whether to return the deploy with the finalized approvals substituted. If ",(0,l.kt)("inlineCode",{parentName:"p"},"false")," or omitted, returns the deploy with the approvals that were originally received by the node."),(0,l.kt)("h2",{id:"globalstateidentifier"},"GlobalStateIdentifier"),(0,l.kt)("p",null,"Identifier for possible ways to query global state."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"BlockHash"))," Query using a Block hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"StateRootHash"))," Query using the state root hash."))),(0,l.kt)("h2",{id:"group"},"Group"),(0,l.kt)("p",null,'A (labelled) "user group". Each entry point of a versioned contract may be associated with one or more user groups which are allowed to call it.'),(0,l.kt)("h3",{id:"groups"},"Groups"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"group"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"keys"))))),(0,l.kt)("h2",{id:"jsonbid"},"JsonBid"),(0,l.kt)("p",null,"An entry in a founding validator map representing a bid."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse"))," The purse that was used for bonding.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"delegation_rate")," The delegation rate.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsondelegator"},(0,l.kt)("inlineCode",{parentName:"a"},"delegators"))," The delegators.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"inactive")," Is this an inactive validator.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"staked_amount"))," The amount of tokens staked by a validator (not including delegators)."))),(0,l.kt)("h2",{id:"jsonbids"},"JsonBids"),(0,l.kt)("p",null,"A Json representation of a single bid."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonbid"},(0,l.kt)("inlineCode",{parentName:"a"},"bid")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key"))))),(0,l.kt)("h2",{id:"jsonblock"},"JsonBlock"),(0,l.kt)("p",null,"A JSON-friendly representation of ",(0,l.kt)("inlineCode",{parentName:"p"},"Block"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonblockbody"},(0,l.kt)("inlineCode",{parentName:"a"},"body"))," JSON-friendly Block body.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"hash"))," BlockHash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonblockheader"},(0,l.kt)("inlineCode",{parentName:"a"},"header"))," JSON-friendly Block header.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonproof"},(0,l.kt)("inlineCode",{parentName:"a"},"proofs"))," JSON-friendly list of proofs for this Block."))),(0,l.kt)("h2",{id:"jsonblockbody"},"JsonBlockBody"),(0,l.kt)("p",null,"A JSON-friendly representation of ",(0,l.kt)("inlineCode",{parentName:"p"},"Body"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"deploy_hashes")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"proposer")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"transfer_hashes"))))),(0,l.kt)("h2",{id:"jsonblockheader"},"JsonBlockHeader"),(0,l.kt)("p",null,"JSON representation of a Block header."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"accumulated_seed"))," Accumulated seed.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"body_hash"))," The body hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id"))," The Block era id.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"height")," The Block height.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"parent_hash"))," The parent hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#protocolversion"},(0,l.kt)("inlineCode",{parentName:"a"},"protocol_version"))," The protocol version.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"random_bit")," Randomness bit.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"state_root_hash"))," The state root hash.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timestamp"},(0,l.kt)("inlineCode",{parentName:"a"},"timestamp"))," The Block timestamp."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"#jsoneraend"},(0,l.kt)("inlineCode",{parentName:"a"},"era_end"))," The era end.")),(0,l.kt)("h2",{id:"jsondelegator"},"JsonDelegator"),(0,l.kt)("p",null,"A delegator associated with the given validator."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"delegatee")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"staked_amount"))))),(0,l.kt)("h2",{id:"jsoneraend"},"JsonEraEnd"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonerareport"},"`era_report"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#validatorweight"},(0,l.kt)("inlineCode",{parentName:"a"},"next_era_validator_weight"))))),(0,l.kt)("h2",{id:"jsonerareport"},"JsonEraReport"),(0,l.kt)("p",null,"Equivocation and reward information to be included in the terminal Block."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"equivocators")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"inactive_validators")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#reward"},(0,l.kt)("inlineCode",{parentName:"a"},"rewards"))))),(0,l.kt)("h2",{id:"jsoneravalidators"},"JsonEraValidators"),(0,l.kt)("p",null,"The validators for the given era."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonvalidatorsweights"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_weights"))))),(0,l.kt)("h2",{id:"jsonexecutionresult"},"JsonExecutionResult"),(0,l.kt)("p",null,"The execution result of a single Deploy."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"block_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#executionresult"},(0,l.kt)("inlineCode",{parentName:"a"},"result"))))),(0,l.kt)("h2",{id:"jsonproof"},"JsonProof"),(0,l.kt)("p",null,"A JSON-friendly representation of a proof, i.e. a Block's finality signature."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#signature"},(0,l.kt)("inlineCode",{parentName:"a"},"signature"))))),(0,l.kt)("h2",{id:"jsonvalidatorchanges"},"JsonValidatorChanges"),(0,l.kt)("p",null,"The changes in a validator's status."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key"))," The public key of the validator.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#jsonvalidatorstatuschange"},(0,l.kt)("inlineCode",{parentName:"a"},"status_changes"))," The set of changes to the validator's status."))),(0,l.kt)("h2",{id:"jsonvalidatorstatuschange"},"JsonValidatorStatusChange"),(0,l.kt)("p",null,"A single change to a validator's status in the given era."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id"))," The era in which the change occurred.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#validatorchange"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_change"))," The change in validator status."))),(0,l.kt)("h2",{id:"jsonvalidatorweights"},"JsonValidatorsWeights"),(0,l.kt)("p",null,"A validator's weight."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"public_key")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"weight"))))),(0,l.kt)("h2",{id:"merkle-proof"},"Merkle_Proof"),(0,l.kt)("p",null,"A merkle proof is a construction created using a merkle trie that allows verification of the associated hashes."),(0,l.kt)("h2",{id:"minimalblockinfo"},"MinimalBlockInfo"),(0,l.kt)("p",null,"Minimal info of a ",(0,l.kt)("inlineCode",{parentName:"p"},"Block"),"."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"creator")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_id")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#blockhash"},(0,l.kt)("inlineCode",{parentName:"a"},"hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"height"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#digest"},(0,l.kt)("inlineCode",{parentName:"a"},"state_root_hash")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#timestamp"},(0,l.kt)("inlineCode",{parentName:"a"},"timestamp"))))),(0,l.kt)("h2",{id:"namedarg"},"NamedArg"),(0,l.kt)("p",null,"Named arguments to a contract."),(0,l.kt)("h2",{id:"namedkey"},"NamedKey"),(0,l.kt)("p",null,"A named key."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The value of the entry: a casper ",(0,l.kt)("inlineCode",{parentName:"p"},"Key")," type.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")," The name of the entry."))),(0,l.kt)("h2",{id:"nextupgrade"},"NextUpgrade"),(0,l.kt)("p",null,"Information about the next protocol upgrade."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#activationpoint"},(0,l.kt)("inlineCode",{parentName:"a"},"activation_point")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"protocol_version")))),(0,l.kt)("h2",{id:"newvalidator"},"NewValidator"),(0,l.kt)("p",null,"The public key for the new validator in a redelegation using ",(0,l.kt)("a",{parentName:"p",href:"#unbondingpurse"},"UnbondingPurse"),"."),(0,l.kt)("h2",{id:"operation"},"Operation"),(0,l.kt)("p",null,"An operation performed while executing a Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The formatted string of the ",(0,l.kt)("inlineCode",{parentName:"p"},"Key"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#opkind"},(0,l.kt)("inlineCode",{parentName:"a"},"kind"))))),(0,l.kt)("h2",{id:"opkind"},"OpKind"),(0,l.kt)("p",null,"The type of operation performed while executing a Deploy."),(0,l.kt)("h2",{id:"parameter"},"Parameter"),(0,l.kt)("p",null,"Parameter to an entry point."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#cltype"},(0,l.kt)("inlineCode",{parentName:"a"},"cl_type")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"name")))),(0,l.kt)("h2",{id:"peerentry"},"PeerEntry"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"address"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"node_id")))),(0,l.kt)("h2",{id:"peersmap"},"PeersMap"),(0,l.kt)("p",null,"Map of peer IDs to network addresses."),(0,l.kt)("h2",{id:"protocolversion"},"ProtocolVersion"),(0,l.kt)("p",null,"Casper Platform protocol version."),(0,l.kt)("h2",{id:"publickey"},"PublicKey"),(0,l.kt)("p",null,"Hex-encoded cryptographic public key, including the algorithm tag prefix."),(0,l.kt)("h2",{id:"purseidentifier"},"PurseIdentifier"),(0,l.kt)("p",null,"The identifier to obtain the purse corresponding to a balance query. Valid identifiers include:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"main_purse_under_public_key")," The main purse under a provided ",(0,l.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"PublicKey")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"main_purse_under_account_hash")," The main purse under a provided ",(0,l.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"AccountHash")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"purse_uref")," A specific purse identified by the associated ",(0,l.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"URef")),"."))),(0,l.kt)("h2",{id:"reactorstate"},"ReactorState"),(0,l.kt)("p",null,"The state of the reactor, which will return one of the following:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Initialize")," Get all components and reactor state set up on start.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"CatchUp")," Orient to the network and attempt to catch up to tip.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Upgrading")," Running commit upgrade and creating immediate switch block.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"KeepUp")," Stay caught up with tip.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Validate")," Node is currently caught up and is an active validator.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"ShutdownForUpgrade")," Node should be shut down for upgrade."))),(0,l.kt)("h2",{id:"reward"},"Reward"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"amount"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator"))))),(0,l.kt)("h2",{id:"runtimeargs"},"RuntimeArgs"),(0,l.kt)("p",null,"Represents a collection of arguments passed to a smart contract."),(0,l.kt)("h2",{id:"seigniorageallocation"},"SeigniorageAllocation"),(0,l.kt)("p",null,"Information about a seigniorage allocation."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Validator")," Info about a seigniorage allocation for a validator."),(0,l.kt)("p",{parentName:"li"},"Required Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Allocated amount."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," Validator's public key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Delegator")," Info about a seigniorage allocation for a delegator."),(0,l.kt)("p",{parentName:"li"},"Require Parameters:"),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Allocated amount."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"delegator_public_key"))," Delegator's public key."),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," Validator's public key."))),(0,l.kt)("h2",{id:"signature"},"Signature"),(0,l.kt)("p",null,"Hex-encoded cryptographic signature, including the algorithm tag prefix."),(0,l.kt)("h2",{id:"storedvalue"},"StoredValue"),(0,l.kt)("p",null,"Representation of a value stored in global state. ",(0,l.kt)("inlineCode",{parentName:"p"},"Account"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"Contract")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"ContractPackage")," have their own ",(0,l.kt)("inlineCode",{parentName:"p"},"json_compatibility")," representation (see their docs for further info)."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#clvalue"},(0,l.kt)("inlineCode",{parentName:"a"},"CLValue"))," A Casper-specific value.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#account"},(0,l.kt)("inlineCode",{parentName:"a"},"Account"))," An Account.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"ContractWasm")," A contract's Wasm.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contract"},(0,l.kt)("inlineCode",{parentName:"a"},"Contract"))," Entry points supported by a contract.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#contractpackage"},(0,l.kt)("inlineCode",{parentName:"a"},"ContractPackage"))," A contract definition, metadata, and security container.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transfer"},(0,l.kt)("inlineCode",{parentName:"a"},"Transfer"))," A record of a transfer.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployinfo"},(0,l.kt)("inlineCode",{parentName:"a"},"DeployInfo"))," A record of a Deploy.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#erainfo"},(0,l.kt)("inlineCode",{parentName:"a"},"EraInfo"))," Auction metadata.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#bid-bid"},(0,l.kt)("inlineCode",{parentName:"a"},"Bid"))," A bid.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#unbondingpurse"},(0,l.kt)("inlineCode",{parentName:"a"},"Withdraw"))," A withdraw."))),(0,l.kt)("h2",{id:"timediff"},"TimeDiff"),(0,l.kt)("p",null,"Human-readable duration."),(0,l.kt)("h2",{id:"timestamp"},"Timestamp"),(0,l.kt)("p",null,"Timestamp formatted as per RFC 3339."),(0,l.kt)("h2",{id:"transfer"},"Transfer"),(0,l.kt)("p",null,"Represents a transfer from one purse to another."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Transfer amount.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#deployhash"},(0,l.kt)("inlineCode",{parentName:"a"},"deploy_hash"))," Deploy that created the transfer.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"from"))," Account from which transfer was executed.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"gas")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"source"))," Source purse.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"target"))," Target purse."))),(0,l.kt)("p",null,"Additional Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"id")," User-defined ID.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#accounthash"},(0,l.kt)("inlineCode",{parentName:"a"},"to"))," Account to which funds are transferred."))),(0,l.kt)("h2",{id:"transferaddr"},"TransferAddr"),(0,l.kt)("p",null,"Hex-encoded transfer address."),(0,l.kt)("h2",{id:"transform"},"Transform"),(0,l.kt)("p",null,"The actual transformation performed while executing a Deploy."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteCLValue")," Write the given ",(0,l.kt)("a",{parentName:"p",href:"#clvalue"},"CLValue")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteAccount")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#accounthash"},"Account")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteDeployInfo")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#deployinfo"},"DeployInfo")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteEraInfo")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#erainfo"},"EraInfo")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteTransfer")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#transfer"},"Transfer")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteBid")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#bid"},"Bid")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"WriteWithdraw")," Writes the given ",(0,l.kt)("a",{parentName:"p",href:"#unbondingpurse"},"Withdraw")," to global state.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddInt32")," Adds the given ",(0,l.kt)("inlineCode",{parentName:"p"},"i32"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddUInt64")," Adds the given ",(0,l.kt)("inlineCode",{parentName:"p"},"u64"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddUInt128")," Adds the given ",(0,l.kt)("a",{parentName:"p",href:"#u128"},(0,l.kt)("inlineCode",{parentName:"a"},"U128")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddUInt256")," Adds the given ",(0,l.kt)("a",{parentName:"p",href:"#u256"},(0,l.kt)("inlineCode",{parentName:"a"},"U256")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddUInt512")," Adds the given ",(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"U512")),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"AddKeys")," Adds the given collection of ",(0,l.kt)("a",{parentName:"p",href:"#namedkey"},"named keys"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Failure")," A failed transformation, containing an error message."))),(0,l.kt)("h2",{id:"transformentry"},"TransformEntry"),(0,l.kt)("p",null,"A transformation performed while executing a Deploy."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"key")," The formatted string of the ",(0,l.kt)("inlineCode",{parentName:"p"},"Key"),".")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#transform"},(0,l.kt)("inlineCode",{parentName:"a"},"transforms"))," The transformation."))),(0,l.kt)("h2",{id:"u128"},"U128"),(0,l.kt)("p",null,"Decimal representation of a 128-bit integer."),(0,l.kt)("h2",{id:"u256"},"U256"),(0,l.kt)("p",null,"Decimal representation of a 256-bit integer."),(0,l.kt)("h2",{id:"u512"},"U512"),(0,l.kt)("p",null,"Decimal representation of a 512-bit integer."),(0,l.kt)("h2",{id:"unbondingpurse"},"UnbondingPurse"),(0,l.kt)("p",null,"Unbonding purse."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Unbonding amount.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse"))," Bonding purse.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_of_creation"))," Era in which the unbonding request was created.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"unbonder_public_key"))," Unbonder's public key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," The original validator's public key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#newvalidator"},(0,l.kt)("inlineCode",{parentName:"a"},"new_validator"))," The redelegated validator's public key."))),(0,l.kt)("h2",{id:"uref"},"URef"),(0,l.kt)("p",null,"Hex-encoded, formatted URef."),(0,l.kt)("h2",{id:"validatorchange"},"ValidatorChange"),(0,l.kt)("p",null,"A change to a validator's status between two eras."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Added"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Removed"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"Banned"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"CannotPropose"))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"SeenAsFaulty")))),(0,l.kt)("h2",{id:"validatorweight"},"ValidatorWeight"),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator")))),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"weight"))))),(0,l.kt)("h2",{id:"vestingschedule"},"VestingSchedule"),(0,l.kt)("p",null,"Vesting schedule for a genesis validator."),(0,l.kt)("h2",{id:"withdrawpurse"},"WithdrawPurse"),(0,l.kt)("p",null,"Withdraw purse, previously known as unbonding purse prior to 1.5. Withdraw purses remain as historical data."),(0,l.kt)("p",null,"Required Parameters:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#u512"},(0,l.kt)("inlineCode",{parentName:"a"},"amount"))," Unbonding amount.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#uref"},(0,l.kt)("inlineCode",{parentName:"a"},"bonding_purse"))," Bonding purse.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#eraid"},(0,l.kt)("inlineCode",{parentName:"a"},"era_of_creation"))," Era in which the unbonding request was created.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"unbonder_public_key"))," Unbonder's public key.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},(0,l.kt)("a",{parentName:"p",href:"#publickey"},(0,l.kt)("inlineCode",{parentName:"a"},"validator_public_key"))," The original validator's public key."))))}N.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c305f31a.43db811a.js b/assets/js/c305f31a.43db811a.js new file mode 100644 index 0000000000..2c39b8f9fa --- /dev/null +++ b/assets/js/c305f31a.43db811a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6646],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(n),h=o,m=c["".concat(s,".").concat(h)]||c[h]||u[h]||r;return n?a.createElement(m,i(i({ref:t},p),{},{components:n})):a.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:o,i[1]=l;for(var d=2;d \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point undelegate \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"delegator:public_key=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entry point that will be used when calling the contract")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"undelegate")," entry point expects three arguments:"),(0,r.kt)("ol",{start:7},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"validator"),": The hexadecimal public key of the validator from whom the tokens will be undelegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The number of tokens to be undelegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"delegator"),": The hexadecimal public key of the account undelegating tokens from a validator. ",(0,r.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the delegation"))),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"undelegate")," entry point on the auction contract has a fixed cost of 2.5 CSPR. There is no minimum amount required for the undelegation call.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example shows an account delegating 100 CSPR:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key ~/KEYS/secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point undelegate \\\n--session-arg \"validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'\" \\\n--session-arg \"amount:u512='100000000000'\" \\\n--session-arg \"delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'\"\n")),(0,r.kt)("p",null,"Next, ",(0,r.kt)("a",{parentName:"p",href:"#verifying-the-undelegation"},"confirm the undelegation"),"."),(0,r.kt)("h3",{id:"undelegating-compiled-wasm"},"Method 2: Undelegating with Compiled Wasm"),(0,r.kt)("p",null,"As part of this process, you need to ",(0,r.kt)("a",{parentName:"p",href:"/developers/cli/delegate#building-the-delegation-wasm"},"build the casper-node contracts")," that produce the undelegation Wasm."),(0,r.kt)("p",null,"Next, use the Casper CLI client to send a deploy containing the ",(0,r.kt)("inlineCode",{parentName:"p"},"undelegate.wasm")," to the network to initiate the undelegation process."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path /undelegate.wasm \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"delegator:public_key=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to where the ",(0,r.kt)("inlineCode",{parentName:"li"},"delegate.wasm")," is located")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"undelegate")," entry point expects three arguments:"),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"validator"),": The hexadecimal public key of the validator from whom the tokens will be undelegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The number of tokens to be undelegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"delegator"),": The hexadecimal public key of the account undelegating tokens from a validator. ",(0,r.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the delegation"))),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example command uses the Casper Testnet to undelegate 100 CSPR, and the payment amount is 6 CSPR. The payment amount varies based on each deploy and network ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". However, notice that this method is more expensive than the previous one that calls the undelegate entry point."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key ~/KEYS/secret_key.pem \\\n--payment-amount 6000000000 \\\n--session-path ~/undelegate.wasm \\\n--session-arg \"validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'\" \\\n--session-arg \"amount:u512='100000000000'\" \\\n--session-arg \"delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'\"\n")),(0,r.kt)("p",null,"Next, ",(0,r.kt)("a",{parentName:"p",href:"#verifying-the-undelegation"},"confirm the undelegation"),"."),(0,r.kt)("h2",{id:"verifying-the-undelegation"},"Verifying the Undelegation"),(0,r.kt)("p",null,"To verify that the undelegation succeeded, you can use the Casper command-line client to generate an RPC request to query the auction state. The subsequent RPC response will confirm that the undelegation request was successfully processed."),(0,r.kt)("p",null,"Here is how you can check the status of the auction to confirm that your bid was withdrawn:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info \\\n--node-address http://:7777\n")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Request fields"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network")),(0,r.kt)("p",null,"If the public key and the amount are absent from the ",(0,r.kt)("inlineCode",{parentName:"p"},"bids")," structure, we can safely conclude that we have indeed undelegated from the validator."),(0,r.kt)("p",null,"If your account is on the official Testnet or Mainnet, you can use the block explorer to look up your account balance and see that the tokens have been added to your balance:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"https://testnet.cspr.live/"},"Testnet explorer")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"https://cspr.live/"},"Mainnet explorer"))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Important Note"),": After undelegating tokens from a validator, you must wait for the unbonding period to lapse before redelegating tokens to either the same validator or a different validator."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c305f31a.66b93372.js b/assets/js/c305f31a.66b93372.js deleted file mode 100644 index 910d9d72eb..0000000000 --- a/assets/js/c305f31a.66b93372.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6646],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return m}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(n),h=o,m=c["".concat(s,".").concat(h)]||c[h]||u[h]||r;return n?a.createElement(m,i(i({ref:t},p),{},{components:n})):a.createElement(m,i({ref:t},p))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:o,i[1]=l;for(var d=2;d \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point undelegate \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"delegator:public_key=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,r.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entry point that will be used when calling the contract")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"undelegate")," entry point expects three arguments:"),(0,r.kt)("ol",{start:7},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"validator"),": The hexadecimal public key of the validator from whom the tokens will be undelegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The number of tokens to be undelegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"delegator"),": The hexadecimal public key of the account undelegating tokens from a validator. ",(0,r.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the delegation"))),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"Calling the ",(0,r.kt)("inlineCode",{parentName:"p"},"undelegate")," entry point on the auction contract has a fixed cost of 2.5 CSPR. There is no minimum amount required for the undelegation call.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example shows an account delegating 100 CSPR:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key ~/KEYS/secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point undelegate \\\n--session-arg \"validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'\" \\\n--session-arg \"amount:u512='100000000000'\" \\\n--session-arg \"delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'\"\n")),(0,r.kt)("p",null,"Next, ",(0,r.kt)("a",{parentName:"p",href:"#verifying-the-undelegation"},"confirm the undelegation"),"."),(0,r.kt)("h3",{id:"undelegating-compiled-wasm"},"Method 2: Undelegating with Compiled Wasm"),(0,r.kt)("p",null,"As part of this process, you need to ",(0,r.kt)("a",{parentName:"p",href:"/developers/cli/delegate#building-the-delegation-wasm"},"build the casper-node contracts")," that produce the undelegation Wasm."),(0,r.kt)("p",null,"Next, use the Casper CLI client to send a deploy containing the ",(0,r.kt)("inlineCode",{parentName:"p"},"undelegate.wasm")," to the network to initiate the undelegation process."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-path /undelegate.wasm \\\n--session-arg \"validator:public_key=''\" \\\n--session-arg \"amount:u512=''\" \\\n--session-arg \"delegator:public_key=''\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,r.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,r.kt)("em",{parentName:"li"},"casper-test")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,r.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to where the ",(0,r.kt)("inlineCode",{parentName:"li"},"delegate.wasm")," is located")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"undelegate")," entry point expects three arguments:"),(0,r.kt)("ol",{start:6},(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"validator"),": The hexadecimal public key of the validator from whom the tokens will be undelegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"amount"),": The number of tokens to be undelegated"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"delegator"),": The hexadecimal public key of the account undelegating tokens from a validator. ",(0,r.kt)("strong",{parentName:"li"},"This key must match the secret key that signs the delegation"))),(0,r.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the ",(0,r.kt)("a",{parentName:"p",href:"/resources/tutorials/beginner/querying-network#deploy-status"},"Deploy Status")," section for more details."),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("p",null,"This example command uses the Casper Testnet to undelegate 100 CSPR, and the payment amount is 6 CSPR. The payment amount varies based on each deploy and network ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),". However, notice that this method is more expensive than the previous one that calls the undelegate entry point."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key ~/KEYS/secret_key.pem \\\n--payment-amount 6000000000 \\\n--session-path ~/undelegate.wasm \\\n--session-arg \"validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'\" \\\n--session-arg \"amount:u512='100000000000'\" \\\n--session-arg \"delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'\"\n")),(0,r.kt)("p",null,"Next, ",(0,r.kt)("a",{parentName:"p",href:"#verifying-the-undelegation"},"confirm the undelegation"),"."),(0,r.kt)("h2",{id:"verifying-the-undelegation"},"Verifying the Undelegation"),(0,r.kt)("p",null,"To verify that the undelegation succeeded, you can use the Casper command-line client to generate an RPC request to query the auction state. The subsequent RPC response will confirm that the undelegation request was successfully processed."),(0,r.kt)("p",null,"Here is how you can check the status of the auction to confirm that your bid was withdrawn:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info \\\n--node-address http://:7777\n")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Request fields"),":"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network")),(0,r.kt)("p",null,"If the public key and the amount are absent from the ",(0,r.kt)("inlineCode",{parentName:"p"},"bids")," structure, we can safely conclude that we have indeed undelegated from the validator."),(0,r.kt)("p",null,"If your account is on the official Testnet or Mainnet, you can use the block explorer to look up your account balance and see that the tokens have been added to your balance:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"https://testnet.cspr.live/"},"Testnet explorer")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"https://cspr.live/"},"Mainnet explorer"))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Important Note"),": After undelegating tokens from a validator, you must wait for the unbonding period to lapse before redelegating tokens to either the same validator or a different validator."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c5563497.290bd4c4.js b/assets/js/c5563497.290bd4c4.js deleted file mode 100644 index 69225e6223..0000000000 --- a/assets/js/c5563497.290bd4c4.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2894],{3905:function(e,t,r){r.d(t,{Zo:function(){return c},kt:function(){return h}});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function s(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=a.createContext({}),p=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=p(r),m=n,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return r?a.createElement(h,s(s({ref:t},c),{},{components:r})):a.createElement(h,s({ref:t},c))}));function h(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[d]="string"==typeof e?e:n,s[1]=i;for(var p=2;p=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=a.createContext({}),p=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=p(r),m=n,h=d["".concat(l,".").concat(m)]||d[m]||u[m]||o;return r?a.createElement(h,s(s({ref:t},c),{},{components:r})):a.createElement(h,s({ref:t},c))}));function h(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[d]="string"==typeof e?e:n,s[1]=i;for(var p=2;p=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=a.createContext({}),l=function(e){var t=a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,i=p(e,["components","mdxType","originalType","parentName"]),u=l(r),d=n,y=u["".concat(c,".").concat(d)]||u[d]||f[d]||o;return r?a.createElement(y,s(s({ref:t},i),{},{components:r})):a.createElement(y,s({ref:t},i))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=d;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[u]="string"==typeof e?e:n,s[1]=p;for(var l=2;l=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var c=a.createContext({}),l=function(e){var t=a.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,c=e.parentName,i=p(e,["components","mdxType","originalType","parentName"]),u=l(r),d=n,y=u["".concat(c,".").concat(d)]||u[d]||f[d]||o;return r?a.createElement(y,s(s({ref:t},i),{},{components:r})):a.createElement(y,s({ref:t},i))}));function y(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,s=new Array(o);s[0]=d;var p={};for(var c in t)hasOwnProperty.call(t,c)&&(p[c]=t[c]);p.originalType=e,p[u]="string"==typeof e?e:n,s[1]=p;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,g=u["".concat(c,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(g,l(l({ref:t},p),{},{components:n})):r.createElement(g,l({ref:t},p))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:a,l[1]=i;for(var s=2;s=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=s(n),m=a,g=u["".concat(c,".").concat(m)]||u[m]||d[m]||o;return n?r.createElement(g,l(l({ref:t},p),{},{components:n})):r.createElement(g,l({ref:t},p))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=m;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:a,l[1]=i;for(var s=2;s=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var p=a.createContext({}),i=function(e){var t=a.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},l=function(e){var t=i(e.components);return a.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=i(r),h=n,m=u["".concat(p,".").concat(h)]||u[h]||f[h]||o;return r?a.createElement(m,c(c({ref:t},l),{},{components:r})):a.createElement(m,c({ref:t},l))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:n,c[1]=s;for(var i=2;i=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var p=a.createContext({}),i=function(e){var t=a.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},l=function(e){var t=i(e.components);return a.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=i(r),h=n,m=u["".concat(p,".").concat(h)]||u[h]||f[h]||o;return r?a.createElement(m,c(c({ref:t},l),{},{components:r})):a.createElement(m,c({ref:t},l))}));function m(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,c=new Array(o);c[0]=h;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:n,c[1]=s;for(var i=2;i=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var c=i.createContext({}),l=function(e){var t=i.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},h=function(e){var t=l(e.components);return i.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var a=e.components,n=e.mdxType,r=e.originalType,c=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),d=l(a),u=n,f=d["".concat(c,".").concat(u)]||d[u]||p[u]||r;return a?i.createElement(f,o(o({ref:t},h),{},{components:a})):i.createElement(f,o({ref:t},h))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=a.length,o=new Array(r);o[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:n,o[1]=s;for(var l=2;l=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var c=i.createContext({}),l=function(e){var t=i.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},h=function(e){var t=l(e.components);return i.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var a=e.components,n=e.mdxType,r=e.originalType,c=e.parentName,h=s(e,["components","mdxType","originalType","parentName"]),d=l(a),u=n,f=d["".concat(c,".").concat(u)]||d[u]||p[u]||r;return a?i.createElement(f,o(o({ref:t},h),{},{components:a})):i.createElement(f,o({ref:t},h))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var r=a.length,o=new Array(r);o[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:n,o[1]=s;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),c=u(r),g=a,m=c["".concat(s,".").concat(g)]||c[g]||d[g]||l;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=r.length,i=new Array(l);i[0]=g;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:a,i[1]=o;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),c=u(r),g=a,m=c["".concat(s,".").concat(g)]||c[g]||d[g]||l;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=r.length,i=new Array(l);i[0]=g;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:a,i[1]=o;for(var u=2;u=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var m=n.createContext({}),s=function(t){var e=n.useContext(m),a=e;return t&&(a="function"==typeof t?t(e):i(i({},e),t)),a},p=function(t){var e=s(t.components);return n.createElement(m.Provider,{value:e},t.children)},d="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},k=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,l=t.originalType,m=t.parentName,p=o(t,["components","mdxType","originalType","parentName"]),d=s(a),k=r,g=d["".concat(m,".").concat(k)]||d[k]||u[k]||l;return a?n.createElement(g,i(i({ref:e},p),{},{components:a})):n.createElement(g,i({ref:e},p))}));function g(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=a.length,i=new Array(l);i[0]=k;var o={};for(var m in e)hasOwnProperty.call(e,m)&&(o[m]=e[m]);o.originalType=t,o[d]="string"==typeof t?t:r,i[1]=o;for(var s=2;s 50% + F/2 \u2014 see the ",(0,l.kt)("inlineCode",{parentName:"td"},"finality_threshold_fraction")," below) of validator nodes must be running to start the blockchain. This timestamp is also used in seeding the pseudo-random number generator used in the contract runtime for computing the genesis post-state hash. ",(0,l.kt)("br",null),(0,l.kt)("br",null),"If it is an integer, it represents an era ID, meaning the protocol version becomes active at the start of this era."),(0,l.kt)("td",{parentName:"tr",align:null},"9100")))),(0,l.kt)("h2",{id:"network"},"network"),(0,l.kt)("p",null,"The following settings configure the networking layer."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"name"),(0,l.kt)("td",{parentName:"tr",align:null},"Human readable network name for convenience. The state_root_hash of the genesis block is the true identifier. The name influences the genesis hash by contributing to seeding the pseudo-random number generator used in the contract runtime for computing the genesis post-state hash."),(0,l.kt)("td",{parentName:"tr",align:null},"'casper'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"maximum_net_message_size"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum size of an acceptable networking message in bytes. Any message larger than this will be rejected at the networking level."),(0,l.kt)("td",{parentName:"tr",align:null},"25_165_824")))),(0,l.kt)("h2",{id:"core"},"core"),(0,l.kt)("p",null,"These settings manage the core protocol behavior."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"era_duration"),(0,l.kt)("td",{parentName:"tr",align:null},"Era duration."),(0,l.kt)("td",{parentName:"tr",align:null},"'120min'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"minimum_era_height"),(0,l.kt)("td",{parentName:"tr",align:null},"Minimum number of blocks per era. An era will take longer than ",(0,l.kt)("inlineCode",{parentName:"td"},"era_duration")," if that is necessary to reach the minimum height."),(0,l.kt)("td",{parentName:"tr",align:null},"20")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"minimum_block_time"),(0,l.kt)("td",{parentName:"tr",align:null},"Minimum difference between a block's and its child's timestamp."),(0,l.kt)("td",{parentName:"tr",align:null},"'16384ms'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"validator_slots"),(0,l.kt)("td",{parentName:"tr",align:null},"Number of slots available in the validator auction."),(0,l.kt)("td",{parentName:"tr",align:null},"100")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"finality_threshold_fraction"),(0,l.kt)("td",{parentName:"tr",align:null},"A number between 0 and 1 representing the fault tolerance threshold as a fraction used by the internal finalizer.",(0,l.kt)("br",null),"It is the fraction of validators that would need to equivocate to make two honest nodes see two conflicting blocks as finalized.",(0,l.kt)("br",null),"Let's say this value is F. A higher value F makes it safer to rely on finalized blocks. It also makes it more difficult to finalize blocks, however, and requires strictly more than (F + 1)/2 validators to be working correctly."),(0,l.kt)("td",{parentName:"tr",align:null},"[1, 3]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"start_protocol_version_with_strict",(0,l.kt)("br",null),"_","finality_signatures_required"),(0,l.kt)("td",{parentName:"tr",align:null},"Protocol version from which nodes are required to hold strict finality signatures."),(0,l.kt)("td",{parentName:"tr",align:null},"'1.5.0'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"legacy_required_finality"),(0,l.kt)("td",{parentName:"tr",align:null},"The finality required for legacy blocks. Options are 'Strict', 'Weak', and 'Any'. ",(0,l.kt)("br",null),"Used to determine finality sufficiency for new joiners syncing blocks created in a protocol version before the start protocol version with strict finality signatures."),(0,l.kt)("td",{parentName:"tr",align:null},"'Strict'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"auction_delay"),(0,l.kt)("td",{parentName:"tr",align:null},"Number of eras before an auction defines the set of validators. If a validator bonds with a sufficient bid in era N, it will be a validator in era N + auction_delay + 1."),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"locked_funds_period"),(0,l.kt)("td",{parentName:"tr",align:null},"The period after genesis during which a genesis validator's bid is locked."),(0,l.kt)("td",{parentName:"tr",align:null},"'90days'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"vesting_schedule_period"),(0,l.kt)("td",{parentName:"tr",align:null},"The period in which the genesis validator's bid is released over time after it is unlocked."),(0,l.kt)("td",{parentName:"tr",align:null},"'13 weeks'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"unbonding_delay"),(0,l.kt)("td",{parentName:"tr",align:null},"Default number of eras that need to pass to be able to withdraw unbonded funds."),(0,l.kt)("td",{parentName:"tr",align:null},"7")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"round_seigniorage_rate"),(0,l.kt)("td",{parentName:"tr",align:null},"Round seigniorage rate represented as a fraction of the total supply.",(0,l.kt)("br",null),"- Annual issuance: 8%.",(0,l.kt)("br",null),"- Minimum block time: 2^15 milliseconds.",(0,l.kt)("br",null),"- Ticks per year: 31536000000.",(0,l.kt)("br",null),(0,l.kt)("br",null),"(1+0.08)^((2^15)/31536000000)-1 is expressed as a fractional number below in Python:",(0,l.kt)("br",null),(0,l.kt)("inlineCode",{parentName:"td"},"Fraction((1 + 0.08)**((2**15)/31536000000) - 1).limit_denominator(1000000000)")),(0,l.kt)("td",{parentName:"tr",align:null},"[7, 87535408]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_associated_keys"),(0,l.kt)("td",{parentName:"tr",align:null},"Maximum number of associated keys for a single account."),(0,l.kt)("td",{parentName:"tr",align:null},"100")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_runtime_call_stack_height"),(0,l.kt)("td",{parentName:"tr",align:null},"Maximum height of the contract runtime call stack."),(0,l.kt)("td",{parentName:"tr",align:null},"12")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"minimum_delegation_amount"),(0,l.kt)("td",{parentName:"tr",align:null},"Minimum allowed delegation amount in motes."),(0,l.kt)("td",{parentName:"tr",align:null},"500_000_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"prune_batch_size"),(0,l.kt)("td",{parentName:"tr",align:null},"Global state prune batch size for tip pruning in version 1.4.15. Possible values:",(0,l.kt)("br",null),"- 0 when the feature is OFF",(0,l.kt)("br",null),"- Integer if the feature is ON, representing the number of eras to process per block."),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"strict_argument_checking"),(0,l.kt)("td",{parentName:"tr",align:null},"Enables strict arguments checking when calling a contract; i.e., all non-optional args are provided and they are of the correct ",(0,l.kt)("inlineCode",{parentName:"td"},"CLType"),"."),(0,l.kt)("td",{parentName:"tr",align:null},"false")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"simultaneous_peer_requests"),(0,l.kt)("td",{parentName:"tr",align:null},"Number of simultaneous peer requests."),(0,l.kt)("td",{parentName:"tr",align:null},"5")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"consensus_protocol"),(0,l.kt)("td",{parentName:"tr",align:null},"The consensus protocol to use. Options are 'Zug' or 'Highway'."),(0,l.kt)("td",{parentName:"tr",align:null},"'Highway'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_delegators_per_validator"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum amount of delegators per validator. If the value is 0, there is no maximum capacity."),(0,l.kt)("td",{parentName:"tr",align:null},"1200")))),(0,l.kt)("h2",{id:"highway"},"highway"),(0,l.kt)("p",null,"These settings configure the Highway Consensus protocol."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"maximum_round_length"),(0,l.kt)("td",{parentName:"tr",align:null},"Highway dynamically chooses its round length between ",(0,l.kt)("inlineCode",{parentName:"td"},"minimum_block_time")," and ",(0,l.kt)("inlineCode",{parentName:"td"},"maximum_round_length"),"."),(0,l.kt)("td",{parentName:"tr",align:null},"'132seconds'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"reduced_reward_multiplier"),(0,l.kt)("td",{parentName:"tr",align:null},"The factor by which rewards for a round are multiplied if the greatest summit has \u226450% quorum, i.e., no finality. Expressed as a fraction (1/5 by default on Mainnet)."),(0,l.kt)("td",{parentName:"tr",align:null},"[1, 5]")))),(0,l.kt)("h2",{id:"deploys"},"deploys"),(0,l.kt)("p",null,"These settings manage deploys and their lifecycle."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_payment_cost"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of motes allowed to be spent during payment. 0 means unlimited."),(0,l.kt)("td",{parentName:"tr",align:null},"'0'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_ttl"),(0,l.kt)("td",{parentName:"tr",align:null},"The duration after the deploy timestamp during which the deploy can be included in a block."),(0,l.kt)("td",{parentName:"tr",align:null},"'18hours'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_dependencies"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of other deploys a deploy can depend on (requiring them to have been executed before it can execute)."),(0,l.kt)("td",{parentName:"tr",align:null},"10")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_block_size"),(0,l.kt)("td",{parentName:"tr",align:null},"Maximum block size in bytes, including deploys contained by the block. 0 means unlimited."),(0,l.kt)("td",{parentName:"tr",align:null},"10_485_760")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_deploy_size"),(0,l.kt)("td",{parentName:"tr",align:null},"Maximum deploy size in bytes. Size is of the deploy when serialized via ToBytes."),(0,l.kt)("td",{parentName:"tr",align:null},"1_048_576")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block_max_deploy_count"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of non-transfer deploys permitted in a single block."),(0,l.kt)("td",{parentName:"tr",align:null},"50")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block_max_transfer_count"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of Wasm-less transfer deploys permitted in a single block."),(0,l.kt)("td",{parentName:"tr",align:null},"1250")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block_max_approval_count"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of approvals permitted in a single block."),(0,l.kt)("td",{parentName:"tr",align:null},"2600")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block_gas_limit"),(0,l.kt)("td",{parentName:"tr",align:null},"The upper limit of the total gas of all deploys in a block."),(0,l.kt)("td",{parentName:"tr",align:null},"4_000_000_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"payment_args_max_length"),(0,l.kt)("td",{parentName:"tr",align:null},"The limit of length of serialized payment code arguments."),(0,l.kt)("td",{parentName:"tr",align:null},"1024")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"session_args_max_length"),(0,l.kt)("td",{parentName:"tr",align:null},"The limit of length of serialized session code arguments."),(0,l.kt)("td",{parentName:"tr",align:null},"1024")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"native_transfer_minimum_motes"),(0,l.kt)("td",{parentName:"tr",align:null},"The minimum amount in motes for a valid native transfer."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")))),(0,l.kt)("h2",{id:"wasm"},"wasm"),(0,l.kt)("p",null,"The following are Wasm-related settings."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Amount of free memory (in 64 kB pages) each contract can use for its stack."),(0,l.kt)("td",{parentName:"tr",align:null},"64")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_stack_height"),(0,l.kt)("td",{parentName:"tr",align:null},"Max stack height (native WebAssembly stack limiter)."),(0,l.kt)("td",{parentName:"tr",align:null},"500")))),(0,l.kt)("h3",{id:"wasmstorage_costs"},"wasm.storage_costs"),(0,l.kt)("p",null,"These settings manage Wasm storage costs."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"gas_per_byte"),(0,l.kt)("td",{parentName:"tr",align:null},"Gas charged per byte stored in global state."),(0,l.kt)("td",{parentName:"tr",align:null},"630_000")))),(0,l.kt)("h3",{id:"wasmopcode_costs"},"wasm.opcode_costs"),(0,l.kt)("p",null,"The following settings manage the cost table for Wasm opcodes."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"bit"),(0,l.kt)("td",{parentName:"tr",align:null},"Bit operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"300")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add"),(0,l.kt)("td",{parentName:"tr",align:null},"Arithmetic add operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"210")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mul"),(0,l.kt)("td",{parentName:"tr",align:null},"Mul operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"240")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"div"),(0,l.kt)("td",{parentName:"tr",align:null},"Div operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"320")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"load"),(0,l.kt)("td",{parentName:"tr",align:null},"Memory load operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"store"),(0,l.kt)("td",{parentName:"tr",align:null},"Memory store operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"4_700")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"const"),(0,l.kt)("td",{parentName:"tr",align:null},"Const store operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"110")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"local"),(0,l.kt)("td",{parentName:"tr",align:null},"Local operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"390")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"global"),(0,l.kt)("td",{parentName:"tr",align:null},"Global operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"390")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"integer_comparison"),(0,l.kt)("td",{parentName:"tr",align:null},"Integer operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"250")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"conversion"),(0,l.kt)("td",{parentName:"tr",align:null},"Conversion operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"420")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"unreachable"),(0,l.kt)("td",{parentName:"tr",align:null},"Unreachable operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"270")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"nop"),(0,l.kt)("td",{parentName:"tr",align:null},"Nop operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"200")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"current_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Get the current memory operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"290")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"grow_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Grow memory cost per page (64 kB)."),(0,l.kt)("td",{parentName:"tr",align:null},"240_000")))),(0,l.kt)("h3",{id:"wasmopcode_costscontrol_flow"},"wasm.opcode_costs.control_flow"),(0,l.kt)("p",null,"These settings manage costs for control flow operations."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"block")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"loop"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"loop")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"if"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"if")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"else"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"else")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"end"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"end")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"br"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"br")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"br_if"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"br_if")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"return"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"return")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"select"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"select")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"call")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"68_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call_indirect"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"call_indirect")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"68_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"drop"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"drop")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")))),(0,l.kt)("h3",{id:"wasmopcode_costscontrol_flowbr_table"},"wasm.opcode_costs.control_flow.br_table"),(0,l.kt)("p",null,"The following settings manage ",(0,l.kt)("inlineCode",{parentName:"p"},"br_table")," Wasm opcodes."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"cost"),(0,l.kt)("td",{parentName:"tr",align:null},"Fixed cost per ",(0,l.kt)("inlineCode",{parentName:"td"},"br_table")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"size_multiplier"),(0,l.kt)("td",{parentName:"tr",align:null},"Size of target labels in the ",(0,l.kt)("inlineCode",{parentName:"td"},"br_table")," opcode will be multiplied by ",(0,l.kt)("inlineCode",{parentName:"td"},"size_multiplier"),"."),(0,l.kt)("td",{parentName:"tr",align:null},"100")))),(0,l.kt)("h3",{id:"wasmhost_function_costs"},"wasm.host_function_costs"),(0,l.kt)("p",null,'The following settings specify costs for low-level bindings for host-side ("external") functions. More documentation and host function declarations are located in ',(0,l.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.5.2/smart_contracts/contract/src/ext_ffi.rs"},"smart_contracts/contract/src/ext_ffi.rs"),"."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"add = { cost = 5_800, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"add_associated_key = { cost = 9_000, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"add_contract_version = { cost = 200, arguments = ","[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"blake2b = { cost = 200, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"call_contract = { cost = 4_500, arguments = ","[0, 0, 0, 0, 0, 420, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"call_versioned_contract = { cost = 4_500, arguments = ","[0, 0, 0, 0, 0, 0, 0, 420, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"create_contract_package_at_hash = { cost = 200, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"create_contract_user_group = { cost = 200, arguments = ","[0, 0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"create_purse = { cost = 2_500_000_000, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"disable_contract_version = { cost = 200, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_balance = { cost = 3_800, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_blocktime = { cost = 330, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_caller = { cost = 380, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_key = { cost = 2_000, arguments = ","[0, 440, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_main_purse = { cost = 1_300, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_named_arg = { cost = 200, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_named_arg_size = { cost = 200, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_phase = { cost = 710, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_system_contract = { cost = 1_100, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"has_key = { cost = 1_500, arguments = ","[0, 840]"," }"),(0,l.kt)("li",{parentName:"ul"},"is_valid_uref = { cost = 760, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"load_named_keys = { cost = 42_000, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"new_uref = { cost = 17_000, arguments = ","[0, 0, 590]"," }"),(0,l.kt)("li",{parentName:"ul"},"random_bytes = { cost = 200, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"print = { cost = 20_000, arguments = ","[0, 4_600]"," }"),(0,l.kt)("li",{parentName:"ul"},"provision_contract_user_group_uref = { cost = 200, arguments = ","[0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"put_key = { cost = 38_000, arguments = ","[0, 1_100, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"read_host_buffer = { cost = 3_500, arguments = ","[0, 310, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"read_value = { cost = 6_000, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"read_value_local = { cost = 5_500, arguments = ","[0, 590, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"remove_associated_key = { cost = 4_200, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"remove_contract_user_group = { cost = 200, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"remove_contract_user_group_urefs = { cost = 200, arguments = ","[0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"remove_key = { cost = 61_000, arguments = ","[0, 3_200]"," }"),(0,l.kt)("li",{parentName:"ul"},"ret = { cost = 23_000, arguments = ","[0, 420_000]"," }"),(0,l.kt)("li",{parentName:"ul"},"revert = { cost = 500, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"set_action_threshold = { cost = 74_000, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"transfer_from_purse_to_account = { cost = 2_500_000_000, arguments = ","[0, 0, 0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"transfer_from_purse_to_purse = { cost = 82_000, arguments = ","[0, 0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"transfer_to_account = { cost = 2_500_000_000, arguments = ","[0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"update_associated_key = { cost = 4_200, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"write = { cost = 14_000, arguments = ","[0, 0, 0, 980]"," }"),(0,l.kt)("li",{parentName:"ul"},"write_local = { cost = 9_500, arguments = ","[0, 1_800, 0, 520]"," }")),(0,l.kt)("h2",{id:"system_costs"},"system_costs"),(0,l.kt)("p",null,"The following settings manage protocol operating costs."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"wasmless_transfer_cost"),(0,l.kt)("td",{parentName:"tr",align:null},"Default gas cost for a wasmless transfer."),(0,l.kt)("td",{parentName:"tr",align:null},"100_000_000")))),(0,l.kt)("h3",{id:"system_costsauction_costs"},"system_costs.auction_costs"),(0,l.kt)("p",null,"These settings manage the costs of calling the ",(0,l.kt)("inlineCode",{parentName:"p"},"auction")," system contract entrypoints."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_era_validators"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_era_validators")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_seigniorage_recipients"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_seigniorage_recipients")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"add_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"delegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"delegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"undelegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"undelegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"run_auction"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"run_auction")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"slash"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"slash")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"distribute"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"distribute")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_delegator_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_delegator_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_validator_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_validator_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_era_id"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_era_id")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"activate_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"activate_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"redelegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"redelegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")))),(0,l.kt)("h3",{id:"system_costsmint_costs"},"system_costs.mint_costs"),(0,l.kt)("p",null,"These settings manage the costs of calling the ",(0,l.kt)("inlineCode",{parentName:"p"},"mint")," system contract entrypoints."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mint"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"mint")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"reduce_total_supply"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"reduce_total_supply")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"create")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"balance"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"balance")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"transfer")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_base_round_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_base_round_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mint_into_existing_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"mint_into_existing_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")))),(0,l.kt)("h3",{id:"system_costshandle_payment_costs"},"system_costs.handle_payment_costs"),(0,l.kt)("p",null,"These settings manage the costs of calling entrypoints on the ",(0,l.kt)("inlineCode",{parentName:"p"},"handle_payment")," system contract."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_payment_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_payment_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"set_refund_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"set_refund_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_refund_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_refund_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"finalize_payment"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"finalize_payment")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")))),(0,l.kt)("h3",{id:"system_costsstandard_payment_costs"},"system_costs.standard_payment_costs"),(0,l.kt)("p",null,"These settings manage the costs of calling entrypoints on the ",(0,l.kt)("inlineCode",{parentName:"p"},"standard_payment")," system contract."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"pay"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"pay")," entrypoint and sending an amount to a payment purse."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d044d178.cdb51ab3.js b/assets/js/d044d178.cdb51ab3.js new file mode 100644 index 0000000000..613fcf74db --- /dev/null +++ b/assets/js/d044d178.cdb51ab3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[2273],{3905:function(t,e,a){a.d(e,{Zo:function(){return p},kt:function(){return g}});var n=a(7294);function r(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function l(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function i(t){for(var e=1;e=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var m=n.createContext({}),s=function(t){var e=n.useContext(m),a=e;return t&&(a="function"==typeof t?t(e):i(i({},e),t)),a},p=function(t){var e=s(t.components);return n.createElement(m.Provider,{value:e},t.children)},d="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},k=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,l=t.originalType,m=t.parentName,p=o(t,["components","mdxType","originalType","parentName"]),d=s(a),k=r,g=d["".concat(m,".").concat(k)]||d[k]||u[k]||l;return a?n.createElement(g,i(i({ref:e},p),{},{components:a})):n.createElement(g,i({ref:e},p))}));function g(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=a.length,i=new Array(l);i[0]=k;var o={};for(var m in e)hasOwnProperty.call(e,m)&&(o[m]=e[m]);o.originalType=t,o[d]="string"==typeof t?t:r,i[1]=o;for(var s=2;s 50% + F/2 \u2014 see the ",(0,l.kt)("inlineCode",{parentName:"td"},"finality_threshold_fraction")," below) of validator nodes must be running to start the blockchain. This timestamp is also used in seeding the pseudo-random number generator used in the contract runtime for computing the genesis post-state hash. ",(0,l.kt)("br",null),(0,l.kt)("br",null),"If it is an integer, it represents an era ID, meaning the protocol version becomes active at the start of this era."),(0,l.kt)("td",{parentName:"tr",align:null},"9100")))),(0,l.kt)("h2",{id:"network"},"network"),(0,l.kt)("p",null,"The following settings configure the networking layer."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"name"),(0,l.kt)("td",{parentName:"tr",align:null},"Human readable network name for convenience. The state_root_hash of the genesis block is the true identifier. The name influences the genesis hash by contributing to seeding the pseudo-random number generator used in the contract runtime for computing the genesis post-state hash."),(0,l.kt)("td",{parentName:"tr",align:null},"'casper'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"maximum_net_message_size"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum size of an acceptable networking message in bytes. Any message larger than this will be rejected at the networking level."),(0,l.kt)("td",{parentName:"tr",align:null},"25_165_824")))),(0,l.kt)("h2",{id:"core"},"core"),(0,l.kt)("p",null,"These settings manage the core protocol behavior."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"era_duration"),(0,l.kt)("td",{parentName:"tr",align:null},"Era duration."),(0,l.kt)("td",{parentName:"tr",align:null},"'120min'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"minimum_era_height"),(0,l.kt)("td",{parentName:"tr",align:null},"Minimum number of blocks per era. An era will take longer than ",(0,l.kt)("inlineCode",{parentName:"td"},"era_duration")," if that is necessary to reach the minimum height."),(0,l.kt)("td",{parentName:"tr",align:null},"20")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"minimum_block_time"),(0,l.kt)("td",{parentName:"tr",align:null},"Minimum difference between a block's and its child's timestamp."),(0,l.kt)("td",{parentName:"tr",align:null},"'16384ms'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"validator_slots"),(0,l.kt)("td",{parentName:"tr",align:null},"Number of slots available in the validator auction."),(0,l.kt)("td",{parentName:"tr",align:null},"100")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"finality_threshold_fraction"),(0,l.kt)("td",{parentName:"tr",align:null},"A number between 0 and 1 representing the fault tolerance threshold as a fraction used by the internal finalizer.",(0,l.kt)("br",null),"It is the fraction of validators that would need to equivocate to make two honest nodes see two conflicting blocks as finalized.",(0,l.kt)("br",null),"Let's say this value is F. A higher value F makes it safer to rely on finalized blocks. It also makes it more difficult to finalize blocks, however, and requires strictly more than (F + 1)/2 validators to be working correctly."),(0,l.kt)("td",{parentName:"tr",align:null},"[1, 3]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"start_protocol_version_with_strict",(0,l.kt)("br",null),"_","finality_signatures_required"),(0,l.kt)("td",{parentName:"tr",align:null},"Protocol version from which nodes are required to hold strict finality signatures."),(0,l.kt)("td",{parentName:"tr",align:null},"'1.5.0'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"legacy_required_finality"),(0,l.kt)("td",{parentName:"tr",align:null},"The finality required for legacy blocks. Options are 'Strict', 'Weak', and 'Any'. ",(0,l.kt)("br",null),"Used to determine finality sufficiency for new joiners syncing blocks created in a protocol version before the start protocol version with strict finality signatures."),(0,l.kt)("td",{parentName:"tr",align:null},"'Strict'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"auction_delay"),(0,l.kt)("td",{parentName:"tr",align:null},"Number of eras before an auction defines the set of validators. If a validator bonds with a sufficient bid in era N, it will be a validator in era N + auction_delay + 1."),(0,l.kt)("td",{parentName:"tr",align:null},"1")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"locked_funds_period"),(0,l.kt)("td",{parentName:"tr",align:null},"The period after genesis during which a genesis validator's bid is locked."),(0,l.kt)("td",{parentName:"tr",align:null},"'90days'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"vesting_schedule_period"),(0,l.kt)("td",{parentName:"tr",align:null},"The period in which the genesis validator's bid is released over time after it is unlocked."),(0,l.kt)("td",{parentName:"tr",align:null},"'13 weeks'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"unbonding_delay"),(0,l.kt)("td",{parentName:"tr",align:null},"Default number of eras that need to pass to be able to withdraw unbonded funds."),(0,l.kt)("td",{parentName:"tr",align:null},"7")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"round_seigniorage_rate"),(0,l.kt)("td",{parentName:"tr",align:null},"Round seigniorage rate represented as a fraction of the total supply.",(0,l.kt)("br",null),"- Annual issuance: 8%.",(0,l.kt)("br",null),"- Minimum block time: 2^15 milliseconds.",(0,l.kt)("br",null),"- Ticks per year: 31536000000.",(0,l.kt)("br",null),(0,l.kt)("br",null),"(1+0.08)^((2^15)/31536000000)-1 is expressed as a fractional number below in Python:",(0,l.kt)("br",null),(0,l.kt)("inlineCode",{parentName:"td"},"Fraction((1 + 0.08)**((2**15)/31536000000) - 1).limit_denominator(1000000000)")),(0,l.kt)("td",{parentName:"tr",align:null},"[7, 87535408]")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_associated_keys"),(0,l.kt)("td",{parentName:"tr",align:null},"Maximum number of associated keys for a single account."),(0,l.kt)("td",{parentName:"tr",align:null},"100")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_runtime_call_stack_height"),(0,l.kt)("td",{parentName:"tr",align:null},"Maximum height of the contract runtime call stack."),(0,l.kt)("td",{parentName:"tr",align:null},"12")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"minimum_delegation_amount"),(0,l.kt)("td",{parentName:"tr",align:null},"Minimum allowed delegation amount in motes."),(0,l.kt)("td",{parentName:"tr",align:null},"500_000_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"prune_batch_size"),(0,l.kt)("td",{parentName:"tr",align:null},"Global state prune batch size for tip pruning in version 1.4.15. Possible values:",(0,l.kt)("br",null),"- 0 when the feature is OFF",(0,l.kt)("br",null),"- Integer if the feature is ON, representing the number of eras to process per block."),(0,l.kt)("td",{parentName:"tr",align:null},"0")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"strict_argument_checking"),(0,l.kt)("td",{parentName:"tr",align:null},"Enables strict arguments checking when calling a contract; i.e., all non-optional args are provided and they are of the correct ",(0,l.kt)("inlineCode",{parentName:"td"},"CLType"),"."),(0,l.kt)("td",{parentName:"tr",align:null},"false")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"simultaneous_peer_requests"),(0,l.kt)("td",{parentName:"tr",align:null},"Number of simultaneous peer requests."),(0,l.kt)("td",{parentName:"tr",align:null},"5")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"consensus_protocol"),(0,l.kt)("td",{parentName:"tr",align:null},"The consensus protocol to use. Options are 'Zug' or 'Highway'."),(0,l.kt)("td",{parentName:"tr",align:null},"'Highway'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_delegators_per_validator"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum amount of delegators per validator. If the value is 0, there is no maximum capacity."),(0,l.kt)("td",{parentName:"tr",align:null},"1200")))),(0,l.kt)("h2",{id:"highway"},"highway"),(0,l.kt)("p",null,"These settings configure the Highway Consensus protocol."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"maximum_round_length"),(0,l.kt)("td",{parentName:"tr",align:null},"Highway dynamically chooses its round length between ",(0,l.kt)("inlineCode",{parentName:"td"},"minimum_block_time")," and ",(0,l.kt)("inlineCode",{parentName:"td"},"maximum_round_length"),"."),(0,l.kt)("td",{parentName:"tr",align:null},"'132seconds'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"reduced_reward_multiplier"),(0,l.kt)("td",{parentName:"tr",align:null},"The factor by which rewards for a round are multiplied if the greatest summit has \u226450% quorum, i.e., no finality. Expressed as a fraction (1/5 by default on Mainnet)."),(0,l.kt)("td",{parentName:"tr",align:null},"[1, 5]")))),(0,l.kt)("h2",{id:"deploys"},"deploys"),(0,l.kt)("p",null,"These settings manage deploys and their lifecycle."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_payment_cost"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of motes allowed to be spent during payment. 0 means unlimited."),(0,l.kt)("td",{parentName:"tr",align:null},"'0'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_ttl"),(0,l.kt)("td",{parentName:"tr",align:null},"The duration after the deploy timestamp during which the deploy can be included in a block."),(0,l.kt)("td",{parentName:"tr",align:null},"'18hours'")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_dependencies"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of other deploys a deploy can depend on (requiring them to have been executed before it can execute)."),(0,l.kt)("td",{parentName:"tr",align:null},"10")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_block_size"),(0,l.kt)("td",{parentName:"tr",align:null},"Maximum block size in bytes, including deploys contained by the block. 0 means unlimited."),(0,l.kt)("td",{parentName:"tr",align:null},"10_485_760")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_deploy_size"),(0,l.kt)("td",{parentName:"tr",align:null},"Maximum deploy size in bytes. Size is of the deploy when serialized via ToBytes."),(0,l.kt)("td",{parentName:"tr",align:null},"1_048_576")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block_max_deploy_count"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of non-transfer deploys permitted in a single block."),(0,l.kt)("td",{parentName:"tr",align:null},"50")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block_max_transfer_count"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of Wasm-less transfer deploys permitted in a single block."),(0,l.kt)("td",{parentName:"tr",align:null},"1250")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block_max_approval_count"),(0,l.kt)("td",{parentName:"tr",align:null},"The maximum number of approvals permitted in a single block."),(0,l.kt)("td",{parentName:"tr",align:null},"2600")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block_gas_limit"),(0,l.kt)("td",{parentName:"tr",align:null},"The upper limit of the total gas of all deploys in a block."),(0,l.kt)("td",{parentName:"tr",align:null},"4_000_000_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"payment_args_max_length"),(0,l.kt)("td",{parentName:"tr",align:null},"The limit of length of serialized payment code arguments."),(0,l.kt)("td",{parentName:"tr",align:null},"1024")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"session_args_max_length"),(0,l.kt)("td",{parentName:"tr",align:null},"The limit of length of serialized session code arguments."),(0,l.kt)("td",{parentName:"tr",align:null},"1024")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"native_transfer_minimum_motes"),(0,l.kt)("td",{parentName:"tr",align:null},"The minimum amount in motes for a valid native transfer."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")))),(0,l.kt)("h2",{id:"wasm"},"wasm"),(0,l.kt)("p",null,"The following are Wasm-related settings."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Amount of free memory (in 64 kB pages) each contract can use for its stack."),(0,l.kt)("td",{parentName:"tr",align:null},"64")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"max_stack_height"),(0,l.kt)("td",{parentName:"tr",align:null},"Max stack height (native WebAssembly stack limiter)."),(0,l.kt)("td",{parentName:"tr",align:null},"500")))),(0,l.kt)("h3",{id:"wasmstorage_costs"},"wasm.storage_costs"),(0,l.kt)("p",null,"These settings manage Wasm storage costs."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"gas_per_byte"),(0,l.kt)("td",{parentName:"tr",align:null},"Gas charged per byte stored in global state."),(0,l.kt)("td",{parentName:"tr",align:null},"630_000")))),(0,l.kt)("h3",{id:"wasmopcode_costs"},"wasm.opcode_costs"),(0,l.kt)("p",null,"The following settings manage the cost table for Wasm opcodes."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"bit"),(0,l.kt)("td",{parentName:"tr",align:null},"Bit operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"300")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add"),(0,l.kt)("td",{parentName:"tr",align:null},"Arithmetic add operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"210")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mul"),(0,l.kt)("td",{parentName:"tr",align:null},"Mul operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"240")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"div"),(0,l.kt)("td",{parentName:"tr",align:null},"Div operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"320")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"load"),(0,l.kt)("td",{parentName:"tr",align:null},"Memory load operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"store"),(0,l.kt)("td",{parentName:"tr",align:null},"Memory store operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"4_700")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"const"),(0,l.kt)("td",{parentName:"tr",align:null},"Const store operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"110")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"local"),(0,l.kt)("td",{parentName:"tr",align:null},"Local operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"390")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"global"),(0,l.kt)("td",{parentName:"tr",align:null},"Global operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"390")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"integer_comparison"),(0,l.kt)("td",{parentName:"tr",align:null},"Integer operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"250")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"conversion"),(0,l.kt)("td",{parentName:"tr",align:null},"Conversion operations multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"420")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"unreachable"),(0,l.kt)("td",{parentName:"tr",align:null},"Unreachable operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"270")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"nop"),(0,l.kt)("td",{parentName:"tr",align:null},"Nop operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"200")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"current_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Get the current memory operation multiplier."),(0,l.kt)("td",{parentName:"tr",align:null},"290")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"grow_memory"),(0,l.kt)("td",{parentName:"tr",align:null},"Grow memory cost per page (64 kB)."),(0,l.kt)("td",{parentName:"tr",align:null},"240_000")))),(0,l.kt)("h3",{id:"wasmopcode_costscontrol_flow"},"wasm.opcode_costs.control_flow"),(0,l.kt)("p",null,"These settings manage costs for control flow operations."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"block"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"block")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"loop"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"loop")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"if"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"if")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"else"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"else")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"end"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"end")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"br"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"br")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"br_if"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"br_if")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"return"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"return")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"select"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"select")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"call")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"68_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"call_indirect"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"call_indirect")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"68_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"drop"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost for ",(0,l.kt)("inlineCode",{parentName:"td"},"drop")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"440")))),(0,l.kt)("h3",{id:"wasmopcode_costscontrol_flowbr_table"},"wasm.opcode_costs.control_flow.br_table"),(0,l.kt)("p",null,"The following settings manage ",(0,l.kt)("inlineCode",{parentName:"p"},"br_table")," Wasm opcodes."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"cost"),(0,l.kt)("td",{parentName:"tr",align:null},"Fixed cost per ",(0,l.kt)("inlineCode",{parentName:"td"},"br_table")," opcode."),(0,l.kt)("td",{parentName:"tr",align:null},"35_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"size_multiplier"),(0,l.kt)("td",{parentName:"tr",align:null},"Size of target labels in the ",(0,l.kt)("inlineCode",{parentName:"td"},"br_table")," opcode will be multiplied by ",(0,l.kt)("inlineCode",{parentName:"td"},"size_multiplier"),"."),(0,l.kt)("td",{parentName:"tr",align:null},"100")))),(0,l.kt)("h3",{id:"wasmhost_function_costs"},"wasm.host_function_costs"),(0,l.kt)("p",null,'The following settings specify costs for low-level bindings for host-side ("external") functions. More documentation and host function declarations are located in ',(0,l.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/release-1.5.2/smart_contracts/contract/src/ext_ffi.rs"},"smart_contracts/contract/src/ext_ffi.rs"),"."),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"add = { cost = 5_800, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"add_associated_key = { cost = 9_000, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"add_contract_version = { cost = 200, arguments = ","[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"blake2b = { cost = 200, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"call_contract = { cost = 4_500, arguments = ","[0, 0, 0, 0, 0, 420, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"call_versioned_contract = { cost = 4_500, arguments = ","[0, 0, 0, 0, 0, 0, 0, 420, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"create_contract_package_at_hash = { cost = 200, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"create_contract_user_group = { cost = 200, arguments = ","[0, 0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"create_purse = { cost = 2_500_000_000, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"disable_contract_version = { cost = 200, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_balance = { cost = 3_800, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_blocktime = { cost = 330, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_caller = { cost = 380, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_key = { cost = 2_000, arguments = ","[0, 440, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_main_purse = { cost = 1_300, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_named_arg = { cost = 200, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_named_arg_size = { cost = 200, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_phase = { cost = 710, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"get_system_contract = { cost = 1_100, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"has_key = { cost = 1_500, arguments = ","[0, 840]"," }"),(0,l.kt)("li",{parentName:"ul"},"is_valid_uref = { cost = 760, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"load_named_keys = { cost = 42_000, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"new_uref = { cost = 17_000, arguments = ","[0, 0, 590]"," }"),(0,l.kt)("li",{parentName:"ul"},"random_bytes = { cost = 200, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"print = { cost = 20_000, arguments = ","[0, 4_600]"," }"),(0,l.kt)("li",{parentName:"ul"},"provision_contract_user_group_uref = { cost = 200, arguments = ","[0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"put_key = { cost = 38_000, arguments = ","[0, 1_100, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"read_host_buffer = { cost = 3_500, arguments = ","[0, 310, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"read_value = { cost = 6_000, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"read_value_local = { cost = 5_500, arguments = ","[0, 590, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"remove_associated_key = { cost = 4_200, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"remove_contract_user_group = { cost = 200, arguments = ","[0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"remove_contract_user_group_urefs = { cost = 200, arguments = ","[0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"remove_key = { cost = 61_000, arguments = ","[0, 3_200]"," }"),(0,l.kt)("li",{parentName:"ul"},"ret = { cost = 23_000, arguments = ","[0, 420_000]"," }"),(0,l.kt)("li",{parentName:"ul"},"revert = { cost = 500, arguments = ","[0]"," }"),(0,l.kt)("li",{parentName:"ul"},"set_action_threshold = { cost = 74_000, arguments = ","[0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"transfer_from_purse_to_account = { cost = 2_500_000_000, arguments = ","[0, 0, 0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"transfer_from_purse_to_purse = { cost = 82_000, arguments = ","[0, 0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"transfer_to_account = { cost = 2_500_000_000, arguments = ","[0, 0, 0, 0, 0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"update_associated_key = { cost = 4_200, arguments = ","[0, 0, 0]"," }"),(0,l.kt)("li",{parentName:"ul"},"write = { cost = 14_000, arguments = ","[0, 0, 0, 980]"," }"),(0,l.kt)("li",{parentName:"ul"},"write_local = { cost = 9_500, arguments = ","[0, 1_800, 0, 520]"," }")),(0,l.kt)("h2",{id:"system_costs"},"system_costs"),(0,l.kt)("p",null,"The following settings manage protocol operating costs."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"wasmless_transfer_cost"),(0,l.kt)("td",{parentName:"tr",align:null},"Default gas cost for a wasmless transfer."),(0,l.kt)("td",{parentName:"tr",align:null},"100_000_000")))),(0,l.kt)("h3",{id:"system_costsauction_costs"},"system_costs.auction_costs"),(0,l.kt)("p",null,"These settings manage the costs of calling the ",(0,l.kt)("inlineCode",{parentName:"p"},"auction")," system contract entrypoints."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_era_validators"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_era_validators")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_seigniorage_recipients"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_seigniorage_recipients")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"add_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"add_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"delegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"delegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"undelegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"undelegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"run_auction"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"run_auction")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"slash"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"slash")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"distribute"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"distribute")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_delegator_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_delegator_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"withdraw_validator_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"withdraw_validator_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_era_id"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_era_id")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"activate_bid"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"activate_bid")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"redelegate"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"redelegate")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")))),(0,l.kt)("h3",{id:"system_costsmint_costs"},"system_costs.mint_costs"),(0,l.kt)("p",null,"These settings manage the costs of calling the ",(0,l.kt)("inlineCode",{parentName:"p"},"mint")," system contract entrypoints."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mint"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"mint")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"reduce_total_supply"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"reduce_total_supply")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"create"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"create")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"balance"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"balance")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"transfer"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"transfer")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"read_base_round_reward"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"read_base_round_reward")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"mint_into_existing_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"mint_into_existing_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"2_500_000_000")))),(0,l.kt)("h3",{id:"system_costshandle_payment_costs"},"system_costs.handle_payment_costs"),(0,l.kt)("p",null,"These settings manage the costs of calling entrypoints on the ",(0,l.kt)("inlineCode",{parentName:"p"},"handle_payment")," system contract."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_payment_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_payment_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"set_refund_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"set_refund_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"get_refund_purse"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"get_refund_purse")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"finalize_payment"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"finalize_payment")," entrypoint."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")))),(0,l.kt)("h3",{id:"system_costsstandard_payment_costs"},"system_costs.standard_payment_costs"),(0,l.kt)("p",null,"These settings manage the costs of calling entrypoints on the ",(0,l.kt)("inlineCode",{parentName:"p"},"standard_payment")," system contract."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Attribute"),(0,l.kt)("th",{parentName:"tr",align:null},"Description"),(0,l.kt)("th",{parentName:"tr",align:null},"Mainnet Setting"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"pay"),(0,l.kt)("td",{parentName:"tr",align:null},"Cost of calling the ",(0,l.kt)("inlineCode",{parentName:"td"},"pay")," entrypoint and sending an amount to a payment purse."),(0,l.kt)("td",{parentName:"tr",align:null},"10_000")))))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d2361378.8bc0121b.js b/assets/js/d2361378.8bc0121b.js deleted file mode 100644 index 319a900efb..0000000000 --- a/assets/js/d2361378.8bc0121b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8306],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return f}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=a.createContext({}),p=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},l=function(e){var t=p(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),d=p(n),h=o,f=d["".concat(c,".").concat(h)]||d[h]||u[h]||r;return n?a.createElement(f,s(s({ref:t},l),{},{components:n})):a.createElement(f,s({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,s=new Array(r);s[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[d]="string"==typeof e?e:o,s[1]=i;for(var p=2;p=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=a.createContext({}),p=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},l=function(e){var t=p(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,l=i(e,["components","mdxType","originalType","parentName"]),d=p(n),h=o,f=d["".concat(c,".").concat(h)]||d[h]||u[h]||r;return n?a.createElement(f,s(s({ref:t},l),{},{components:n})):a.createElement(f,s({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,s=new Array(r);s[0]=h;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[d]="string"==typeof e?e:o,s[1]=i;for(var p=2;p=0||(r[a]=e[a]);return r}(e,n);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=t.createContext({}),s=function(e){var n=t.useContext(o),a=n;return e&&(a="function"==typeof e?e(n):d(d({},n),e)),a},l=function(e){var n=s(e.components);return t.createElement(o.Provider,{value:n},e.children)},b="mdxType",i={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},p=t.forwardRef((function(e,n){var a=e.components,r=e.mdxType,c=e.originalType,o=e.parentName,l=f(e,["components","mdxType","originalType","parentName"]),b=s(a),p=r,u=b["".concat(o,".").concat(p)]||b[p]||i[p]||c;return a?t.createElement(u,d(d({ref:n},l),{},{components:a})):t.createElement(u,d({ref:n},l))}));function u(e,n){var a=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var c=a.length,d=new Array(c);d[0]=p;var f={};for(var o in n)hasOwnProperty.call(n,o)&&(f[o]=n[o]);f.originalType=e,f[b]="string"==typeof e?e:r,d[1]=f;for(var s=2;saccount_put_deploy_result",id:"account_put_deploy_result",level:3},{value:"speculative_exec",id:"speculative_exec",level:2},{value:"speculative_exec_result",id:"speculative_exec_result",level:3}],i={toc:b},p="wrapper";function u(e){var n=e.components,a=(0,r.Z)(e,d);return(0,c.kt)(p,(0,t.Z)({},i,a,{components:n,mdxType:"MDXLayout"}),(0,c.kt)("h1",{id:"transactional"},"Transactional JSON-RPC Methods"),(0,c.kt)("hr",null),(0,c.kt)("h2",{id:"account-put-deploy"},"account_put_deploy"),(0,c.kt)("p",null,"This is the only means by which users can send their compiled Wasm (as part of a Deploy) to a node on a Casper network. The request takes in the ",(0,c.kt)("a",{parentName:"p",href:"/concepts/design/casper-design/#execution-semantics-deploys"},"Deploy")," as a parameter, prior to sending it to a node on a network for execution."),(0,c.kt)("table",null,(0,c.kt)("thead",{parentName:"table"},(0,c.kt)("tr",{parentName:"thead"},(0,c.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,c.kt)("th",{parentName:"tr",align:null},"Type"),(0,c.kt)("th",{parentName:"tr",align:null},"Description"))),(0,c.kt)("tbody",{parentName:"table"},(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deploy"},"deploy")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"A Deploy consists of an item containing a smart contract along with the requester's signature(s).")))),(0,c.kt)("blockquote",null,(0,c.kt)("p",{parentName:"blockquote"},(0,c.kt)("strong",{parentName:"p"},"Note"),": You can find a list of ",(0,c.kt)("a",{parentName:"p",href:"/operators/setup/joining/#known-addresses"},"trusted peers")," in the network's configuration file, ",(0,c.kt)("inlineCode",{parentName:"p"},"config.toml"),". Here is an ",(0,c.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/resources/production/config-example.toml#L131"},"example config.toml"),". You may send deploys to one of the trusted nodes or use them to query other online nodes.")),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Example account_put_deploy request"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "account_put_deploy",\n "params": [\n {\n "approvals": [\n {\n "signer": "01f8b29f39c38600ecb3bbb082951e04ab63a4ad4f7c9048a5057e461a5a8d58a5",\n "signature": "019d6ef5c62c80ad4e50df343fba6f0fced17dea4c65e7976f66335ffcfcde2a7f02e928c8507cef3c76c3151e0e9cc9c3f7838b9f7a99ac4be5522ca092841100"\n }\n ],\n "hash": "00a8677713222df88b6988926e0b14adeda6c663957f5075003395da4e5c6888",\n "header": {\n "account": "01f8b29f39c38600ecb3bbb082951e04ab63a4ad4f7c9048a5057e461a5a8d58a5",\n "body_hash": "145ae09d6da5bc290051db8cb7132a41a30473d5900eaaf409d92b666325ca00",\n "chain_name": "casper-net-1",\n "dependencies": [\n "0101010101010101010101010101010101010101010101010101010101010101"\n ],\n "gas_price": 1,\n "timestamp": "2023-09-26T14:07:10.024Z",\n "ttl": "1h"\n },\n "payment": {\n "StoredContractByName": {\n "args": [\n [\n "amount",\n {\n "bytes": "0400f90295",\n "cl_type": "U512"\n }\n ]\n ],\n "entry_point": "example-entry-point",\n "name": "casper-example"\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400f90295"\n }\n ],\n [\n "target",\n {\n "cl_type": "URef",\n "bytes": "09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db07"\n }\n ]\n ]\n }\n }\n }\n ]\n}\n\n'))),(0,c.kt)("h3",{id:"account_put_deploy_result"},(0,c.kt)("inlineCode",{parentName:"h3"},"account_put_deploy_result")),(0,c.kt)("p",null,"The result contains the ",(0,c.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#deployhash"},"deploy_hash"),", which is the primary identifier of a Deploy within a Casper network."),(0,c.kt)("table",null,(0,c.kt)("thead",{parentName:"table"},(0,c.kt)("tr",{parentName:"thead"},(0,c.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,c.kt)("th",{parentName:"tr",align:null},"Type"),(0,c.kt)("th",{parentName:"tr",align:null},"Description"))),(0,c.kt)("tbody",{parentName:"table"},(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},"api_version"),(0,c.kt)("td",{parentName:"tr",align:null},"String"),(0,c.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deployhash"},"deploy_hash")),(0,c.kt)("td",{parentName:"tr",align:null},"String"),(0,c.kt)("td",{parentName:"tr",align:null},"A hex-encoded hash of the Deploy as sent.")))),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Example account_put_deploy result"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy_hash": "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa"\n }\n}\n\n'))),(0,c.kt)("h2",{id:"speculative_exec"},"speculative_exec"),(0,c.kt)("p",null,"The ",(0,c.kt)("inlineCode",{parentName:"p"},"speculative_exec")," endpoint provides a method to execute a ",(0,c.kt)("inlineCode",{parentName:"p"},"Deploy")," without committing its execution effects to global state. By default, ",(0,c.kt)("inlineCode",{parentName:"p"},"speculative_exec")," is disabled on a node. Sending a request to a node with the endpoint disabled will result in an error message. If enabled, ",(0,c.kt)("inlineCode",{parentName:"p"},"speculative_exec")," operates on a separate port from the primary JSON-RPC, using 7778."),(0,c.kt)("p",null,(0,c.kt)("inlineCode",{parentName:"p"},"speculative_exec")," executes a Deploy at a specified block. In the case of this endpoint, the execution effects are not committed to global state. As such, it can be used for observing the execution effects of a Deploy without paying for the execution of the Deploy."),(0,c.kt)("table",null,(0,c.kt)("thead",{parentName:"table"},(0,c.kt)("tr",{parentName:"thead"},(0,c.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,c.kt)("th",{parentName:"tr",align:null},"Type"),(0,c.kt)("th",{parentName:"tr",align:null},"Description"))),(0,c.kt)("tbody",{parentName:"table"},(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"The block hash or height on top of which to execute the deploy. If not supplied,the most recent block will be used.")),(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deploy"},"deploy")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"A Deploy consists of an item containing a smart contract along with the requester's signature(s).")))),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Example speculative_exec request"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "method": "speculative_exec",\n "params": {\n "block_identifier": null,\n "deploy": {\n "hash": "b6aa46333fb858deee7f259a5bca581251c6200a5d902aeb1244c3a7169b5971",\n "header": {\n "account": "01a2905e4680aa49e0b44100d9dfc861b9605bb35f9956b1e99eb43863363d80aa",\n "timestamp": "2023-05-23T13:32:45.554Z",\n "ttl": "30m",\n "gas_price": 1,\n "body_hash": "74db109805bb20de43ef89a5b084544a858908b236601519d5827cd9b7fbb925",\n "dependencies": [],\n "chain_name": "integration-test"\n },\n "payment": {\n "ModuleBytes": {\n "module_bytes": "",\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400e1f505",\n "parsed": "100000000"\n }\n ]\n ]\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400f90295",\n "parsed": "2500000000"\n }\n ],\n [\n "target",\n {\n "cl_type": "PublicKey",\n "bytes": "01265ea737411b349ad3d0fc724c2c588acd2765c057e5c690cd5e3dade401782b",\n "parsed": "01265ea737411b349ad3d0fc724c2c588acd2765c057e5c690cd5e3dade401782b"\n }\n ],\n [\n "id",\n {\n "cl_type": {\n "Option": "U64"\n },\n "bytes": "010000000000000000",\n "parsed": 0\n }\n ]\n ]\n }\n },\n "approvals": [\n {\n "signer": "01a2905e4680aa49e0b44100d9dfc861b9605bb35f9956b1e99eb43863363d80aa",\n "signature": "01c94d517d5bbc8d5c74e0e68b8cb308561ff979a1c91907b56d427cc90156c437726c0b736d17f7303f2db66e405c7e5c8175b8b863703938eff1659766dff808"\n }\n ]\n }\n },\n "id": 6889533540839698701\n}\n\n'))),(0,c.kt)("h3",{id:"speculative_exec_result"},(0,c.kt)("inlineCode",{parentName:"h3"},"speculative_exec_result")),(0,c.kt)("p",null,"The result contains the hash of the targeted block and the results of the execution."),(0,c.kt)("table",null,(0,c.kt)("thead",{parentName:"table"},(0,c.kt)("tr",{parentName:"thead"},(0,c.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,c.kt)("th",{parentName:"tr",align:null},"Type"),(0,c.kt)("th",{parentName:"tr",align:null},"Description"))),(0,c.kt)("tbody",{parentName:"table"},(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},"api_version"),(0,c.kt)("td",{parentName:"tr",align:null},"String"),(0,c.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockhash"},"block_hash")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"The Block hash on top of which the deploy was executed.")),(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#executionresult"},"execution_results")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"The map of Block hash to execution result.")))),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Example speculative_exec result"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "id": -8801853076373554652,\n "result": {\n "api_version": "1.5.0",\n "block_hash": "ff862326b08702a5089d64e32100537b7ff984cac4c0ba6d1c561f7c47125f76",\n "execution_result": {\n "Success": {\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "transform": "Identity"\n },\n {\n "key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-0a300922655180354a9ee92b808c7b45b08e5b01d9da0bac9a9b3415bcebbf8d",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "05f0e630ed87",\n "parsed": "583799990000"\n }\n }\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": {\n "AddUInt512": "100000000"\n }\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "transform": "Identity"\n },\n {\n "key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-0a300922655180354a9ee92b808c7b45b08e5b01d9da0bac9a9b3415bcebbf8d",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "05f0e630ed87",\n "parsed": "583799990000"\n }\n }\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": {\n "AddUInt512": "100000000"\n }\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": "Identity"\n },\n {\n "key": "balance-92ec6dfbdf151e20b55c89e0a327959cf6e5b091c5f2b39201c1858e2943f3bd",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "05f0ed2d5887",\n "parsed": "581299990000"\n }\n }\n },\n {\n "key": "balance-92ec6dfbdf151e20b55c89e0a327959cf6e5b091c5f2b39201c1858e2943f3bd",\n "transform": {\n "AddUInt512": "2500000000"\n }\n },\n {\n "key": "transfer-97426c848475dae98446f2c2fd00ec7901cd8ddfe250171ff4ed25d78412a612",\n "transform": {\n "WriteTransfer": {\n "deploy_hash": "d898910011b1f2f8797a442740e69cd5de41b9f796e658e962a24663e6199e5a",\n "from": "account-hash-0a9b33af5108c5a6e1067b0ddec6853ce1745d591375d767ac5db680d21845e7",\n "to": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "source": "uref-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678-007",\n "target": "uref-92ec6dfbdf151e20b55c89e0a327959cf6e5b091c5f2b39201c1858e2943f3bd-004",\n "amount": "2500000000",\n "gas": "0",\n "id": 0\n }\n }\n },\n {\n "key": "deploy-d898910011b1f2f8797a442740e69cd5de41b9f796e658e962a24663e6199e5a",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "d898910011b1f2f8797a442740e69cd5de41b9f796e658e962a24663e6199e5a",\n "transfers": [\n "transfer-97426c848475dae98446f2c2fd00ec7901cd8ddfe250171ff4ed25d78412a612"\n ],\n "from": "account-hash-0a9b33af5108c5a6e1067b0ddec6853ce1745d591375d767ac5db680d21845e7",\n "source": "uref-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678-007",\n "gas": "100000000"\n }\n }\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-0a300922655180354a9ee92b808c7b45b08e5b01d9da0bac9a9b3415bcebbf8d",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": "Identity"\n },\n {\n "key": "balance-ecc530e74cf2185936a334aa1e0f07539aa3b33c4b547e71fc4109151755652f",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "00",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-ecc530e74cf2185936a334aa1e0f07539aa3b33c4b547e71fc4109151755652f",\n "transform": {\n "AddUInt512": "100000000"\n }\n }\n ]\n },\n "transfers": [\n "transfer-97426c848475dae98446f2c2fd00ec7901cd8ddfe250171ff4ed25d78412a612"\n ],\n "cost": "100000000"\n }\n }\n }\n}\n\n'))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d45ad3b6.8b90874a.js b/assets/js/d45ad3b6.8b90874a.js new file mode 100644 index 0000000000..290b45492b --- /dev/null +++ b/assets/js/d45ad3b6.8b90874a.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[3617],{3905:function(e,n,a){a.d(n,{Zo:function(){return l},kt:function(){return u}});var t=a(7294);function r(e,n,a){return n in e?Object.defineProperty(e,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[n]=a,e}function c(e,n){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),a.push.apply(a,t)}return a}function d(e){for(var n=1;n=0||(r[a]=e[a]);return r}(e,n);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=t.createContext({}),s=function(e){var n=t.useContext(o),a=n;return e&&(a="function"==typeof e?e(n):d(d({},n),e)),a},l=function(e){var n=s(e.components);return t.createElement(o.Provider,{value:n},e.children)},b="mdxType",i={inlineCode:"code",wrapper:function(e){var n=e.children;return t.createElement(t.Fragment,{},n)}},p=t.forwardRef((function(e,n){var a=e.components,r=e.mdxType,c=e.originalType,o=e.parentName,l=f(e,["components","mdxType","originalType","parentName"]),b=s(a),p=r,u=b["".concat(o,".").concat(p)]||b[p]||i[p]||c;return a?t.createElement(u,d(d({ref:n},l),{},{components:a})):t.createElement(u,d({ref:n},l))}));function u(e,n){var a=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var c=a.length,d=new Array(c);d[0]=p;var f={};for(var o in n)hasOwnProperty.call(n,o)&&(f[o]=n[o]);f.originalType=e,f[b]="string"==typeof e?e:r,d[1]=f;for(var s=2;saccount_put_deploy_result",id:"account_put_deploy_result",level:3},{value:"speculative_exec",id:"speculative_exec",level:2},{value:"speculative_exec_result",id:"speculative_exec_result",level:3}],i={toc:b},p="wrapper";function u(e){var n=e.components,a=(0,r.Z)(e,d);return(0,c.kt)(p,(0,t.Z)({},i,a,{components:n,mdxType:"MDXLayout"}),(0,c.kt)("h1",{id:"transactional"},"Transactional JSON-RPC Methods"),(0,c.kt)("hr",null),(0,c.kt)("h2",{id:"account-put-deploy"},"account_put_deploy"),(0,c.kt)("p",null,"This is the only means by which users can send their compiled Wasm (as part of a Deploy) to a node on a Casper network. The request takes in the ",(0,c.kt)("a",{parentName:"p",href:"/concepts/design/casper-design/#execution-semantics-deploys"},"Deploy")," as a parameter, prior to sending it to a node on a network for execution."),(0,c.kt)("table",null,(0,c.kt)("thead",{parentName:"table"},(0,c.kt)("tr",{parentName:"thead"},(0,c.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,c.kt)("th",{parentName:"tr",align:null},"Type"),(0,c.kt)("th",{parentName:"tr",align:null},"Description"))),(0,c.kt)("tbody",{parentName:"table"},(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deploy"},"deploy")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"A Deploy consists of an item containing a smart contract along with the requester's signature(s).")))),(0,c.kt)("blockquote",null,(0,c.kt)("p",{parentName:"blockquote"},(0,c.kt)("strong",{parentName:"p"},"Note"),": You can find a list of ",(0,c.kt)("a",{parentName:"p",href:"/operators/setup/joining/#known-addresses"},"trusted peers")," in the network's configuration file, ",(0,c.kt)("inlineCode",{parentName:"p"},"config.toml"),". Here is an ",(0,c.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/resources/production/config-example.toml#L131"},"example config.toml"),". You may send deploys to one of the trusted nodes or use them to query other online nodes.")),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Example account_put_deploy request"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "method": "account_put_deploy",\n "params": [\n {\n "approvals": [\n {\n "signer": "01f8b29f39c38600ecb3bbb082951e04ab63a4ad4f7c9048a5057e461a5a8d58a5",\n "signature": "019d6ef5c62c80ad4e50df343fba6f0fced17dea4c65e7976f66335ffcfcde2a7f02e928c8507cef3c76c3151e0e9cc9c3f7838b9f7a99ac4be5522ca092841100"\n }\n ],\n "hash": "00a8677713222df88b6988926e0b14adeda6c663957f5075003395da4e5c6888",\n "header": {\n "account": "01f8b29f39c38600ecb3bbb082951e04ab63a4ad4f7c9048a5057e461a5a8d58a5",\n "body_hash": "145ae09d6da5bc290051db8cb7132a41a30473d5900eaaf409d92b666325ca00",\n "chain_name": "casper-net-1",\n "dependencies": [\n "0101010101010101010101010101010101010101010101010101010101010101"\n ],\n "gas_price": 1,\n "timestamp": "2023-09-26T14:07:10.024Z",\n "ttl": "1h"\n },\n "payment": {\n "StoredContractByName": {\n "args": [\n [\n "amount",\n {\n "bytes": "0400f90295",\n "cl_type": "U512"\n }\n ]\n ],\n "entry_point": "example-entry-point",\n "name": "casper-example"\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400f90295"\n }\n ],\n [\n "target",\n {\n "cl_type": "URef",\n "bytes": "09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db07"\n }\n ]\n ]\n }\n }\n }\n ]\n}\n\n'))),(0,c.kt)("h3",{id:"account_put_deploy_result"},(0,c.kt)("inlineCode",{parentName:"h3"},"account_put_deploy_result")),(0,c.kt)("p",null,"The result contains the ",(0,c.kt)("a",{parentName:"p",href:"/developers/json-rpc/types_chain#deployhash"},"deploy_hash"),", which is the primary identifier of a Deploy within a Casper network."),(0,c.kt)("table",null,(0,c.kt)("thead",{parentName:"table"},(0,c.kt)("tr",{parentName:"thead"},(0,c.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,c.kt)("th",{parentName:"tr",align:null},"Type"),(0,c.kt)("th",{parentName:"tr",align:null},"Description"))),(0,c.kt)("tbody",{parentName:"table"},(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},"api_version"),(0,c.kt)("td",{parentName:"tr",align:null},"String"),(0,c.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deployhash"},"deploy_hash")),(0,c.kt)("td",{parentName:"tr",align:null},"String"),(0,c.kt)("td",{parentName:"tr",align:null},"A hex-encoded hash of the Deploy as sent.")))),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Example account_put_deploy result"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 1,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.13",\n "deploy_hash": "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa"\n }\n}\n\n'))),(0,c.kt)("h2",{id:"speculative_exec"},"speculative_exec"),(0,c.kt)("p",null,"The ",(0,c.kt)("inlineCode",{parentName:"p"},"speculative_exec")," endpoint provides a method to execute a ",(0,c.kt)("inlineCode",{parentName:"p"},"Deploy")," without committing its execution effects to global state. By default, ",(0,c.kt)("inlineCode",{parentName:"p"},"speculative_exec")," is disabled on a node. Sending a request to a node with the endpoint disabled will result in an error message. If enabled, ",(0,c.kt)("inlineCode",{parentName:"p"},"speculative_exec")," operates on a separate port from the primary JSON-RPC, using 7778."),(0,c.kt)("p",null,(0,c.kt)("inlineCode",{parentName:"p"},"speculative_exec")," executes a Deploy at a specified block. In the case of this endpoint, the execution effects are not committed to global state. As such, it can be used for observing the execution effects of a Deploy without paying for the execution of the Deploy."),(0,c.kt)("table",null,(0,c.kt)("thead",{parentName:"table"},(0,c.kt)("tr",{parentName:"thead"},(0,c.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,c.kt)("th",{parentName:"tr",align:null},"Type"),(0,c.kt)("th",{parentName:"tr",align:null},"Description"))),(0,c.kt)("tbody",{parentName:"table"},(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockidentifier"},"block_identifier")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"The block hash or height on top of which to execute the deploy. If not supplied,the most recent block will be used.")),(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#deploy"},"deploy")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"A Deploy consists of an item containing a smart contract along with the requester's signature(s).")))),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Example speculative_exec request"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "method": "speculative_exec",\n "params": {\n "block_identifier": null,\n "deploy": {\n "hash": "b6aa46333fb858deee7f259a5bca581251c6200a5d902aeb1244c3a7169b5971",\n "header": {\n "account": "01a2905e4680aa49e0b44100d9dfc861b9605bb35f9956b1e99eb43863363d80aa",\n "timestamp": "2023-05-23T13:32:45.554Z",\n "ttl": "30m",\n "gas_price": 1,\n "body_hash": "74db109805bb20de43ef89a5b084544a858908b236601519d5827cd9b7fbb925",\n "dependencies": [],\n "chain_name": "integration-test"\n },\n "payment": {\n "ModuleBytes": {\n "module_bytes": "",\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400e1f505",\n "parsed": "100000000"\n }\n ]\n ]\n }\n },\n "session": {\n "Transfer": {\n "args": [\n [\n "amount",\n {\n "cl_type": "U512",\n "bytes": "0400f90295",\n "parsed": "2500000000"\n }\n ],\n [\n "target",\n {\n "cl_type": "PublicKey",\n "bytes": "01265ea737411b349ad3d0fc724c2c588acd2765c057e5c690cd5e3dade401782b",\n "parsed": "01265ea737411b349ad3d0fc724c2c588acd2765c057e5c690cd5e3dade401782b"\n }\n ],\n [\n "id",\n {\n "cl_type": {\n "Option": "U64"\n },\n "bytes": "010000000000000000",\n "parsed": 0\n }\n ]\n ]\n }\n },\n "approvals": [\n {\n "signer": "01a2905e4680aa49e0b44100d9dfc861b9605bb35f9956b1e99eb43863363d80aa",\n "signature": "01c94d517d5bbc8d5c74e0e68b8cb308561ff979a1c91907b56d427cc90156c437726c0b736d17f7303f2db66e405c7e5c8175b8b863703938eff1659766dff808"\n }\n ]\n }\n },\n "id": 6889533540839698701\n}\n\n'))),(0,c.kt)("h3",{id:"speculative_exec_result"},(0,c.kt)("inlineCode",{parentName:"h3"},"speculative_exec_result")),(0,c.kt)("p",null,"The result contains the hash of the targeted block and the results of the execution."),(0,c.kt)("table",null,(0,c.kt)("thead",{parentName:"table"},(0,c.kt)("tr",{parentName:"thead"},(0,c.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,c.kt)("th",{parentName:"tr",align:null},"Type"),(0,c.kt)("th",{parentName:"tr",align:null},"Description"))),(0,c.kt)("tbody",{parentName:"table"},(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},"api_version"),(0,c.kt)("td",{parentName:"tr",align:null},"String"),(0,c.kt)("td",{parentName:"tr",align:null},"The RPC API version.")),(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#blockhash"},"block_hash")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"The Block hash on top of which the deploy was executed.")),(0,c.kt)("tr",{parentName:"tbody"},(0,c.kt)("td",{parentName:"tr",align:null},(0,c.kt)("a",{parentName:"td",href:"/developers/json-rpc/types_chain#executionresult"},"execution_results")),(0,c.kt)("td",{parentName:"tr",align:null},"Object"),(0,c.kt)("td",{parentName:"tr",align:null},"The map of Block hash to execution result.")))),(0,c.kt)("details",null,(0,c.kt)("summary",null,"Example speculative_exec result"),(0,c.kt)("pre",null,(0,c.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "jsonrpc": "2.0",\n "id": -8801853076373554652,\n "result": {\n "api_version": "1.5.0",\n "block_hash": "ff862326b08702a5089d64e32100537b7ff984cac4c0ba6d1c561f7c47125f76",\n "execution_result": {\n "Success": {\n "effect": {\n "operations": [],\n "transforms": [\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "transform": "Identity"\n },\n {\n "key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-0a300922655180354a9ee92b808c7b45b08e5b01d9da0bac9a9b3415bcebbf8d",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "05f0e630ed87",\n "parsed": "583799990000"\n }\n }\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": {\n "AddUInt512": "100000000"\n }\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "transform": "Identity"\n },\n {\n "key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-0a300922655180354a9ee92b808c7b45b08e5b01d9da0bac9a9b3415bcebbf8d",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "05f0e630ed87",\n "parsed": "583799990000"\n }\n }\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": {\n "AddUInt512": "100000000"\n }\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": "Identity"\n },\n {\n "key": "balance-92ec6dfbdf151e20b55c89e0a327959cf6e5b091c5f2b39201c1858e2943f3bd",\n "transform": "Identity"\n },\n {\n "key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "05f0ed2d5887",\n "parsed": "581299990000"\n }\n }\n },\n {\n "key": "balance-92ec6dfbdf151e20b55c89e0a327959cf6e5b091c5f2b39201c1858e2943f3bd",\n "transform": {\n "AddUInt512": "2500000000"\n }\n },\n {\n "key": "transfer-97426c848475dae98446f2c2fd00ec7901cd8ddfe250171ff4ed25d78412a612",\n "transform": {\n "WriteTransfer": {\n "deploy_hash": "d898910011b1f2f8797a442740e69cd5de41b9f796e658e962a24663e6199e5a",\n "from": "account-hash-0a9b33af5108c5a6e1067b0ddec6853ce1745d591375d767ac5db680d21845e7",\n "to": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",\n "source": "uref-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678-007",\n "target": "uref-92ec6dfbdf151e20b55c89e0a327959cf6e5b091c5f2b39201c1858e2943f3bd-004",\n "amount": "2500000000",\n "gas": "0",\n "id": 0\n }\n }\n },\n {\n "key": "deploy-d898910011b1f2f8797a442740e69cd5de41b9f796e658e962a24663e6199e5a",\n "transform": {\n "WriteDeployInfo": {\n "deploy_hash": "d898910011b1f2f8797a442740e69cd5de41b9f796e658e962a24663e6199e5a",\n "transfers": [\n "transfer-97426c848475dae98446f2c2fd00ec7901cd8ddfe250171ff4ed25d78412a612"\n ],\n "from": "account-hash-0a9b33af5108c5a6e1067b0ddec6853ce1745d591375d767ac5db680d21845e7",\n "source": "uref-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678-007",\n "gas": "100000000"\n }\n }\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-0a300922655180354a9ee92b808c7b45b08e5b01d9da0bac9a9b3415bcebbf8d",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": "Identity"\n },\n {\n "key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",\n "transform": "Identity"\n },\n {\n "key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": "Identity"\n },\n {\n "key": "balance-ecc530e74cf2185936a334aa1e0f07539aa3b33c4b547e71fc4109151755652f",\n "transform": "Identity"\n },\n {\n "key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",\n "transform": {\n "WriteCLValue": {\n "cl_type": "U512",\n "bytes": "00",\n "parsed": "0"\n }\n }\n },\n {\n "key": "balance-ecc530e74cf2185936a334aa1e0f07539aa3b33c4b547e71fc4109151755652f",\n "transform": {\n "AddUInt512": "100000000"\n }\n }\n ]\n },\n "transfers": [\n "transfer-97426c848475dae98446f2c2fd00ec7901cd8ddfe250171ff4ed25d78412a612"\n ],\n "cost": "100000000"\n }\n }\n }\n}\n\n'))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/db0e1f9a.56848ffd.js b/assets/js/db0e1f9a.56848ffd.js deleted file mode 100644 index ac5717f439..0000000000 --- a/assets/js/db0e1f9a.56848ffd.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[8444],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return m}});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=r.createContext({}),u=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(i.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},k=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=u(n),k=a,m=p["".concat(i,".").concat(k)]||p[k]||d[k]||o;return n?r.createElement(m,l(l({ref:t},c),{},{components:n})):r.createElement(m,l({ref:t},c))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=k;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[p]="string"==typeof e?e:a,l[1]=s;for(var u=2;u=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=r.createContext({}),u=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(i.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},k=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=u(n),k=a,m=p["".concat(i,".").concat(k)]||p[k]||d[k]||o;return n?r.createElement(m,l(l({ref:t},c),{},{components:n})):r.createElement(m,l({ref:t},c))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=k;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[p]="string"==typeof e?e:a,l[1]=s;for(var u=2;u=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),h=a,m=p["".concat(c,".").concat(h)]||p[h]||f[h]||i;return n?r.createElement(m,o(o({ref:t},u),{},{components:n})):r.createElement(m,o({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:a,o[1]=s;for(var l=2;l=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(n),h=a,m=p["".concat(c,".").concat(h)]||p[h]||f[h]||i;return n?r.createElement(m,o(o({ref:t},u),{},{components:n})):r.createElement(m,o({ref:t},u))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:a,o[1]=s;for(var l=2;l=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var d=a.createContext({}),c=function(e){var n=a.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},l=function(e){var n=c(e.components);return a.createElement(d.Provider,{value:n},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(t),h=i,b=p["".concat(d,".").concat(h)]||p[h]||u[h]||o;return t?a.createElement(b,r(r({ref:n},l),{},{components:t})):a.createElement(b,r({ref:n},l))}));function b(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var o=t.length,r=new Array(o);r[0]=h;var s={};for(var d in n)hasOwnProperty.call(n,d)&&(s[d]=n[d]);s.originalType=e,s[p]="string"==typeof e?e:i,r[1]=s;for(var c=2;c \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point add_bid \\\n--session-arg=\"public_key:public_key=''\" \\\n--session-arg=\"amount:u512=''\" \\\n--session-arg=\"delegation_rate:u8=''\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entrypoint that will be used when calling the contract")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid")," entry point expects three arguments:"),(0,o.kt)("ol",{start:7},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public key"),": The hexadecimal public key of the account's purse submitting the bid. This key must match the secret key that signs the bid"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"amount"),": The bidding amount"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"delegation_rate"),": Percentage of the rewards that the node operator retains for their services")),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid")," entry point on the auction contract has a fixed cost of 2.5 CSPR.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"This example command uses the Casper Testnet to bid 10,000 CSPR for a validating slot:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point add_bid \\\n--session-arg \"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg \"amount:U512='$[10000 * 1000000000]'\" \\\n--session-arg=\"delegation_rate:u8='10'\"\n")),(0,o.kt)("p",null,"Next, ",(0,o.kt)("a",{parentName:"p",href:"#check-the-status-of-the-bid-in-the-auction"},"check the status of the auction")," to see if you have won a validator slot."),(0,o.kt)("h2",{id:"bonding-compiled-wasm"},"Method 2: Bonding with Compiled Wasm"),(0,o.kt)("p",null,"Another way to send a bonding transaction to the network is via a deploy containing the compiled ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid.wasm"),". For details, refer to ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup/joining#step-3-build-contracts"},"Building the Required Contracts"),"."),(0,o.kt)("p",null,"The following deploy is a template for sending a bonding request:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http:// \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name \\\n--payment-amount \\\n--session-path $HOME/casper-node/target/wasm32-unknown-unknown/release/add_bid.wasm \\\n--session-arg=\"public_key:public_key=''\" \\\n--session-arg=\"amount:u512=''\" \\\n--session-arg=\"delegation_rate:u8=''\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the compiled Wasm on your computer")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid.wasm")," expects three arguments:"),(0,o.kt)("ol",{start:7},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key"),": The hexadecimal public key of the account's purse submitting the bid. This key must match the secret key that signs the bid"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"amount"),": The bidding amount"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"delegation_rate"),": Percentage of the rewards that the node operator retains for their services")),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"This method is more expensive than calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid")," entrypoint in the system auction contract, which has a fixed cost of 2.5 CSPR.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"Here is an example request to bond using the ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid.wasm"),". The payment amount specified is 3 CSPR. You must modify the payment and other values in the deploy based on the network's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.235.219:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 3000000000 \\\n--session-path ~/casper-node/target/wasm32-unknown-unknown/release/add_bid.wasm \\\n--session-arg \"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg \"amount:U512='$[10000 * 1000000000]'\" \\\n--session-arg=\"delegation_rate:u8='10'\"\n")),(0,o.kt)("p",null,"Next, check the bid status to see if you have won a validator slot."),(0,o.kt)("h2",{id:"check-the-status-of-the-bid-in-the-auction"},"Checking the Bid Status"),(0,o.kt)("p",null,"Since the bid was submitted using a deploy like any other, perform ",(0,o.kt)("inlineCode",{parentName:"p"},"get-deploy")," using the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client"),", to see the execution status."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address http:// \n")),(0,o.kt)("p",null,"If the bid wins the auction, the public key and associated bonded amount will appear in the auction contract as part of the validator set for a future era. To determine if the bid was accepted, query the auction contract:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info --node-address http://\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example auction info response"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n"jsonrpc": "2.0",\n"result": {\n "bids": [\n {\n "bid": {\n "bonding_purse": "uref-488a0bbc3c3729f5696965da7a3aeee83805392944e36157909da273255fdb85-007",\n "delegation_rate": 0,\n "delegators": [],\n "release_era": null,\n "reward": "93328432442428418861229954179737",\n "staked_amount": "10000000000000000"\n },\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012"\n },\n {\n "bid": {\n "bonding_purse": "uref-14e128b099b0c3680100520226e6999b322989586cc22db0630db5ec1329f0a7-007",\n "delegation_rate": 10,\n "delegators": [],\n "release_era": null,\n "reward": "0",\n "staked_amount": "9000000000000000"\n },\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87"\n },\n {\n "bid": {\n "bonding_purse": "uref-6c0bf8cee1c0749dd9766376910867a84b2e826eaf6c118fcb0224c7d8d229dd-007",\n "delegation_rate": 10,\n "delegators": [],\n "release_era": null,\n "reward": "266185120443441810685787",\n "staked_amount": "100000000"\n },\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f"\n },\n {\n "bid": {\n "bonding_purse": "uref-3880b3daf95f962f57e6a4b1589564abf7deef58a1fb0753d1108316bba7b3d7-007",\n "delegation_rate": 10,\n "delegators": [],\n "release_era": null,\n "reward": "0",\n "staked_amount": "9000000000000000"\n },\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643"\n },\n {\n "bid": {\n "bonding_purse": "uref-5a777c9cd53456b49eecf25dcc13e12ddff4106175a69f8e24a7c9a4c135df0d-007",\n "delegation_rate": 0,\n "delegators": [],\n "release_era": null,\n "reward": "93328432442428418861229954179737",\n "staked_amount": "10000000000000000"\n },\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e"\n }\n ],\n "block_height": 318,\n "era_validators": [\n {\n "era_id": 20,\n "validator_weights": [\n {\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",\n "weight": "10000000000000000"\n },\n {\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",\n "weight": "100000000"\n },\n {\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",\n "weight": "10000000000000000"\n }\n ]\n },\n {\n "era_id": 21,\n "validator_weights": [\n {\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",\n "weight": "10000000000000000"\n },\n {\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",\n "weight": "100000000"\n },\n {\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",\n "weight": "10000000000000000"\n }\n ]\n },\n {\n "era_id": 22,\n "validator_weights": [\n {\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",\n "weight": "10000000000000000"\n },\n {\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",\n "weight": "100000000"\n },\n {\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",\n "weight": "10000000000000000"\n }\n ]\n },\n {\n "era_id": 23,\n "validator_weights": [\n {\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",\n "weight": "10000000000000000"\n },\n {\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",\n "weight": "100000000"\n },\n {\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",\n "weight": "10000000000000000"\n }\n ]\n }\n ],\n "state_root_hash": "c16ba80ea200d786008f8100ea79f9cfeb8d7d5ee8b133eda5a50dcf1c7131e8"\n},\n"id": -3624528661787095850\n}\n'))),(0,o.kt)("br",null),(0,o.kt)("p",null,"Note the ",(0,o.kt)("inlineCode",{parentName:"p"},"era_id")," and the ",(0,o.kt)("inlineCode",{parentName:"p"},"validator_weights")," in the response above. The current era is the one with the lowest ID in the ",(0,o.kt)("inlineCode",{parentName:"p"},"era_validators")," array. For a given ",(0,o.kt)("inlineCode",{parentName:"p"},"era_id"),", a set of validators is defined. If the public key associated with a bid appears in the ",(0,o.kt)("inlineCode",{parentName:"p"},"validator_weights")," structure for an era, then the account is bonded in that era."),(0,o.kt)("h2",{id:"losing-bid"},"A Losing Bid"),(0,o.kt)("p",null,"If a bid doesn't win a slot in the auction, it is too low. The resolution is to increase the bid amount. It is possible to submit additional bids, to increase the odds of winning a slot. It is also possible to encourage token holders to delegate stake to you for bonding."),(0,o.kt)("h2",{id:"avoiding-ejection"},"Avoiding Ejection"),(0,o.kt)("p",null,"To stay bonded and avoid ejection, each validator must keep their node running and in sync with the rest of the network. To recover from ejection, you will find more details ",(0,o.kt)("a",{parentName:"p",href:"/operators/becoming-a-validator/recovering"},"here"),"."),(0,o.kt)("h2",{id:"withdrawing-a-bid"},"Withdrawing a Bid"),(0,o.kt)("p",null,"Follow the steps in ",(0,o.kt)("a",{parentName:"p",href:"/operators/becoming-a-validator/unbonding"},"Unbonding")," to withdraw a bid."))}b.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/dd0f338d.b2499a9b.js b/assets/js/dd0f338d.b2499a9b.js deleted file mode 100644 index 702b7eb451..0000000000 --- a/assets/js/dd0f338d.b2499a9b.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[1301],{3905:function(e,n,t){t.d(n,{Zo:function(){return l},kt:function(){return b}});var a=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function r(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var d=a.createContext({}),c=function(e){var n=a.useContext(d),t=n;return e&&(t="function"==typeof e?e(n):r(r({},n),e)),t},l=function(e){var n=c(e.components);return a.createElement(d.Provider,{value:n},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},h=a.forwardRef((function(e,n){var t=e.components,i=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(t),h=i,b=p["".concat(d,".").concat(h)]||p[h]||u[h]||o;return t?a.createElement(b,r(r({ref:n},l),{},{components:t})):a.createElement(b,r({ref:n},l))}));function b(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var o=t.length,r=new Array(o);r[0]=h;var s={};for(var d in n)hasOwnProperty.call(n,d)&&(s[d]=n[d]);s.originalType=e,s[p]="string"==typeof e?e:i,r[1]=s;for(var c=2;c \\\n--secret-key \\\n--chain-name \\\n--payment-amount \\\n--session-hash \\\n--session-entry-point add_bid \\\n--session-arg=\"public_key:public_key=''\" \\\n--session-arg=\"amount:u512=''\" \\\n--session-arg=\"delegation_rate:u8=''\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version ",(0,o.kt)("a",{parentName:"li",href:"https://github.com/casper-network/casper-node/blob/release-1.5.1/resources/production/chainspec.toml"},"1.5.1")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-hash")," - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Testnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Mainnet"),": ",(0,o.kt)("inlineCode",{parentName:"li"},"hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea"))),(0,o.kt)("ol",{start:6},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-entry-point")," - Name of the entrypoint that will be used when calling the contract")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid")," entry point expects three arguments:"),(0,o.kt)("ol",{start:7},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public key"),": The hexadecimal public key of the account's purse submitting the bid. This key must match the secret key that signs the bid"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"amount"),": The bidding amount"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"delegation_rate"),": Percentage of the rewards that the node operator retains for their services")),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid")," entry point on the auction contract has a fixed cost of 2.5 CSPR.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"This example command uses the Casper Testnet to bid 10,000 CSPR for a validating slot:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.75.254:7777 \\\n--chain-name casper-test \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--payment-amount 2500000000 \\\n--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \\\n--session-entry-point add_bid \\\n--session-arg \"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg \"amount:U512='$[10000 * 1000000000]'\" \\\n--session-arg=\"delegation_rate:u8='10'\"\n")),(0,o.kt)("p",null,"Next, ",(0,o.kt)("a",{parentName:"p",href:"#check-the-status-of-the-bid-in-the-auction"},"check the status of the auction")," to see if you have won a validator slot."),(0,o.kt)("h2",{id:"bonding-compiled-wasm"},"Method 2: Bonding with Compiled Wasm"),(0,o.kt)("p",null,"Another way to send a bonding transaction to the network is via a deploy containing the compiled ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid.wasm"),". For details, refer to ",(0,o.kt)("a",{parentName:"p",href:"/operators/setup/joining#step-3-build-contracts"},"Building the Required Contracts"),"."),(0,o.kt)("p",null,"The following deploy is a template for sending a bonding request:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http:// \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name \\\n--payment-amount \\\n--session-path $HOME/casper-node/target/wasm32-unknown-unknown/release/add_bid.wasm \\\n--session-arg=\"public_key:public_key=''\" \\\n--session-arg=\"amount:u512=''\" \\\n--session-arg=\"delegation_rate:u8=''\"\n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the account paying for the Deploy"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the Deploy. For Mainnet, use ",(0,o.kt)("em",{parentName:"li"},"casper"),". For Testnet, use ",(0,o.kt)("em",{parentName:"li"},"casper-test")),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The payment for the Deploy in motes"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the compiled Wasm on your computer")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid.wasm")," expects three arguments:"),(0,o.kt)("ol",{start:7},(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key"),": The hexadecimal public key of the account's purse submitting the bid. This key must match the secret key that signs the bid"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"amount"),": The bidding amount"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"delegation_rate"),": Percentage of the rewards that the node operator retains for their services")),(0,o.kt)("p",null,"The command will return a deploy hash, which is needed to verify the deploy's processing results."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"This method is more expensive than calling the ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid")," entrypoint in the system auction contract, which has a fixed cost of 2.5 CSPR.")),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example:")),(0,o.kt)("p",null,"Here is an example request to bond using the ",(0,o.kt)("inlineCode",{parentName:"p"},"add_bid.wasm"),". The payment amount specified is 3 CSPR. You must modify the payment and other values in the deploy based on the network's ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec.toml"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo -u casper casper-client put-deploy \\\n--node-address http://65.21.235.219:7777 \\\n--secret-key /etc/casper/validator_keys/secret_key.pem \\\n--chain-name casper-test \\\n--payment-amount 3000000000 \\\n--session-path ~/casper-node/target/wasm32-unknown-unknown/release/add_bid.wasm \\\n--session-arg \"public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'\" \\\n--session-arg \"amount:U512='$[10000 * 1000000000]'\" \\\n--session-arg=\"delegation_rate:u8='10'\"\n")),(0,o.kt)("p",null,"Next, check the bid status to see if you have won a validator slot."),(0,o.kt)("h2",{id:"check-the-status-of-the-bid-in-the-auction"},"Checking the Bid Status"),(0,o.kt)("p",null,"Since the bid was submitted using a deploy like any other, perform ",(0,o.kt)("inlineCode",{parentName:"p"},"get-deploy")," using the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client"),", to see the execution status."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-deploy --node-address http:// \n")),(0,o.kt)("p",null,"If the bid wins the auction, the public key and associated bonded amount will appear in the auction contract as part of the validator set for a future era. To determine if the bid was accepted, query the auction contract:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-auction-info --node-address http://\n")),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Example auction info response"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'{\n"jsonrpc": "2.0",\n"result": {\n "bids": [\n {\n "bid": {\n "bonding_purse": "uref-488a0bbc3c3729f5696965da7a3aeee83805392944e36157909da273255fdb85-007",\n "delegation_rate": 0,\n "delegators": [],\n "release_era": null,\n "reward": "93328432442428418861229954179737",\n "staked_amount": "10000000000000000"\n },\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012"\n },\n {\n "bid": {\n "bonding_purse": "uref-14e128b099b0c3680100520226e6999b322989586cc22db0630db5ec1329f0a7-007",\n "delegation_rate": 10,\n "delegators": [],\n "release_era": null,\n "reward": "0",\n "staked_amount": "9000000000000000"\n },\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87"\n },\n {\n "bid": {\n "bonding_purse": "uref-6c0bf8cee1c0749dd9766376910867a84b2e826eaf6c118fcb0224c7d8d229dd-007",\n "delegation_rate": 10,\n "delegators": [],\n "release_era": null,\n "reward": "266185120443441810685787",\n "staked_amount": "100000000"\n },\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f"\n },\n {\n "bid": {\n "bonding_purse": "uref-3880b3daf95f962f57e6a4b1589564abf7deef58a1fb0753d1108316bba7b3d7-007",\n "delegation_rate": 10,\n "delegators": [],\n "release_era": null,\n "reward": "0",\n "staked_amount": "9000000000000000"\n },\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643"\n },\n {\n "bid": {\n "bonding_purse": "uref-5a777c9cd53456b49eecf25dcc13e12ddff4106175a69f8e24a7c9a4c135df0d-007",\n "delegation_rate": 0,\n "delegators": [],\n "release_era": null,\n "reward": "93328432442428418861229954179737",\n "staked_amount": "10000000000000000"\n },\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e"\n }\n ],\n "block_height": 318,\n "era_validators": [\n {\n "era_id": 20,\n "validator_weights": [\n {\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",\n "weight": "10000000000000000"\n },\n {\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",\n "weight": "100000000"\n },\n {\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",\n "weight": "10000000000000000"\n }\n ]\n },\n {\n "era_id": 21,\n "validator_weights": [\n {\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",\n "weight": "10000000000000000"\n },\n {\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",\n "weight": "100000000"\n },\n {\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",\n "weight": "10000000000000000"\n }\n ]\n },\n {\n "era_id": 22,\n "validator_weights": [\n {\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",\n "weight": "10000000000000000"\n },\n {\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",\n "weight": "100000000"\n },\n {\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",\n "weight": "10000000000000000"\n }\n ]\n },\n {\n "era_id": 23,\n "validator_weights": [\n {\n "public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",\n "weight": "10000000000000000"\n },\n {\n "public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",\n "weight": "100000000"\n },\n {\n "public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",\n "weight": "9000000000000000"\n },\n {\n "public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",\n "weight": "10000000000000000"\n }\n ]\n }\n ],\n "state_root_hash": "c16ba80ea200d786008f8100ea79f9cfeb8d7d5ee8b133eda5a50dcf1c7131e8"\n},\n"id": -3624528661787095850\n}\n'))),(0,o.kt)("br",null),(0,o.kt)("p",null,"Note the ",(0,o.kt)("inlineCode",{parentName:"p"},"era_id")," and the ",(0,o.kt)("inlineCode",{parentName:"p"},"validator_weights")," in the response above. The current era is the one with the lowest ID in the ",(0,o.kt)("inlineCode",{parentName:"p"},"era_validators")," array. For a given ",(0,o.kt)("inlineCode",{parentName:"p"},"era_id"),", a set of validators is defined. If the public key associated with a bid appears in the ",(0,o.kt)("inlineCode",{parentName:"p"},"validator_weights")," structure for an era, then the account is bonded in that era."),(0,o.kt)("h2",{id:"losing-bid"},"A Losing Bid"),(0,o.kt)("p",null,"If a bid doesn't win a slot in the auction, it is too low. The resolution is to increase the bid amount. It is possible to submit additional bids, to increase the odds of winning a slot. It is also possible to encourage token holders to delegate stake to you for bonding."),(0,o.kt)("h2",{id:"avoiding-ejection"},"Avoiding Ejection"),(0,o.kt)("p",null,"To stay bonded and avoid ejection, each validator must keep their node running and in sync with the rest of the network. To recover from ejection, you will find more details ",(0,o.kt)("a",{parentName:"p",href:"/operators/becoming-a-validator/recovering"},"here"),"."),(0,o.kt)("h2",{id:"withdrawing-a-bid"},"Withdrawing a Bid"),(0,o.kt)("p",null,"Follow the steps in ",(0,o.kt)("a",{parentName:"p",href:"/operators/becoming-a-validator/unbonding"},"Unbonding")," to withdraw a bid."))}b.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/de7cb1a1.66494672.js b/assets/js/de7cb1a1.66494672.js deleted file mode 100644 index 51557f1710..0000000000 --- a/assets/js/de7cb1a1.66494672.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5153],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),p=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=p(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},k=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(n),k=r,h=u["".concat(c,".").concat(k)]||u[k]||d[k]||o;return n?a.createElement(h,i(i({ref:t},l),{},{components:n})):a.createElement(h,i({ref:t},l))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=k;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var p=2;psecret_key.pem file",id:"generating-the-secret_keypem-file",level:4},{value:"Generating public keys from the secret_key.pem file",id:"generating-public-keys-from-the-secret_keypem-file",level:4},{value:"Generating an Account Hash",id:"generating-an-account-hash",level:2},{value:"Finding the Main Purse URef",id:"purse-uref",level:2},{value:"Using the Casper CLI client",id:"using-the-casper-cli-client",level:3},{value:"Using a block explorer",id:"using-a-block-explorer",level:3}],d={toc:u},k="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)(k,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"accounts-and-cryptographic-keys"},"Accounts and Cryptographic Keys"),(0,o.kt)("p",null,"The Casper blockchain uses an on-chain ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"account-based model"),", uniquely identified by an ",(0,o.kt)("inlineCode",{parentName:"p"},"AccountHash")," derived from a specific ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey"),". The ",(0,o.kt)("inlineCode",{parentName:"p"},"AccountHash")," is a 32-byte hash derived from any of the supported ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey")," variants below to standardize keys that can vary in length."),(0,o.kt)("p",null,"By default, a transactional interaction with the blockchain takes the form of a ",(0,o.kt)("inlineCode",{parentName:"p"},"Deploy")," cryptographically signed by the key-pair corresponding to the ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey")," used to create the account."),(0,o.kt)("p",null,"The Casper platform supports two types of keys for creating accounts and signing transactions:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#eddsa-keys"},"Ed25519")," keys, which use the Edwards-curve Digital Signature Algorithm (EdDSA) and are 66 bytes long"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#ecdsa-keys"},"Secp256k1")," keys, which use the Elliptic Curve Digital Signature Algorithm (ECDSA) with the P-256 curve; they are 68 bytes long and are also found on the Ethereum blockchain")),(0,o.kt)("p",null,"You can generate keys using both formats, and it is also possible to ",(0,o.kt)("a",{parentName:"p",href:"#working-with-existing-ethereum-keys"},"work with existing Ethereum keys"),"."),(0,o.kt)("p",null,"You can also ",(0,o.kt)("a",{parentName:"p",href:"#generating-an-account-hash"},"generate an account hash")," from a public key with the Casper command-line client."),(0,o.kt)("h2",{id:"creating-accounts-and-keys"},"Creating Accounts and Keys"),(0,o.kt)("p",null,"When you create an account on the Casper blockchain, a cryptographic key-pair will be created when using either the ",(0,o.kt)("a",{parentName:"p",href:"#option-1-key-generation-using-the-casper-client"},"Casper command-line client")," or a block explorer."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"SAVE your keys to a safe place, preferably offline.")),(0,o.kt)("h3",{id:"option-1-key-generation-using-the-casper-client"},"Option 1: Generating keys using the Casper Client"),(0,o.kt)("p",null,"This option describes how you can use the Casper command-line client to set up an account using either key type."),(0,o.kt)("h4",{id:"eddsa-keys"},"EdDSA Keys"),(0,o.kt)("p",null,"The command-line client generates EdDSA keys by default. Use the command below to create the account."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir ed25519-keys\ncasper-client keygen ed25519-keys/\ntree ed25519-keys/\n")),(0,o.kt)("p",null,"Sample output of the ",(0,o.kt)("inlineCode",{parentName:"p"},"tree")," command shows the contents of the ",(0,o.kt)("em",{parentName:"p"},"ed25519-keys")," folder:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"ed25519-keys/\n\u251c\u2500\u2500 public_key.pem\n\u251c\u2500\u2500 public_key_hex\n\u2514\u2500\u2500 secret_key.pem\n\n0 directories, 3 files\n")),(0,o.kt)("p",null,"Here are some details about the files generated:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key.pem")," is a ",(0,o.kt)("em",{parentName:"li"},"PEM"),"-encoded public key"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key_hex")," is a hexadecimal-encoded string of the public key"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret_key.pem")," is the ",(0,o.kt)("em",{parentName:"li"},"PEM"),"-encoded secret key")),(0,o.kt)("p",null,"The public-key-hex for ",(0,o.kt)("inlineCode",{parentName:"p"},"Ed25519")," keys starts with 01 and is 66 bytes long:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cat ed25519-keys/public_key_hex\n011724c5c8e2404ca01c872e1bbd9202a0114e5d143760f685086a5cffe261dabd\n")),(0,o.kt)("h4",{id:"ecdsa-keys"},"ECDSA Keys"),(0,o.kt)("p",null,"To create ",(0,o.kt)("inlineCode",{parentName:"p"},"Secp256k1")," keys, which use the ECDSA algorithm with the P-256 curve, follow these steps:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir secp256k1-keys\ncasper-client keygen -a secp256k1 secp256k1-keys/\ntree secp256k1-keys/\n")),(0,o.kt)("p",null,"Sample output of the ",(0,o.kt)("inlineCode",{parentName:"p"},"tree")," command shows the contents of the ",(0,o.kt)("em",{parentName:"p"},"secp256k1-keys")," folder:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"secp256k1-keys/\n\u251c\u2500\u2500 public_key.pem\n\u251c\u2500\u2500 public_key_hex\n\u2514\u2500\u2500 secret_key.pem\n\n0 directories, 3 files\n")),(0,o.kt)("p",null,"The public-key-hex for ",(0,o.kt)("inlineCode",{parentName:"p"},"Secp256k1")," keys starts with 02 and is 68 bytes long:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cat secp256k1-keys/public_key_hex\n020287e1a79d0d9f3196391808a8b3e5007895f43cde679e4c960e7e9b92841bb98d\n")),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"After generating keys for the account, you may add funds to the account's purse to finish the account creation process.")),(0,o.kt)("h3",{id:"option-2-key-generation-using-a-block-explorer"},"Option 2: Generating keys using a block explorer"),(0,o.kt)("p",null,"This option is available on networks that have a block explorer."),(0,o.kt)("p",null,"For instance, on the official Testnet, the ",(0,o.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"CSPR.live")," block explorer is available, and the following instructions assume you are using it."),(0,o.kt)("p",null,"Start by creating an account using the ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/"},"Casper Wallet"),", ",(0,o.kt)("a",{parentName:"p",href:"https://support.ledger.com/hc/en-us/articles/4416379141009-Casper-CSPR-?support=true"},"Ledger"),", or ",(0,o.kt)("a",{parentName:"p",href:"https://casper.tor.us/"},"Torus Wallet"),"."),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"The Casper Signer has been replaced with the Casper Wallet and will be deprecated. We recommend migrating all your Casper accounts to the Casper Wallet as outlined ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/user-guide/signer-user-start-here"},"here"),".")),(0,o.kt)("h2",{id:"funding-your-account"},"Funding your Account"),(0,o.kt)("p",null,"Once you create your account, you can ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#funding-an-account"},"fund the account's main purse")," to finish the process of setting it up."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Until you fund your account's main purse, it does not exist on the blockchain.")),(0,o.kt)("h2",{id:"working-with-existing-ethereum-keys"},"Working with Existing Ethereum Keys"),(0,o.kt)("p",null,"You can also use existing Ethereum keys in Casper. Here is an example set of Ethereum keys and their corresponding address:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Address:0x7863B6F7232D99FF80B74E4C8BB3BEE3BDE0291F\nPublic key:0470fecd1f7ae5c1cd53a52c4ca88cd5b76c2926d7e1d831addaa2a64bea9cc3ede6a8e9981c609ee7ab7e3fa37ba914f2fc52f6eea9b746b6fe663afa96750d66\nPrivate key:29773906aef3ee1f5868371fd7c50f9092205df26f60e660cafacbf2b95fe086\n")),(0,o.kt)("p",null,"To use existing Ethereum keys, the Casper virtual machine (VM) needs to know that the key is a ",(0,o.kt)("inlineCode",{parentName:"p"},"Secp256k1")," type. To achieve this, we will prefix the public key hex with 02, as shown in the example below."),(0,o.kt)("p",null,"The Casper command-line client provides an example of how this works."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example"),":"),(0,o.kt)("p",null,"The following transaction sends 10 CSPR."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client transfer \\\n--transfer-id 1234567 \\\n--node-address http://localhost:7777 \\\n--chain-name casper \\\n--target-account 020470fecd1f7ae5c1cd53a52c4ca88cd5b76c2926d7e1d831addaa2a64bea9cc3ede6a8e9981c609ee7ab7e3fa37ba914f2fc52f6eea9b746b6fe663afa96750d66 \\\n--amount 10000000000 \\\n--secret-key \\\n--payment-amount 100000000\n")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"The payment amount varies based on each deploy and network ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),".")),(0,o.kt)("p",null,"The Casper command-line client requires the secret key in ",(0,o.kt)("em",{parentName:"p"},"PEM")," format to send a Deploy from this account. If you want to use existing Ethereum keys with the command-line client, a conversion to ",(0,o.kt)("em",{parentName:"p"},"PEM")," format is needed."),(0,o.kt)("p",null,"The following example is a JS script that generates a ",(0,o.kt)("em",{parentName:"p"},"PEM")," file, using a ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/stacks-network/key-encoder-js"},"key encoder")," and Node.js. To install these components, do the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install nodejs\nnpm install key-encoder\n")),(0,o.kt)("p",null,"Then create the JS script ",(0,o.kt)("em",{parentName:"p"},"convert-to-pem.js")," using ",(0,o.kt)("em",{parentName:"p"},"vi")," or ",(0,o.kt)("em",{parentName:"p"},"nano"),", and include this content:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'var KeyEncoder = require("key-encoder"),\n keyEncoder = new KeyEncoder.default("secp256k1");\nlet priv_hex = "THE SECRET KEY TO ENCODE";\nlet priv_pem = keyEncoder.encodePrivate(priv_hex, "raw", "pem");\nconsole.log(priv_pem);\n')),(0,o.kt)("p",null,"Then run the script using Node.js and name the secret key."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"node convert-to-pem.js > eth-secret.pem\n")),(0,o.kt)("p",null,"To view the secret key, use ",(0,o.kt)("inlineCode",{parentName:"p"},"cat "),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cat eth-secret.pem\n")),(0,o.kt)("p",null,"Below is the sample output showing the contents of the secret key."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIBjXY+7xZagzTjL4p8bGWS8FPRcW13mgytdu5c3e556MoAcGBSuBBAAK\noUQDQgAEpV4dVaPeAEaH0VXrQtLzjpGt1pui1q08311em6wDCchGNjzsnOY7stGF\ntlKF2V5RFQn4rzkwipSYnrqaPf1pTA==\n-----END EC PRIVATE KEY-----\n")),(0,o.kt)("h3",{id:"option-3-generating-keys-using-openssl"},"Option 3: Generating keys using OpenSSL"),(0,o.kt)("p",null,"You can generate keys without the Casper client using the ",(0,o.kt)("a",{parentName:"p",href:"https://www.openssl.org/"},"openssl")," cryptography toolkit. The commands below are valid only for generating Ed25519 keys on a Linux operating system."),(0,o.kt)("h4",{id:"generating-the-secret_keypem-file"},"Generating the ",(0,o.kt)("inlineCode",{parentName:"h4"},"secret_key.pem")," file"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"openssl genpkey -algorithm ed25519 -out secret_key.pem\n")),(0,o.kt)("h4",{id:"generating-public-keys-from-the-secret_keypem-file"},"Generating public keys from the ",(0,o.kt)("inlineCode",{parentName:"h4"},"secret_key.pem")," file"),(0,o.kt)("p",null,"For default Ed25519 keys, you can generate the ",(0,o.kt)("inlineCode",{parentName:"p"},"public_key.pem")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"public_key_hex")," using these commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'openssl pkey -in secret_key.pem -pubout -out public_key.pem\n\n{ echo -n 01; openssl pkey -outform DER -pubout -in "secret_key.pem" | tail -c +13 | openssl base64 | openssl base64 -d | hexdump -ve \'/1 "%02x" \' | tr -d "/n"; } > public_key_hex\n')),(0,o.kt)("h2",{id:"generating-an-account-hash"},"Generating an Account Hash"),(0,o.kt)("p",null,"To generate the account hash for a public key, use the ",(0,o.kt)("em",{parentName:"p"},"account-address")," option of the Casper client. The argument for the ",(0,o.kt)("em",{parentName:"p"},"public-key")," must be a properly formatted public key. The public key may also be read from a file, which should be one of the two files generated via the ",(0,o.kt)("em",{parentName:"p"},"keygen")," command: ",(0,o.kt)("em",{parentName:"p"},"public_key_hex")," or ",(0,o.kt)("em",{parentName:"p"},"public_key.pem"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client account-address --public-key \n")),(0,o.kt)("h2",{id:"purse-uref"},"Finding the Main Purse URef"),(0,o.kt)("p",null,"You can use the Casper CLI client or a block explorer to find the URef identifying an account's main purse."),(0,o.kt)("h3",{id:"using-the-casper-cli-client"},"Using the Casper CLI client"),(0,o.kt)("p",null,"With the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client"),", use the ",(0,o.kt)("inlineCode",{parentName:"p"},"get-account-info")," subcommand."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-account-info \\\n--node-address \\\n--public-key \n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public-key")," - This must be a properly formatted public key. The public key may instead be read in from a file, in which case, enter the path to the file as the argument. The file should be one of the two public key files generated via the ",(0,o.kt)("inlineCode",{parentName:"li"},"keygen"),' subcommand; "public_key_hex" or "public_key.pem"')),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Sample command and output"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client get-account-info --node-address http://65.21.75.254:7777 --public-key 0202ceafc0aa35f5a7bdda22f65c046b9b30b858459e18d3670f035839ad887fe5db\n{\n "id": -2018234245556346849,\n "jsonrpc": "2.0",\n "result": {\n "account": {\n "account_hash": "account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34",\n "weight": 1\n }\n ],\n "main_purse": "uref-974019c976b5f26412ce486158d2431967af35d91387dae8cbcd43c20fce6452-007",\n "named_keys": []\n },\n "api_version": "1.4.15",\n "merkle_proof": "[29712 hex chars]"\n }\n}\n\n'))),(0,o.kt)("p",null,"Run the following help command for more details:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-account-info --help\n")),(0,o.kt)("h3",{id:"using-a-block-explorer"},"Using a block explorer"),(0,o.kt)("p",null,"Using the block explorer for ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"Mainnet")," or ",(0,o.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"Testnet"),", open the Account in question, and expand the ",(0,o.kt)("inlineCode",{parentName:"p"},"Raw Data")," section. Look for the ",(0,o.kt)("inlineCode",{parentName:"p"},"main_purse")," field and find the corresponding URef. If you do not see data in the ",(0,o.kt)("inlineCode",{parentName:"p"},"Raw Data")," section, then the account has not been funded yet."),(0,o.kt)("p",{align:"center"},(0,o.kt)("img",{src:"/image/design/main_purse_uref.png",alt:"Image showing an account's main purse",width:"500"})))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/de7cb1a1.9816e830.js b/assets/js/de7cb1a1.9816e830.js new file mode 100644 index 0000000000..88a0492b28 --- /dev/null +++ b/assets/js/de7cb1a1.9816e830.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5153],{3905:function(e,t,n){n.d(t,{Zo:function(){return l},kt:function(){return h}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=a.createContext({}),p=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=p(e.components);return a.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},k=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=p(n),k=r,h=u["".concat(c,".").concat(k)]||u[k]||d[k]||o;return n?a.createElement(h,i(i({ref:t},l),{},{components:n})):a.createElement(h,i({ref:t},l))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=k;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var p=2;psecret_key.pem file",id:"generating-the-secret_keypem-file",level:4},{value:"Generating public keys from the secret_key.pem file",id:"generating-public-keys-from-the-secret_keypem-file",level:4},{value:"Generating an Account Hash",id:"generating-an-account-hash",level:2},{value:"Finding the Main Purse URef",id:"purse-uref",level:2},{value:"Using the Casper CLI client",id:"using-the-casper-cli-client",level:3},{value:"Using a block explorer",id:"using-a-block-explorer",level:3}],d={toc:u},k="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,i);return(0,o.kt)(k,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"accounts-and-cryptographic-keys"},"Accounts and Cryptographic Keys"),(0,o.kt)("p",null,"The Casper blockchain uses an on-chain ",(0,o.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#accounts-head"},"account-based model"),", uniquely identified by an ",(0,o.kt)("inlineCode",{parentName:"p"},"AccountHash")," derived from a specific ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey"),". The ",(0,o.kt)("inlineCode",{parentName:"p"},"AccountHash")," is a 32-byte hash derived from any of the supported ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey")," variants below to standardize keys that can vary in length."),(0,o.kt)("p",null,"By default, a transactional interaction with the blockchain takes the form of a ",(0,o.kt)("inlineCode",{parentName:"p"},"Deploy")," cryptographically signed by the key-pair corresponding to the ",(0,o.kt)("inlineCode",{parentName:"p"},"PublicKey")," used to create the account."),(0,o.kt)("p",null,"The Casper platform supports two types of keys for creating accounts and signing transactions:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#eddsa-keys"},"Ed25519")," keys, which use the Edwards-curve Digital Signature Algorithm (EdDSA) and are 66 bytes long"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"#ecdsa-keys"},"Secp256k1")," keys, which use the Elliptic Curve Digital Signature Algorithm (ECDSA) with the P-256 curve; they are 68 bytes long and are also found on the Ethereum blockchain")),(0,o.kt)("p",null,"You can generate keys using both formats, and it is also possible to ",(0,o.kt)("a",{parentName:"p",href:"#working-with-existing-ethereum-keys"},"work with existing Ethereum keys"),"."),(0,o.kt)("p",null,"You can also ",(0,o.kt)("a",{parentName:"p",href:"#generating-an-account-hash"},"generate an account hash")," from a public key with the Casper command-line client."),(0,o.kt)("h2",{id:"creating-accounts-and-keys"},"Creating Accounts and Keys"),(0,o.kt)("p",null,"When you create an account on the Casper blockchain, a cryptographic key-pair will be created when using either the ",(0,o.kt)("a",{parentName:"p",href:"#option-1-key-generation-using-the-casper-client"},"Casper command-line client")," or a block explorer."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"SAVE your keys to a safe place, preferably offline.")),(0,o.kt)("h3",{id:"option-1-key-generation-using-the-casper-client"},"Option 1: Generating keys using the Casper Client"),(0,o.kt)("p",null,"This option describes how you can use the Casper command-line client to set up an account using either key type."),(0,o.kt)("h4",{id:"eddsa-keys"},"EdDSA Keys"),(0,o.kt)("p",null,"The command-line client generates EdDSA keys by default. Use the command below to create the account."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir ed25519-keys\ncasper-client keygen ed25519-keys/\ntree ed25519-keys/\n")),(0,o.kt)("p",null,"Sample output of the ",(0,o.kt)("inlineCode",{parentName:"p"},"tree")," command shows the contents of the ",(0,o.kt)("em",{parentName:"p"},"ed25519-keys")," folder:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"ed25519-keys/\n\u251c\u2500\u2500 public_key.pem\n\u251c\u2500\u2500 public_key_hex\n\u2514\u2500\u2500 secret_key.pem\n\n0 directories, 3 files\n")),(0,o.kt)("p",null,"Here are some details about the files generated:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key.pem")," is a ",(0,o.kt)("em",{parentName:"li"},"PEM"),"-encoded public key"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public_key_hex")," is a hexadecimal-encoded string of the public key"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"secret_key.pem")," is the ",(0,o.kt)("em",{parentName:"li"},"PEM"),"-encoded secret key")),(0,o.kt)("p",null,"The public-key-hex for ",(0,o.kt)("inlineCode",{parentName:"p"},"Ed25519")," keys starts with 01 and is 66 bytes long:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cat ed25519-keys/public_key_hex\n011724c5c8e2404ca01c872e1bbd9202a0114e5d143760f685086a5cffe261dabd\n")),(0,o.kt)("h4",{id:"ecdsa-keys"},"ECDSA Keys"),(0,o.kt)("p",null,"To create ",(0,o.kt)("inlineCode",{parentName:"p"},"Secp256k1")," keys, which use the ECDSA algorithm with the P-256 curve, follow these steps:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir secp256k1-keys\ncasper-client keygen -a secp256k1 secp256k1-keys/\ntree secp256k1-keys/\n")),(0,o.kt)("p",null,"Sample output of the ",(0,o.kt)("inlineCode",{parentName:"p"},"tree")," command shows the contents of the ",(0,o.kt)("em",{parentName:"p"},"secp256k1-keys")," folder:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"secp256k1-keys/\n\u251c\u2500\u2500 public_key.pem\n\u251c\u2500\u2500 public_key_hex\n\u2514\u2500\u2500 secret_key.pem\n\n0 directories, 3 files\n")),(0,o.kt)("p",null,"The public-key-hex for ",(0,o.kt)("inlineCode",{parentName:"p"},"Secp256k1")," keys starts with 02 and is 68 bytes long:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cat secp256k1-keys/public_key_hex\n020287e1a79d0d9f3196391808a8b3e5007895f43cde679e4c960e7e9b92841bb98d\n")),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"After generating keys for the account, you may add funds to the account's purse to finish the account creation process.")),(0,o.kt)("h3",{id:"option-2-key-generation-using-a-block-explorer"},"Option 2: Generating keys using a block explorer"),(0,o.kt)("p",null,"This option is available on networks that have a block explorer."),(0,o.kt)("p",null,"For instance, on the official Testnet, the ",(0,o.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"CSPR.live")," block explorer is available, and the following instructions assume you are using it."),(0,o.kt)("p",null,"Start by creating an account using the ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/"},"Casper Wallet"),", ",(0,o.kt)("a",{parentName:"p",href:"https://support.ledger.com/hc/en-us/articles/4416379141009-Casper-CSPR-?support=true"},"Ledger"),", or ",(0,o.kt)("a",{parentName:"p",href:"https://casper.tor.us/"},"Torus Wallet"),"."),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"The Casper Signer has been replaced with the Casper Wallet and will be deprecated. We recommend migrating all your Casper accounts to the Casper Wallet as outlined ",(0,o.kt)("a",{parentName:"p",href:"https://www.casperwallet.io/user-guide/signer-user-start-here"},"here"),".")),(0,o.kt)("h2",{id:"funding-your-account"},"Funding your Account"),(0,o.kt)("p",null,"Once you create your account, you can ",(0,o.kt)("a",{parentName:"p",href:"/developers/prerequisites#funding-an-account"},"fund the account's main purse")," to finish the process of setting it up."),(0,o.kt)("admonition",{type:"note"},(0,o.kt)("p",{parentName:"admonition"},"Until you fund your account's main purse, it does not exist on the blockchain.")),(0,o.kt)("h2",{id:"working-with-existing-ethereum-keys"},"Working with Existing Ethereum Keys"),(0,o.kt)("p",null,"You can also use existing Ethereum keys in Casper. Here is an example set of Ethereum keys and their corresponding address:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"Address:0x7863B6F7232D99FF80B74E4C8BB3BEE3BDE0291F\nPublic key:0470fecd1f7ae5c1cd53a52c4ca88cd5b76c2926d7e1d831addaa2a64bea9cc3ede6a8e9981c609ee7ab7e3fa37ba914f2fc52f6eea9b746b6fe663afa96750d66\nPrivate key:29773906aef3ee1f5868371fd7c50f9092205df26f60e660cafacbf2b95fe086\n")),(0,o.kt)("p",null,"To use existing Ethereum keys, the Casper virtual machine (VM) needs to know that the key is a ",(0,o.kt)("inlineCode",{parentName:"p"},"Secp256k1")," type. To achieve this, we will prefix the public key hex with 02, as shown in the example below."),(0,o.kt)("p",null,"The Casper command-line client provides an example of how this works."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Example"),":"),(0,o.kt)("p",null,"The following transaction sends 10 CSPR."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client transfer \\\n--transfer-id 1234567 \\\n--node-address http://localhost:7777 \\\n--chain-name casper \\\n--target-account 020470fecd1f7ae5c1cd53a52c4ca88cd5b76c2926d7e1d831addaa2a64bea9cc3ede6a8e9981c609ee7ab7e3fa37ba914f2fc52f6eea9b746b6fe663afa96750d66 \\\n--amount 10000000000 \\\n--secret-key \\\n--payment-amount 100000000\n")),(0,o.kt)("admonition",{type:"tip"},(0,o.kt)("p",{parentName:"admonition"},"The payment amount varies based on each deploy and network ",(0,o.kt)("a",{parentName:"p",href:"/concepts/glossary/C#chainspec"},"chainspec"),".")),(0,o.kt)("p",null,"The Casper command-line client requires the secret key in ",(0,o.kt)("em",{parentName:"p"},"PEM")," format to send a Deploy from this account. If you want to use existing Ethereum keys with the command-line client, a conversion to ",(0,o.kt)("em",{parentName:"p"},"PEM")," format is needed."),(0,o.kt)("p",null,"The following example is a JS script that generates a ",(0,o.kt)("em",{parentName:"p"},"PEM")," file, using a ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/stacks-network/key-encoder-js"},"key encoder")," and Node.js. To install these components, do the following:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install nodejs\nnpm install key-encoder\n")),(0,o.kt)("p",null,"Then create the JS script ",(0,o.kt)("em",{parentName:"p"},"convert-to-pem.js")," using ",(0,o.kt)("em",{parentName:"p"},"vi")," or ",(0,o.kt)("em",{parentName:"p"},"nano"),", and include this content:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-javascript"},'var KeyEncoder = require("key-encoder"),\n keyEncoder = new KeyEncoder.default("secp256k1");\nlet priv_hex = "THE SECRET KEY TO ENCODE";\nlet priv_pem = keyEncoder.encodePrivate(priv_hex, "raw", "pem");\nconsole.log(priv_pem);\n')),(0,o.kt)("p",null,"Then run the script using Node.js and name the secret key."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"node convert-to-pem.js > eth-secret.pem\n")),(0,o.kt)("p",null,"To view the secret key, use ",(0,o.kt)("inlineCode",{parentName:"p"},"cat "),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cat eth-secret.pem\n")),(0,o.kt)("p",null,"Below is the sample output showing the contents of the secret key."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIBjXY+7xZagzTjL4p8bGWS8FPRcW13mgytdu5c3e556MoAcGBSuBBAAK\noUQDQgAEpV4dVaPeAEaH0VXrQtLzjpGt1pui1q08311em6wDCchGNjzsnOY7stGF\ntlKF2V5RFQn4rzkwipSYnrqaPf1pTA==\n-----END EC PRIVATE KEY-----\n")),(0,o.kt)("h3",{id:"option-3-generating-keys-using-openssl"},"Option 3: Generating keys using OpenSSL"),(0,o.kt)("p",null,"You can generate keys without the Casper client using the ",(0,o.kt)("a",{parentName:"p",href:"https://www.openssl.org/"},"openssl")," cryptography toolkit. The commands below are valid only for generating Ed25519 keys on a Linux operating system."),(0,o.kt)("h4",{id:"generating-the-secret_keypem-file"},"Generating the ",(0,o.kt)("inlineCode",{parentName:"h4"},"secret_key.pem")," file"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"openssl genpkey -algorithm ed25519 -out secret_key.pem\n")),(0,o.kt)("h4",{id:"generating-public-keys-from-the-secret_keypem-file"},"Generating public keys from the ",(0,o.kt)("inlineCode",{parentName:"h4"},"secret_key.pem")," file"),(0,o.kt)("p",null,"For default Ed25519 keys, you can generate the ",(0,o.kt)("inlineCode",{parentName:"p"},"public_key.pem")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"public_key_hex")," using these commands:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'openssl pkey -in secret_key.pem -pubout -out public_key.pem\n\n{ echo -n 01; openssl pkey -outform DER -pubout -in "secret_key.pem" | tail -c +13 | openssl base64 | openssl base64 -d | hexdump -ve \'/1 "%02x" \' | tr -d "/n"; } > public_key_hex\n')),(0,o.kt)("h2",{id:"generating-an-account-hash"},"Generating an Account Hash"),(0,o.kt)("p",null,"To generate the account hash for a public key, use the ",(0,o.kt)("em",{parentName:"p"},"account-address")," option of the Casper client. The argument for the ",(0,o.kt)("em",{parentName:"p"},"public-key")," must be a properly formatted public key. The public key may also be read from a file, which should be one of the two files generated via the ",(0,o.kt)("em",{parentName:"p"},"keygen")," command: ",(0,o.kt)("em",{parentName:"p"},"public_key_hex")," or ",(0,o.kt)("em",{parentName:"p"},"public_key.pem"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client account-address --public-key \n")),(0,o.kt)("h2",{id:"purse-uref"},"Finding the Main Purse URef"),(0,o.kt)("p",null,"You can use the Casper CLI client or a block explorer to find the URef identifying an account's main purse."),(0,o.kt)("h3",{id:"using-the-casper-cli-client"},"Using the Casper CLI client"),(0,o.kt)("p",null,"With the ",(0,o.kt)("inlineCode",{parentName:"p"},"casper-client"),", use the ",(0,o.kt)("inlineCode",{parentName:"p"},"get-account-info")," subcommand."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-account-info \\\n--node-address \\\n--public-key \n")),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777"),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"public-key")," - This must be a properly formatted public key. The public key may instead be read in from a file, in which case, enter the path to the file as the argument. The file should be one of the two public key files generated via the ",(0,o.kt)("inlineCode",{parentName:"li"},"keygen"),' subcommand; "public_key_hex" or "public_key.pem"')),(0,o.kt)("details",null,(0,o.kt)("summary",null,"Sample command and output"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client get-account-info --node-address http://65.21.75.254:7777 --public-key 0202ceafc0aa35f5a7bdda22f65c046b9b30b858459e18d3670f035839ad887fe5db\n{\n "id": -2018234245556346849,\n "jsonrpc": "2.0",\n "result": {\n "account": {\n "account_hash": "account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34",\n "action_thresholds": {\n "deployment": 1,\n "key_management": 1\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34",\n "weight": 1\n }\n ],\n "main_purse": "uref-974019c976b5f26412ce486158d2431967af35d91387dae8cbcd43c20fce6452-007",\n "named_keys": []\n },\n "api_version": "1.4.15",\n "merkle_proof": "[29712 hex chars]"\n }\n}\n\n'))),(0,o.kt)("p",null,"Run the following help command for more details:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-account-info --help\n")),(0,o.kt)("h3",{id:"using-a-block-explorer"},"Using a block explorer"),(0,o.kt)("p",null,"Using the block explorer for ",(0,o.kt)("a",{parentName:"p",href:"https://cspr.live/"},"Mainnet")," or ",(0,o.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/"},"Testnet"),", open the Account in question, and expand the ",(0,o.kt)("inlineCode",{parentName:"p"},"Raw Data")," section. Look for the ",(0,o.kt)("inlineCode",{parentName:"p"},"main_purse")," field and find the corresponding URef. If you do not see data in the ",(0,o.kt)("inlineCode",{parentName:"p"},"Raw Data")," section, then the account has not been funded yet."),(0,o.kt)("p",{align:"center"},(0,o.kt)("img",{src:"/image/design/main_purse_uref.png",alt:"Image showing an account's main purse",width:"500"})))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e00654fa.08fe7795.js b/assets/js/e00654fa.08fe7795.js new file mode 100644 index 0000000000..970c44a16d --- /dev/null +++ b/assets/js/e00654fa.08fe7795.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7698],{3905:function(e,t,a){a.d(t,{Zo:function(){return d},kt:function(){return h}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},d=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=c(a),g=r,h=p["".concat(l,".").concat(g)]||p[g]||u[g]||o;return a?n.createElement(h,i(i({ref:t},d),{},{components:a})):n.createElement(h,i({ref:t},d))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),c=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},d=function(e){var t=c(e.components);return n.createElement(l.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),p=c(a),g=r,h=p["".concat(l,".").concat(g)]||p[g]||u[g]||o;return a?n.createElement(h,i(i({ref:t},d),{},{components:a})):n.createElement(h,i({ref:t},d))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=g;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;c=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),c=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},i=function(e){var t=c(e.components);return a.createElement(p.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,p=e.parentName,i=o(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,y=u["".concat(p,".").concat(m)]||u[m]||d[m]||s;return n?a.createElement(y,l(l({ref:t},i),{},{components:n})):a.createElement(y,l({ref:t},i))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,l=new Array(s);l[0]=m;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[u]="string"==typeof e?e:r,l[1]=o;for(var c=2;c child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:u(n);return function(e){var t=(0,c.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function y(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,s=(0,o.k6)(),l=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,p._X)(l),(0,r.useCallback)((function(e){if(l){var t=new URLSearchParams(s.location.search);t.set(l,e),s.replace(Object.assign({},s.location,{search:t.toString()}))}}),[l,s])]}function k(e){var t,n,a,s,l=e.defaultValue,o=e.queryString,p=void 0!==o&&o,c=e.groupId,u=d(e),k=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:l,tabValues:u})})),h=k[0],b=k[1],f=y({queryString:p,groupId:c}),g=f[0],_=f[1],v=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:c}.groupId),n=(0,i.Nk)(t),a=n[0],s=n[1],[a,(0,r.useCallback)((function(e){t&&s.set(e)}),[t,s])]),w=v[0],C=v[1],N=function(){var e=null!=g?g:w;return m({value:e,tabValues:u})?e:null}();return(0,r.useLayoutEffect)((function(){N&&b(N)}),[N]),{selectedValue:h,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:u}))throw new Error("Can't select invalid tab value="+e);b(e),_(e),C(e)}),[_,C,u]),tabValues:u}}var h=n(2389),b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function f(e){var t=e.className,n=e.block,o=e.selectedValue,p=e.selectValue,c=e.tabValues,i=[],u=(0,l.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,n=i.indexOf(t),a=c[n].value;a!==o&&(u(t),p(a))},m=function(e){var t,n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var a,r=i.indexOf(e.currentTarget)+1;n=null!=(a=i[r])?a:i[0];break;case"ArrowLeft":var s,l=i.indexOf(e.currentTarget)-1;n=null!=(s=i[l])?s:i[i.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.Z)("tabs",{"tabs--block":n},t)},c.map((function(e){var t=e.value,n=e.label,l=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:o===t?0:-1,"aria-selected":o===t,key:t,ref:function(e){return i.push(e)},onKeyDown:m,onClick:d},l,{className:(0,s.Z)("tabs__item",b.tabItem,null==l?void 0:l.className,{"tabs__item--active":o===t})}),null!=n?n:t)})))}function g(e){var t=e.lazy,n=e.children,a=e.selectedValue,s=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var l=s.find((function(e){return e.props.value===a}));return l?(0,r.cloneElement)(l,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},s.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function _(e){var t=k(e);return r.createElement("div",{className:(0,s.Z)("tabs-container",b.tabList)},r.createElement(f,(0,a.Z)({},e,t)),r.createElement(g,(0,a.Z)({},e,t)))}function v(e){var t=(0,h.Z)();return r.createElement(_,(0,a.Z)({key:String(t)},e))}},4139:function(e,t,n){n.r(t),n.d(t,{assets:function(){return d},contentTitle:function(){return i},default:function(){return h},frontMatter:function(){return c},metadata:function(){return u},toc:function(){return m}});var a=n(7462),r=n(3366),s=(n(7294),n(3905)),l=n(4866),o=n(5162),p=["components"],c={},i="SDK Client Library Usage",u={unversionedId:"developers/dapps/sdk/client-library-usage",id:"developers/dapps/sdk/client-library-usage",title:"SDK Client Library Usage",description:"Installing the SDKs",source:"@site/source/docs/casper/developers/dapps/sdk/client-library-usage.md",sourceDirName:"developers/dapps/sdk",slug:"/developers/dapps/sdk/client-library-usage",permalink:"/developers/dapps/sdk/client-library-usage",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/dapps/sdk/client-library-usage.md",tags:[],version:"current",lastUpdatedAt:1707229568,formattedLastUpdatedAt:"Feb 6, 2024",frontMatter:{},sidebar:"developers",previous:{title:"SDK Client Libraries",permalink:"/sdk"},next:{title:"JavaScript/TypeScript SDK",permalink:"/developers/dapps/sdk/script-sdk"}},d={},m=[{value:"Installing the SDKs",id:"installing-the-sdks",level:2},{value:"Creating Accounts",id:"creating-accounts",level:2},{value:"Creating new account keys",id:"creating-new-account-keys",level:3},{value:"Exporting the public key and account hash",id:"exporting-the-public-key-and-account-hash",level:3},{value:"Uploading the secret key from a file",id:"uploading-the-secret-key-from-a-file",level:3},{value:"Transferring CSPR",id:"transferring-cspr",level:2},{value:"Installing Contracts",id:"installing-contracts",level:2},{value:"Staking",id:"staking",level:2},{value:"Calling Contracts",id:"calling-contracts",level:2},{value:"Staking",id:"staking-1",level:2}],y={toc:m},k="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,p);return(0,s.kt)(k,(0,a.Z)({},y,n,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"sdk-client-library-usage"},"SDK Client Library Usage"),(0,s.kt)("h2",{id:"installing-the-sdks"},"Installing the SDKs"),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("p",null,"Use ",(0,s.kt)("inlineCode",{parentName:"p"},"npm")," or ",(0,s.kt)("inlineCode",{parentName:"p"},"yarn")," to install the ",(0,s.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/casper-js-sdk"},"casper-js-sdk")," package:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"npm install casper-js-sdk\n")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"yarn install casper-js-sdk\n"))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("p",null,"Use ",(0,s.kt)("a",{parentName:"p",href:"https://pypi.org/project/pip/"},(0,s.kt)("inlineCode",{parentName:"a"},"pip"))," to install the ",(0,s.kt)("a",{parentName:"p",href:"https://pypi.org/project/pycspr/"},"pycspr")," package:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"pip install pycspr\n"))),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("p",null,"Include the casper-client dependency to your ",(0,s.kt)("inlineCode",{parentName:"p"},"Cargo.toml"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},'[dependencies]\ncasper-client="1.5.1"\n')),(0,s.kt)("p",null,"and add it to your ",(0,s.kt)("inlineCode",{parentName:"p"},"main.rs"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"extern crate casper_client;\n")),(0,s.kt)("p",null,"Use types and methods from casper_client:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"use casper_client::transfer;\nuse casper_client::put_deploy;\n//...\n")),(0,s.kt)("p",null,"as casper_client functions are asynchronous, a tokyo runtime is necessary for testing:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},'[dependencies]\ntokio = { version = "^1.27.0", features = ["full"] }\n')))),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"creating-accounts"},"Creating Accounts"),(0,s.kt)("p",null,"You may use the SDKs to interact with accounts on a Casper network. Accounts can use either an Ed25519 or Secp256k1 digital signature scheme. See the ",(0,s.kt)("a",{parentName:"p",href:"/concepts/accounts-and-keys"},"Accounts and Cryptographic Keys")," page for more details."),(0,s.kt)("h3",{id:"creating-new-account-keys"},"Creating new account keys"),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { Keys } = require("casper-js-sdk");\nconst keypair = Keys.Ed25519.new();\nconst { publicKey, privateKey } = keypair;\n')),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"Ed25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"Secp256K1")," if you wish.")),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},"from pycspr.crypto import KeyAlgorithm, get_key_pair\nkeypair = get_key_pair(KeyAlgorithm.ED25519)\n")),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"ED25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"SECP256K1")," if you wish.")),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("p",null,"Create a keypair and write the files to a specified ",(0,s.kt)("inlineCode",{parentName:"p"},"PATH"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},' casper_client::keygen::generate_files("PATH", "ED25519", false).unwrap();\n')),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"ED25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"SECP256K1")," if you wish."))),(0,s.kt)("h3",{id:"exporting-the-public-key-and-account-hash"},"Exporting the public key and account hash"),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"keypair")," variable contains the private and public key pair for the account. You can use, read, or export the public key. You may also want access to the account hash, often used within smart contracts on a Casper network. The following methods show how to extract the public key and account hash."),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},"// Create a hexadecimal representation of the public key and account hash.\nconst publicKeyHex = publicKey.toHex();\nconst accountHashHex = publicKey.toAccountHashStr();\n")),(0,s.kt)("p",null,"Note that ",(0,s.kt)("inlineCode",{parentName:"p"},"accountHashHex"),' will be prefixed with the text "account-hash-".')),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},"import pycspr.crypto\n\npublicKeyBytes = keypair.account_key\npublicKeyHex = pycspr.crypto.cl_checksum.encode(publicKeyBytes)\naccountHashBytes = pycspr.crypto.cl_operations.get_account_hash(publicKeyBytes)\naccountHashHex = pycspr.crypto.cl_checksum.encode(accountHashBytes)\n")))),(0,s.kt)("h3",{id:"uploading-the-secret-key-from-a-file"},"Uploading the secret key from a file"),(0,s.kt)("p",null,"To use a specific account, you should not include the private key in the source code; instead, upload the account's secret key from a local file. Update the path to the file in the example below."),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { Keys } = require("casper-js-sdk");\nconst keypair = Keys.Ed25519.loadKeyPairFromPrivateFile("./secret_key.pem");\n')),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"Ed25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"Secp256K1")," if you wish.")),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\nkeypair = pycspr.parse_private_key(\n "./secret_key.pem",\n pycspr.crypto.KeyAlgorithm.ED25519\n)\n')),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"ED25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"SECP256K1")," if you wish.")),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("p",null,"In Rust, we don't explicitly import the private key as an object, but instead supply its path as an argument when calling functions:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'let deploy_params: casper_client::DeployStrParams = casper_client::DeployStrParams{\n secret_key:"./secret_key.pem",\n timestamp:"",\n ...\n};\n')))),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"transferring-cspr"},"Transferring CSPR"),(0,s.kt)("p",null,"Using the ",(0,s.kt)("inlineCode",{parentName:"p"},"keypair")," created ",(0,s.kt)("a",{parentName:"p",href:"#creating-accounts"},"above"),", you can sign a deploy that transfers CSPR."),(0,s.kt)("p",null,"Replace the ",(0,s.kt)("inlineCode",{parentName:"p"},"NODE_ADDRESS")," and corresponding RPC port with an active node on the network. You can find active online peers for Mainnet on ",(0,s.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"cspr.live")," and for Testnet on ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"testnet.cspr.live"),". The RPC port is usually ",(0,s.kt)("inlineCode",{parentName:"p"},"7777"),", but it depends on the network's configuration settings."),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { CasperClient, DeployUtil } = require("casper-js-sdk");\n\nconst casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst receipientPublicKeyHex = "01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c";\n\nconst amount = 2.5e9; // Minimum transfer: 2.5 CSPR\nlet deployParams = new DeployUtil.DeployParams(\n keypair.publicKey,\n "casper", // or "casper-test" for Testnet\n);\n\nconst session = DeployUtil.ExecutableDeployItem.newTransferWithOptionalTransferId(amount, recipientPublicKeyHex);\n\nconst payment = DeployUtil.standardPayment(0.1e9); // Gas payment in motes: 0.1 CSPR\nconst deploy = DeployUtil.makeDeploy(deployParams, session, payment);\nconst signedDeploy = DeployUtil.signDeploy(deploy, keypair);\n\nconsole.log(await casperClient.putDeploy(signedDeploy));\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\n\nclient = NodeClient(NodeConnection(host = "NODE_ADDRESS", port_rpc = 7777))\nrecipientPublicKeyHex = "01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c"\nrecipientPublicKeyBytes = pycspr.crypto.cl_checksum.decode(recipientPublicKeyHex)\n\ndeployParams = pycspr.create_deploy_parameters(\n account = keypair,\n chain_name = "casper" # or "casper-test" for Testnet\n)\n\ndeploy = pycspr.create_transfer(\n params = deployParams,\n amount = int(2.5e9), # Minimum transfer: 2.5 CSPR\n target = recipientPublicKeyBytes\n)\n\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n'))),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'extern crate casper_client;\nasync fn send_transfer(){\n let maybe_rpc_id: &str = "";\n let node_address: &str = "http://135.181.216.142:7777";\n let verbosity_level: u64 = 1;\n let amount: &str = "2500000000";\n let target_account: &str = recipient;\n let transfer_id: &str = "1";\n let deploy_params: casper_client::DeployStrParams = casper_client::DeployStrParams{\n secret_key:"./sk_testnet.pem",\n timestamp:"",\n ttl:"50s",\n gas_price:"1000000000",\n chain_name:"casper", // or "casper-test" for testnet\n dependencies: Vec::new(),\n session_account: "01daad67ebbcb725e02a1955a6617512b311435a21ca6d523085aa015d2d1b473a"\n\n };\n let recipient: &str = "0106ca7c39cd272dbf21a86eeb3b36b7c26e2e9b94af64292419f7862936bca2ca";\n let payment_params: casper_client::PaymentStrParams = casper_client::PaymentStrParams::with_amount(amount);\n let result = casper_client::transfer(maybe_rpc_id, node_address, verbosity_level, amount, target_account, transfer_id, deploy_params, payment_params).await.unwrap();\n println!("Deploy response: {:?}", result);\n}\n\n#[tokio::main]\nasync fn main(){\n send_transfer().await;\n}\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"installing-contracts"},"Installing Contracts"),(0,s.kt)("p",null,"To install a contract on the network, you need to sign and send a deploy containing the compiled Wasm."),(0,s.kt)("p",null,"Replace the ",(0,s.kt)("inlineCode",{parentName:"p"},"NODE_ADDRESS")," and corresponding RPC port with an active node on the network. You can find active online peers for Mainnet on ",(0,s.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"cspr.live")," and for Testnet on ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"testnet.cspr.live"),". The RPC port is usually ",(0,s.kt)("inlineCode",{parentName:"p"},"7777"),", but it depends on the network's configuration settings."),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { CasperClient, Contracts, RuntimeArgs, CLValueBuilder } = require("casper-js-sdk");\nconst fs = require("fs");\n\nconst casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst contract = new Contracts.Contract(casperClient);\n\nconst contractWasm = new Uint8Array(fs.readFileSync("/path/to/contract.wasm").buffer);\n\nconst runtimeArguments = RuntimeArgs.fromMap({\n argument: CLValueBuilder.string("Hello world!"),\n});\n\nconst deploy = contract.install(\n contractWasm,\n runtimeArguments,\n "10000000000", // Gas payment (10 CSPR)\n keypair.publicKey,\n "casper", // or "casper-test" for Testnet\n [keypair],\n);\n\nconsole.log(await casperClient.putDeploy(deploy));\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\nfrom pycspr.types import ModuleBytes, CL_String\n\nclient = NodeClient(NodeConnection(host = "NODE_ADDRESS", port_rpc = 7777))\n\ndeployParams = pycspr.create_deploy_parameters(\n account = keypair,\n chain_name = "casper" # or "casper-test" for Testnet\n)\npayment = pycspr.create_standard_payment(10000000000) # 10 CSPR\nsession = ModuleBytes(\n module_bytes = pycspr.read_wasm("/path/to/contract.wasm"),\n args = {\n "message": CL_String("Hello world!"),\n }\n)\n\ndeploy = pycspr.create_deploy(deployParams, payment, session)\n\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n'))),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'extern crate casper_client;\nasync fn put_deploy(){\n let maybe_rpc: &str = "";\n let verbosity: u64 = 1;\n let node_address: &str = "http://135.181.216.142:7777";\n let deploy_params: casper_client::DeployStrParams = casper_client::DeployStrParams{\n secret_key:"./sk_testnet.pem",\n timestamp:"",\n ttl:"50s",\n gas_price:"1000000000",\n chain_name:"casper", // or "casper-test"\n dependencies: Vec::new(),\n session_account: "01daad67ebbcb725e02a1955a6617512b311435a21ca6d523085aa015d2d1b473a"\n\n };\n // Without session args:\n // let session_args: Vec<&str> = Vec::new();\n // With session args:\n let mut session_args: Vec<&str> = Vec::new();\n session_args.push("argument:String=\'hello world\'");\n let session_params: casper_client::SessionStrParams = casper_client::SessionStrParams::with_path("./contract.wasm", session_args, "");\n let payment_params: casper_client::PaymentStrParams = casper_client::PaymentStrParams::with_amount("10000000000");\n let result = casper_client::put_deploy(maybe_rpc_id, node_address, verbosity_level, deploy_params, session_params, payment_params).await.unwrap();\n println!("Deploy response: {:?}", result);\n}\n\n#[tokio::main]\nasync fn main(){\n send_transfer().await;\n}\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."),(0,s.kt)("h2",{id:"staking"},"Staking"),(0,s.kt)("p",null,"Token staking is a fundamental aspect of the Casper Network, whereby users lock up tokens as collateral in exchange for the ability to participate in the blockchain's consensus mechanism and earn rewards. This delegated Proof-of-Stake consensus mechanism is crucial for the network's effective operation. With the aid of any of the Casper SDKs, you can delegate your tokens to validators and participate in staking on the network."),(0,s.kt)("p",null,"The delegation functionality is available as a smart contract, which can be found in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository. To delegate tokens, first clone the repository:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-network/casper-node.git\ncd casper-node/\n")),(0,s.kt)("p",null,"Then compile the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/smart_contracts/contracts/client/delegate/src/main.rs"},"delegate contract"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"make setup-rs\nmake build-contract-rs/delegate\n")),(0,s.kt)("p",null,"Now, assuming that you cloned ",(0,s.kt)("inlineCode",{parentName:"p"},"casper-node")," from your project's root directory, ",(0,s.kt)("inlineCode",{parentName:"p"},"cd")," back into it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"cd ../\n")),(0,s.kt)("p",null,"Now in your dApp's backend (or standalone script), load the ",(0,s.kt)("em",{parentName:"p"},"delegate.wasm"),' file into memory and deploy it with the arguments "amount", "delegator", and "validator" included.'),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { CasperClient, Contracts, RuntimeArgs, CLValueBuilder, CLPublicKey } = require("casper-js-sdk");\nconst fs = require("fs");\n\nconst casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst contract = new Contracts.Contract(casperClient);\n\nconst contractWasm = new Uint8Array(fs.readFileSync("./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm").buffer);\n\nconst runtimeArguments = RuntimeArgs.fromMap({\n amount: CLValueBuilder.u512(500e9), // Minimum delegation amount: 500 CSPR\n delegator: keypair.publicKey,\n validator: CLPublicKey.fromHex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c"),\n});\n\nconst deploy = contract.install(\n contractWasm,\n runtimeArguments,\n "5000000000", // Gas payment (5 CSPR)\n keypair.publicKey,\n "casper", // or "casper-test" for testnet\n [keypair],\n);\n\n(async () => {\n console.log(await casperClient.putDeploy(deploy));\n})();\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\n\nvalidator_public_key = pycspr.factory.accounts.create_public_key_from_account_key(\n bytes.fromhex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c")\n)\n\ndeploy_params = pycspr.create_deploy_parameters(\n account = keypair, # Only the public key is used, see `create_deploy_parameters`\n chain_name = "casper" # or "casper-test" for testnet\n)\n\ndeploy = pycspr.create_validator_delegation(\n params = deploy_params,\n amount = int(500e9), # Minimum delegation amount: 500 CSPR\n public_key_of_delegator = keypair,\n public_key_of_validator = validator_public_key,\n path_to_wasm = "./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm"\n)\n\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n'))),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'extern crate casper_client;\nasync fn put_deploy(){\n let maybe_rpc: &str = "";\n let verbosity: u64 = 1;\n let node_address: &str = "http://135.181.216.142:7777";\n let deploy_params: casper_client::DeployStrParams = casper_client::DeployStrParams{\n secret_key:"./sk_testnet.pem",\n timestamp:"",\n ttl:"50s",\n gas_price:"1000000000",\n chain_name:"casper", // or "casper-test" for testnet\n dependencies: Vec::new(),\n session_account: "01daad67ebbcb725e02a1955a6617512b311435a21ca6d523085aa015d2d1b473a"\n\n };\n let mut session_args: Vec<&str> = Vec::new();\n session_args.push("amount:U512=\'500000000000\'");\n\n session_args.push("delegator:public_key=\'01daad67ebbcb725e02a1955a6617512b311435a21ca6d523085aa015d2d1b473a\'");\n session_args.push("validator:public_key=\'validator_public_key\'");\n\n let session_params: casper_client::SessionStrParams = casper_client::SessionStrParams::with_path("./delegate.wasm", session_args, "");\n let payment_params: casper_client::PaymentStrParams = casper_client::PaymentStrParams::with_amount("5000000000");\n let result = casper_client::put_deploy(maybe_rpc, node_address, verbosity, deploy_params, session_params, payment_params).await.unwrap();\n println!("Deploy result: {:?}", result);\n}\n\n#[tokio::main]\nasync fn main(){\n put_deploy().await;\n}\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"calling-contracts"},"Calling Contracts"),(0,s.kt)("p",null,"Smart contracts on a Casper network are invoked by calling entry points. See below how to use Casper's SDKs to interact with these entry points and update the global state from a dApp:"),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst contract = new Contracts.Contract(casperClient);\ncontract.setContractHash("hash-a3cac24aec9de1bbdb87083587b14d8aeffba5dfed27686512b7bb5dee60445d");\nconst runtimeArguments = RuntimeArgs.fromMap({\n message: CLValueBuilder.string("Hello world!"),\n});\nconst deploy = contract.callEntrypoint(\n "update_msg",\n runtimeArguments,\n keypair.publicKey,\n "casper", // or "casper-test" for Testnet\n "1000000000", // 1 CSPR (10^9 Motes)\n [keypair],\n);\n(async () => {\n console.log(await casperClient.putDeploy(deploy));\n})();\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\nclient = NodeClient(NodeConnection(host = "NODE_ADDRESS", port_rpc = 7777))\ndeployParams = pycspr.create_deploy_parameters(\n account = keypair,\n chain_name = "casper-test"\n)\npayment = pycspr.create_standard_payment(10_000_000_000)\nsession = pycspr.types.StoredContractByHash(\n entry_point = "update_msg",\n hash = bytes.fromhex("a3cac24aec9de1bbdb87083587b14d8aeffba5dfed27686512b7bb5dee60445d"),\n args = {\n "message": pycspr.types.CL_String("Hello world!"),\n }\n)\ndeploy = pycspr.create_deploy(deployParams, payment, session)\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"staking-1"},"Staking"),(0,s.kt)("p",null,"Token staking is a fundamental aspect of a Casper network, whereby users lock up tokens as collateral in exchange for the ability to participate in the blockchain's consensus mechanism and earn rewards. This delegated Proof-of-Stake consensus mechanism is crucial for the network's effective operation. With the aid of any of the Casper SDKs, you can delegate your tokens to validators and participate in staking on the network."),(0,s.kt)("p",null,"The delegation functionality is available as a smart contract, which can be found in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository. To delegate tokens, first clone the repository:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-network/casper-node.git\ncd casper-node/\n")),(0,s.kt)("p",null,"Then compile the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/smart_contracts/contracts/client/delegate/src/main.rs"},"delegate contract"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"make setup-rs\nmake build-contract-rs/delegate\n")),(0,s.kt)("p",null,"Now, navigate back to your project's root directory. In your dApp's backend (or standalone script), load the ",(0,s.kt)("em",{parentName:"p"},"delegate.wasm"),' file into memory and deploy it with the arguments "amount", "delegator", and "validator" included.'),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { CasperClient, Contracts, RuntimeArgs, CLValueBuilder, CLPublicKey } = require("casper-js-sdk");\nconst fs = require("fs");\n\nconst casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst contract = new Contracts.Contract(casperClient);\n\nconst contractWasm = new Uint8Array(fs.readFileSync("./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm").buffer);\n\nconst runtimeArguments = RuntimeArgs.fromMap({\n amount: CLValueBuilder.u512(500e9), // Minimum delegation amount: 500 CSPR\n delegator: keypair.publicKey,\n validator: CLPublicKey.fromHex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c"),\n});\n\nconst deploy = contract.install(\n contractWasm,\n runtimeArguments,\n "5000000000", // Gas payment (5 CSPR)\n keypair.publicKey,\n "casper", // or "casper-test" for testnet\n [keypair],\n);\n\n(async () => {\n console.log(await casperClient.putDeploy(deploy));\n})();\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\n\nvalidator_public_key = pycspr.factory.accounts.create_public_key_from_account_key(\n bytes.fromhex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c")\n)\n\ndeploy_params = pycspr.create_deploy_parameters(\n account = keypair, # Only the public key is used, see `create_deploy_parameters`\n chain_name = "casper" # or "casper-test" for testnet\n)\n\ndeploy = pycspr.create_validator_delegation(\n params = deploy_params,\n amount = int(500e9), # Minimum delegation amount: 500 CSPR\n public_key_of_delegator = keypair,\n public_key_of_validator = validator_public_key,\n path_to_wasm = "./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm"\n)\n\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e2fa8c79.c9a19ee9.js b/assets/js/e2fa8c79.c9a19ee9.js new file mode 100644 index 0000000000..3a77165618 --- /dev/null +++ b/assets/js/e2fa8c79.c9a19ee9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4080],{3905:function(e,t,n){n.d(t,{Zo:function(){return i},kt:function(){return y}});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),c=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},i=function(e){var t=c(e.components);return a.createElement(p.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,s=e.originalType,p=e.parentName,i=o(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,y=u["".concat(p,".").concat(m)]||u[m]||d[m]||s;return n?a.createElement(y,l(l({ref:t},i),{},{components:n})):a.createElement(y,l({ref:t},i))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=n.length,l=new Array(s);l[0]=m;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[u]="string"==typeof e?e:r,l[1]=o;for(var c=2;c child <"+("string"==typeof e.type?e.type:e.type.name)+'>: all children of the component should be , and every should have a unique "value" prop.')})))?void 0:n.filter(Boolean))?t:[]}(e).map((function(e){var t=e.props;return{value:t.value,label:t.label,attributes:t.attributes,default:t.default}}))}function d(e){var t=e.values,n=e.children;return(0,r.useMemo)((function(){var e=null!=t?t:u(n);return function(e){var t=(0,c.l)(e,(function(e,t){return e.value===t.value}));if(t.length>0)throw new Error('Docusaurus error: Duplicate values "'+t.map((function(e){return e.value})).join(", ")+'" found in . Every value needs to be unique.')}(e),e}),[t,n])}function m(e){var t=e.value;return e.tabValues.some((function(e){return e.value===t}))}function y(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId,s=(0,o.k6)(),l=function(e){var t=e.queryString,n=void 0!==t&&t,a=e.groupId;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return null!=a?a:null}({queryString:n,groupId:a});return[(0,p._X)(l),(0,r.useCallback)((function(e){if(l){var t=new URLSearchParams(s.location.search);t.set(l,e),s.replace(Object.assign({},s.location,{search:t.toString()}))}}),[l,s])]}function k(e){var t,n,a,s,l=e.defaultValue,o=e.queryString,p=void 0!==o&&o,c=e.groupId,u=d(e),k=(0,r.useState)((function(){return function(e){var t,n=e.defaultValue,a=e.tabValues;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!m({value:n,tabValues:a}))throw new Error('Docusaurus error: The has a defaultValue "'+n+'" but none of its children has the corresponding value. Available values are: '+a.map((function(e){return e.value})).join(", ")+". If you intend to show no default tab, use defaultValue={null} instead.");return n}var r=null!=(t=a.find((function(e){return e.default})))?t:a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:l,tabValues:u})})),h=k[0],b=k[1],f=y({queryString:p,groupId:c}),g=f[0],_=f[1],v=(t=function(e){return e?"docusaurus.tab."+e:null}({groupId:c}.groupId),n=(0,i.Nk)(t),a=n[0],s=n[1],[a,(0,r.useCallback)((function(e){t&&s.set(e)}),[t,s])]),w=v[0],C=v[1],N=function(){var e=null!=g?g:w;return m({value:e,tabValues:u})?e:null}();return(0,r.useLayoutEffect)((function(){N&&b(N)}),[N]),{selectedValue:h,selectValue:(0,r.useCallback)((function(e){if(!m({value:e,tabValues:u}))throw new Error("Can't select invalid tab value="+e);b(e),_(e),C(e)}),[_,C,u]),tabValues:u}}var h=n(2389),b={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function f(e){var t=e.className,n=e.block,o=e.selectedValue,p=e.selectValue,c=e.tabValues,i=[],u=(0,l.o5)().blockElementScrollPositionUntilNextRender,d=function(e){var t=e.currentTarget,n=i.indexOf(t),a=c[n].value;a!==o&&(u(t),p(a))},m=function(e){var t,n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":var a,r=i.indexOf(e.currentTarget)+1;n=null!=(a=i[r])?a:i[0];break;case"ArrowLeft":var s,l=i.indexOf(e.currentTarget)-1;n=null!=(s=i[l])?s:i[i.length-1]}null==(t=n)||t.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.Z)("tabs",{"tabs--block":n},t)},c.map((function(e){var t=e.value,n=e.label,l=e.attributes;return r.createElement("li",(0,a.Z)({role:"tab",tabIndex:o===t?0:-1,"aria-selected":o===t,key:t,ref:function(e){return i.push(e)},onKeyDown:m,onClick:d},l,{className:(0,s.Z)("tabs__item",b.tabItem,null==l?void 0:l.className,{"tabs__item--active":o===t})}),null!=n?n:t)})))}function g(e){var t=e.lazy,n=e.children,a=e.selectedValue,s=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){var l=s.find((function(e){return e.props.value===a}));return l?(0,r.cloneElement)(l,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},s.map((function(e,t){return(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})})))}function _(e){var t=k(e);return r.createElement("div",{className:(0,s.Z)("tabs-container",b.tabList)},r.createElement(f,(0,a.Z)({},e,t)),r.createElement(g,(0,a.Z)({},e,t)))}function v(e){var t=(0,h.Z)();return r.createElement(_,(0,a.Z)({key:String(t)},e))}},4139:function(e,t,n){n.r(t),n.d(t,{assets:function(){return d},contentTitle:function(){return i},default:function(){return h},frontMatter:function(){return c},metadata:function(){return u},toc:function(){return m}});var a=n(7462),r=n(3366),s=(n(7294),n(3905)),l=n(4866),o=n(5162),p=["components"],c={},i="SDK Client Library Usage",u={unversionedId:"developers/dapps/sdk/client-library-usage",id:"developers/dapps/sdk/client-library-usage",title:"SDK Client Library Usage",description:"Installing the SDKs",source:"@site/source/docs/casper/developers/dapps/sdk/client-library-usage.md",sourceDirName:"developers/dapps/sdk",slug:"/developers/dapps/sdk/client-library-usage",permalink:"/developers/dapps/sdk/client-library-usage",draft:!1,editUrl:"https://github.com/casper-network/docs/tree/dev/source/docs/casper/developers/dapps/sdk/client-library-usage.md",tags:[],version:"current",lastUpdatedAt:1707837031,formattedLastUpdatedAt:"Feb 13, 2024",frontMatter:{},sidebar:"developers",previous:{title:"SDK Client Libraries",permalink:"/sdk"},next:{title:"JavaScript/TypeScript SDK",permalink:"/developers/dapps/sdk/script-sdk"}},d={},m=[{value:"Installing the SDKs",id:"installing-the-sdks",level:2},{value:"Creating Accounts",id:"creating-accounts",level:2},{value:"Creating new account keys",id:"creating-new-account-keys",level:3},{value:"Exporting the public key and account hash",id:"exporting-the-public-key-and-account-hash",level:3},{value:"Uploading the secret key from a file",id:"uploading-the-secret-key-from-a-file",level:3},{value:"Transferring CSPR",id:"transferring-cspr",level:2},{value:"Installing Contracts",id:"installing-contracts",level:2},{value:"Staking",id:"staking",level:2},{value:"Calling Contracts",id:"calling-contracts",level:2},{value:"Staking",id:"staking-1",level:2}],y={toc:m},k="wrapper";function h(e){var t=e.components,n=(0,r.Z)(e,p);return(0,s.kt)(k,(0,a.Z)({},y,n,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"sdk-client-library-usage"},"SDK Client Library Usage"),(0,s.kt)("h2",{id:"installing-the-sdks"},"Installing the SDKs"),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("p",null,"Use ",(0,s.kt)("inlineCode",{parentName:"p"},"npm")," or ",(0,s.kt)("inlineCode",{parentName:"p"},"yarn")," to install the ",(0,s.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/casper-js-sdk"},"casper-js-sdk")," package:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"npm install casper-js-sdk\n")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"yarn install casper-js-sdk\n"))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("p",null,"Use ",(0,s.kt)("a",{parentName:"p",href:"https://pypi.org/project/pip/"},(0,s.kt)("inlineCode",{parentName:"a"},"pip"))," to install the ",(0,s.kt)("a",{parentName:"p",href:"https://pypi.org/project/pycspr/"},"pycspr")," package:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"pip install pycspr\n"))),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("p",null,"Include the casper-client dependency to your ",(0,s.kt)("inlineCode",{parentName:"p"},"Cargo.toml"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},'[dependencies]\ncasper-client="1.5.1"\n')),(0,s.kt)("p",null,"and add it to your ",(0,s.kt)("inlineCode",{parentName:"p"},"main.rs"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"extern crate casper_client;\n")),(0,s.kt)("p",null,"Use types and methods from casper_client:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"use casper_client::transfer;\nuse casper_client::put_deploy;\n//...\n")),(0,s.kt)("p",null,"as casper_client functions are asynchronous, a tokyo runtime is necessary for testing:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},'[dependencies]\ntokio = { version = "^1.27.0", features = ["full"] }\n')))),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"creating-accounts"},"Creating Accounts"),(0,s.kt)("p",null,"You may use the SDKs to interact with accounts on a Casper network. Accounts can use either an Ed25519 or Secp256k1 digital signature scheme. See the ",(0,s.kt)("a",{parentName:"p",href:"/concepts/accounts-and-keys"},"Accounts and Cryptographic Keys")," page for more details."),(0,s.kt)("h3",{id:"creating-new-account-keys"},"Creating new account keys"),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { Keys } = require("casper-js-sdk");\nconst keypair = Keys.Ed25519.new();\nconst { publicKey, privateKey } = keypair;\n')),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"Ed25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"Secp256K1")," if you wish.")),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},"from pycspr.crypto import KeyAlgorithm, get_key_pair\nkeypair = get_key_pair(KeyAlgorithm.ED25519)\n")),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"ED25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"SECP256K1")," if you wish.")),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("p",null,"Create a keypair and write the files to a specified ",(0,s.kt)("inlineCode",{parentName:"p"},"PATH"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},' casper_client::keygen::generate_files("PATH", "ED25519", false).unwrap();\n')),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"ED25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"SECP256K1")," if you wish."))),(0,s.kt)("h3",{id:"exporting-the-public-key-and-account-hash"},"Exporting the public key and account hash"),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"keypair")," variable contains the private and public key pair for the account. You can use, read, or export the public key. You may also want access to the account hash, often used within smart contracts on a Casper network. The following methods show how to extract the public key and account hash."),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},"// Create a hexadecimal representation of the public key and account hash.\nconst publicKeyHex = publicKey.toHex();\nconst accountHashHex = publicKey.toAccountHashStr();\n")),(0,s.kt)("p",null,"Note that ",(0,s.kt)("inlineCode",{parentName:"p"},"accountHashHex"),' will be prefixed with the text "account-hash-".')),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},"import pycspr.crypto\n\npublicKeyBytes = keypair.account_key\npublicKeyHex = pycspr.crypto.cl_checksum.encode(publicKeyBytes)\naccountHashBytes = pycspr.crypto.cl_operations.get_account_hash(publicKeyBytes)\naccountHashHex = pycspr.crypto.cl_checksum.encode(accountHashBytes)\n")))),(0,s.kt)("h3",{id:"uploading-the-secret-key-from-a-file"},"Uploading the secret key from a file"),(0,s.kt)("p",null,"To use a specific account, you should not include the private key in the source code; instead, upload the account's secret key from a local file. Update the path to the file in the example below."),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { Keys } = require("casper-js-sdk");\nconst keypair = Keys.Ed25519.loadKeyPairFromPrivateFile("./secret_key.pem");\n')),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"Ed25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"Secp256K1")," if you wish.")),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\nkeypair = pycspr.parse_private_key(\n "./secret_key.pem",\n pycspr.crypto.KeyAlgorithm.ED25519\n)\n')),(0,s.kt)("p",null,"Replace ",(0,s.kt)("inlineCode",{parentName:"p"},"ED25519")," with ",(0,s.kt)("inlineCode",{parentName:"p"},"SECP256K1")," if you wish.")),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("p",null,"In Rust, we don't explicitly import the private key as an object, but instead supply its path as an argument when calling functions:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'let deploy_params: casper_client::DeployStrParams = casper_client::DeployStrParams{\n secret_key:"./secret_key.pem",\n timestamp:"",\n ...\n};\n')))),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"transferring-cspr"},"Transferring CSPR"),(0,s.kt)("p",null,"Using the ",(0,s.kt)("inlineCode",{parentName:"p"},"keypair")," created ",(0,s.kt)("a",{parentName:"p",href:"#creating-accounts"},"above"),", you can sign a deploy that transfers CSPR."),(0,s.kt)("p",null,"Replace the ",(0,s.kt)("inlineCode",{parentName:"p"},"NODE_ADDRESS")," and corresponding RPC port with an active node on the network. You can find active online peers for Mainnet on ",(0,s.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"cspr.live")," and for Testnet on ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"testnet.cspr.live"),". The RPC port is usually ",(0,s.kt)("inlineCode",{parentName:"p"},"7777"),", but it depends on the network's configuration settings."),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { CasperClient, DeployUtil } = require("casper-js-sdk");\n\nconst casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst receipientPublicKeyHex = "01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c";\n\nconst amount = 2.5e9; // Minimum transfer: 2.5 CSPR\nlet deployParams = new DeployUtil.DeployParams(\n keypair.publicKey,\n "casper", // or "casper-test" for Testnet\n);\n\nconst session = DeployUtil.ExecutableDeployItem.newTransferWithOptionalTransferId(amount, recipientPublicKeyHex);\n\nconst payment = DeployUtil.standardPayment(0.1e9); // Gas payment in motes: 0.1 CSPR\nconst deploy = DeployUtil.makeDeploy(deployParams, session, payment);\nconst signedDeploy = DeployUtil.signDeploy(deploy, keypair);\n\nconsole.log(await casperClient.putDeploy(signedDeploy));\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\n\nclient = NodeClient(NodeConnection(host = "NODE_ADDRESS", port_rpc = 7777))\nrecipientPublicKeyHex = "01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c"\nrecipientPublicKeyBytes = pycspr.crypto.cl_checksum.decode(recipientPublicKeyHex)\n\ndeployParams = pycspr.create_deploy_parameters(\n account = keypair,\n chain_name = "casper" # or "casper-test" for Testnet\n)\n\ndeploy = pycspr.create_transfer(\n params = deployParams,\n amount = int(2.5e9), # Minimum transfer: 2.5 CSPR\n target = recipientPublicKeyBytes\n)\n\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n'))),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'extern crate casper_client;\nasync fn send_transfer(){\n let maybe_rpc_id: &str = "";\n let node_address: &str = "http://135.181.216.142:7777";\n let verbosity_level: u64 = 1;\n let amount: &str = "2500000000";\n let target_account: &str = recipient;\n let transfer_id: &str = "1";\n let deploy_params: casper_client::DeployStrParams = casper_client::DeployStrParams{\n secret_key:"./sk_testnet.pem",\n timestamp:"",\n ttl:"50s",\n gas_price:"1000000000",\n chain_name:"casper", // or "casper-test" for testnet\n dependencies: Vec::new(),\n session_account: "01daad67ebbcb725e02a1955a6617512b311435a21ca6d523085aa015d2d1b473a"\n\n };\n let recipient: &str = "0106ca7c39cd272dbf21a86eeb3b36b7c26e2e9b94af64292419f7862936bca2ca";\n let payment_params: casper_client::PaymentStrParams = casper_client::PaymentStrParams::with_amount(amount);\n let result = casper_client::transfer(maybe_rpc_id, node_address, verbosity_level, amount, target_account, transfer_id, deploy_params, payment_params).await.unwrap();\n println!("Deploy response: {:?}", result);\n}\n\n#[tokio::main]\nasync fn main(){\n send_transfer().await;\n}\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"installing-contracts"},"Installing Contracts"),(0,s.kt)("p",null,"To install a contract on the network, you need to sign and send a deploy containing the compiled Wasm."),(0,s.kt)("p",null,"Replace the ",(0,s.kt)("inlineCode",{parentName:"p"},"NODE_ADDRESS")," and corresponding RPC port with an active node on the network. You can find active online peers for Mainnet on ",(0,s.kt)("a",{parentName:"p",href:"https://cspr.live/tools/peers"},"cspr.live")," and for Testnet on ",(0,s.kt)("a",{parentName:"p",href:"https://testnet.cspr.live/tools/peers"},"testnet.cspr.live"),". The RPC port is usually ",(0,s.kt)("inlineCode",{parentName:"p"},"7777"),", but it depends on the network's configuration settings."),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { CasperClient, Contracts, RuntimeArgs, CLValueBuilder } = require("casper-js-sdk");\nconst fs = require("fs");\n\nconst casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst contract = new Contracts.Contract(casperClient);\n\nconst contractWasm = new Uint8Array(fs.readFileSync("/path/to/contract.wasm").buffer);\n\nconst runtimeArguments = RuntimeArgs.fromMap({\n argument: CLValueBuilder.string("Hello world!"),\n});\n\nconst deploy = contract.install(\n contractWasm,\n runtimeArguments,\n "10000000000", // Gas payment (10 CSPR)\n keypair.publicKey,\n "casper", // or "casper-test" for Testnet\n [keypair],\n);\n\nconsole.log(await casperClient.putDeploy(deploy));\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\nfrom pycspr.types import ModuleBytes, CL_String\n\nclient = NodeClient(NodeConnection(host = "NODE_ADDRESS", port_rpc = 7777))\n\ndeployParams = pycspr.create_deploy_parameters(\n account = keypair,\n chain_name = "casper" # or "casper-test" for Testnet\n)\npayment = pycspr.create_standard_payment(10000000000) # 10 CSPR\nsession = ModuleBytes(\n module_bytes = pycspr.read_wasm("/path/to/contract.wasm"),\n args = {\n "message": CL_String("Hello world!"),\n }\n)\n\ndeploy = pycspr.create_deploy(deployParams, payment, session)\n\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n'))),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'extern crate casper_client;\nasync fn put_deploy(){\n let maybe_rpc: &str = "";\n let verbosity: u64 = 1;\n let node_address: &str = "http://135.181.216.142:7777";\n let deploy_params: casper_client::DeployStrParams = casper_client::DeployStrParams{\n secret_key:"./sk_testnet.pem",\n timestamp:"",\n ttl:"50s",\n gas_price:"1000000000",\n chain_name:"casper", // or "casper-test"\n dependencies: Vec::new(),\n session_account: "01daad67ebbcb725e02a1955a6617512b311435a21ca6d523085aa015d2d1b473a"\n\n };\n // Without session args:\n // let session_args: Vec<&str> = Vec::new();\n // With session args:\n let mut session_args: Vec<&str> = Vec::new();\n session_args.push("argument:String=\'hello world\'");\n let session_params: casper_client::SessionStrParams = casper_client::SessionStrParams::with_path("./contract.wasm", session_args, "");\n let payment_params: casper_client::PaymentStrParams = casper_client::PaymentStrParams::with_amount("10000000000");\n let result = casper_client::put_deploy(maybe_rpc_id, node_address, verbosity_level, deploy_params, session_params, payment_params).await.unwrap();\n println!("Deploy response: {:?}", result);\n}\n\n#[tokio::main]\nasync fn main(){\n send_transfer().await;\n}\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."),(0,s.kt)("h2",{id:"staking"},"Staking"),(0,s.kt)("p",null,"Token staking is a fundamental aspect of the Casper Network, whereby users lock up tokens as collateral in exchange for the ability to participate in the blockchain's consensus mechanism and earn rewards. This delegated Proof-of-Stake consensus mechanism is crucial for the network's effective operation. With the aid of any of the Casper SDKs, you can delegate your tokens to validators and participate in staking on the network."),(0,s.kt)("p",null,"The delegation functionality is available as a smart contract, which can be found in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository. To delegate tokens, first clone the repository:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-network/casper-node.git\ncd casper-node/\n")),(0,s.kt)("p",null,"Then compile the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/smart_contracts/contracts/client/delegate/src/main.rs"},"delegate contract"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"make setup-rs\nmake build-contract-rs/delegate\n")),(0,s.kt)("p",null,"Now, assuming that you cloned ",(0,s.kt)("inlineCode",{parentName:"p"},"casper-node")," from your project's root directory, ",(0,s.kt)("inlineCode",{parentName:"p"},"cd")," back into it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"cd ../\n")),(0,s.kt)("p",null,"Now in your dApp's backend (or standalone script), load the ",(0,s.kt)("em",{parentName:"p"},"delegate.wasm"),' file into memory and deploy it with the arguments "amount", "delegator", and "validator" included.'),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { CasperClient, Contracts, RuntimeArgs, CLValueBuilder, CLPublicKey } = require("casper-js-sdk");\nconst fs = require("fs");\n\nconst casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst contract = new Contracts.Contract(casperClient);\n\nconst contractWasm = new Uint8Array(fs.readFileSync("./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm").buffer);\n\nconst runtimeArguments = RuntimeArgs.fromMap({\n amount: CLValueBuilder.u512(500e9), // Minimum delegation amount: 500 CSPR\n delegator: keypair.publicKey,\n validator: CLPublicKey.fromHex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c"),\n});\n\nconst deploy = contract.install(\n contractWasm,\n runtimeArguments,\n "5000000000", // Gas payment (5 CSPR)\n keypair.publicKey,\n "casper", // or "casper-test" for testnet\n [keypair],\n);\n\n(async () => {\n console.log(await casperClient.putDeploy(deploy));\n})();\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\n\nvalidator_public_key = pycspr.factory.accounts.create_public_key_from_account_key(\n bytes.fromhex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c")\n)\n\ndeploy_params = pycspr.create_deploy_parameters(\n account = keypair, # Only the public key is used, see `create_deploy_parameters`\n chain_name = "casper" # or "casper-test" for testnet\n)\n\ndeploy = pycspr.create_validator_delegation(\n params = deploy_params,\n amount = int(500e9), # Minimum delegation amount: 500 CSPR\n public_key_of_delegator = keypair,\n public_key_of_validator = validator_public_key,\n path_to_wasm = "./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm"\n)\n\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n'))),(0,s.kt)(o.Z,{value:"rust",label:"Rust",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},'extern crate casper_client;\nasync fn put_deploy(){\n let maybe_rpc: &str = "";\n let verbosity: u64 = 1;\n let node_address: &str = "http://135.181.216.142:7777";\n let deploy_params: casper_client::DeployStrParams = casper_client::DeployStrParams{\n secret_key:"./sk_testnet.pem",\n timestamp:"",\n ttl:"50s",\n gas_price:"1000000000",\n chain_name:"casper", // or "casper-test" for testnet\n dependencies: Vec::new(),\n session_account: "01daad67ebbcb725e02a1955a6617512b311435a21ca6d523085aa015d2d1b473a"\n\n };\n let mut session_args: Vec<&str> = Vec::new();\n session_args.push("amount:U512=\'500000000000\'");\n\n session_args.push("delegator:public_key=\'01daad67ebbcb725e02a1955a6617512b311435a21ca6d523085aa015d2d1b473a\'");\n session_args.push("validator:public_key=\'validator_public_key\'");\n\n let session_params: casper_client::SessionStrParams = casper_client::SessionStrParams::with_path("./delegate.wasm", session_args, "");\n let payment_params: casper_client::PaymentStrParams = casper_client::PaymentStrParams::with_amount("5000000000");\n let result = casper_client::put_deploy(maybe_rpc, node_address, verbosity, deploy_params, session_params, payment_params).await.unwrap();\n println!("Deploy result: {:?}", result);\n}\n\n#[tokio::main]\nasync fn main(){\n put_deploy().await;\n}\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"calling-contracts"},"Calling Contracts"),(0,s.kt)("p",null,"Smart contracts on a Casper network are invoked by calling entry points. See below how to use Casper's SDKs to interact with these entry points and update the global state from a dApp:"),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst contract = new Contracts.Contract(casperClient);\ncontract.setContractHash("hash-a3cac24aec9de1bbdb87083587b14d8aeffba5dfed27686512b7bb5dee60445d");\nconst runtimeArguments = RuntimeArgs.fromMap({\n message: CLValueBuilder.string("Hello world!"),\n});\nconst deploy = contract.callEntrypoint(\n "update_msg",\n runtimeArguments,\n keypair.publicKey,\n "casper", // or "casper-test" for Testnet\n "1000000000", // 1 CSPR (10^9 Motes)\n [keypair],\n);\n(async () => {\n console.log(await casperClient.putDeploy(deploy));\n})();\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\nclient = NodeClient(NodeConnection(host = "NODE_ADDRESS", port_rpc = 7777))\ndeployParams = pycspr.create_deploy_parameters(\n account = keypair,\n chain_name = "casper-test"\n)\npayment = pycspr.create_standard_payment(10_000_000_000)\nsession = pycspr.types.StoredContractByHash(\n entry_point = "update_msg",\n hash = bytes.fromhex("a3cac24aec9de1bbdb87083587b14d8aeffba5dfed27686512b7bb5dee60445d"),\n args = {\n "message": pycspr.types.CL_String("Hello world!"),\n }\n)\ndeploy = pycspr.create_deploy(deployParams, payment, session)\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"staking-1"},"Staking"),(0,s.kt)("p",null,"Token staking is a fundamental aspect of a Casper network, whereby users lock up tokens as collateral in exchange for the ability to participate in the blockchain's consensus mechanism and earn rewards. This delegated Proof-of-Stake consensus mechanism is crucial for the network's effective operation. With the aid of any of the Casper SDKs, you can delegate your tokens to validators and participate in staking on the network."),(0,s.kt)("p",null,"The delegation functionality is available as a smart contract, which can be found in the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node"},"casper-node")," repository. To delegate tokens, first clone the repository:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com/casper-network/casper-node.git\ncd casper-node/\n")),(0,s.kt)("p",null,"Then compile the ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/casper-network/casper-node/blob/dev/smart_contracts/contracts/client/delegate/src/main.rs"},"delegate contract"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-bash"},"make setup-rs\nmake build-contract-rs/delegate\n")),(0,s.kt)("p",null,"Now, navigate back to your project's root directory. In your dApp's backend (or standalone script), load the ",(0,s.kt)("em",{parentName:"p"},"delegate.wasm"),' file into memory and deploy it with the arguments "amount", "delegator", and "validator" included.'),(0,s.kt)(l.Z,{mdxType:"Tabs"},(0,s.kt)(o.Z,{value:"js",label:"JavaScript",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-javascript"},'const { CasperClient, Contracts, RuntimeArgs, CLValueBuilder, CLPublicKey } = require("casper-js-sdk");\nconst fs = require("fs");\n\nconst casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");\nconst contract = new Contracts.Contract(casperClient);\n\nconst contractWasm = new Uint8Array(fs.readFileSync("./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm").buffer);\n\nconst runtimeArguments = RuntimeArgs.fromMap({\n amount: CLValueBuilder.u512(500e9), // Minimum delegation amount: 500 CSPR\n delegator: keypair.publicKey,\n validator: CLPublicKey.fromHex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c"),\n});\n\nconst deploy = contract.install(\n contractWasm,\n runtimeArguments,\n "5000000000", // Gas payment (5 CSPR)\n keypair.publicKey,\n "casper", // or "casper-test" for testnet\n [keypair],\n);\n\n(async () => {\n console.log(await casperClient.putDeploy(deploy));\n})();\n'))),(0,s.kt)(o.Z,{value:"python",label:"Python",mdxType:"TabItem"},(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-python"},'import pycspr\n\nvalidator_public_key = pycspr.factory.accounts.create_public_key_from_account_key(\n bytes.fromhex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c")\n)\n\ndeploy_params = pycspr.create_deploy_parameters(\n account = keypair, # Only the public key is used, see `create_deploy_parameters`\n chain_name = "casper" # or "casper-test" for testnet\n)\n\ndeploy = pycspr.create_validator_delegation(\n params = deploy_params,\n amount = int(500e9), # Minimum delegation amount: 500 CSPR\n public_key_of_delegator = keypair,\n public_key_of_validator = validator_public_key,\n path_to_wasm = "./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm"\n)\n\ndeploy.approve(keypair)\nclient.send_deploy(deploy)\nprint(deploy.hash.hex())\n')))),(0,s.kt)("p",null,"Once submitted, the above snippet will print the deploy hash in the console."))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e2ffc27a.0a9a921a.js b/assets/js/e2ffc27a.0a9a921a.js deleted file mode 100644 index f51986d581..0000000000 --- a/assets/js/e2ffc27a.0a9a921a.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5036],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return m}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=p(n),h=o,m=d["".concat(s,".").concat(h)]||d[h]||u[h]||r;return n?a.createElement(m,l(l({ref:t},c),{},{components:n})):a.createElement(m,l({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,l=new Array(r);l[0]=h;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:o,l[1]=i;for(var p=2;p \\\n --chain-name [NETWORK_NAME]] \\\n --secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \\\n --payment-amount [AMOUNT] \\\n --session-path [WASM_FILE_PATH]/[File_Name].wasm\n --session-arg <"NAME:TYPE=\'VALUE\'" OR "NAME:TYPE=null">\n\n')),(0,r.kt)("p",null,"Check if the request to the Testnet can be made and get a snapshot of the network with the state root hash:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"\ncasper-client get-state-root-hash --node-address http://78.46.32.13:7777\n\n")),(0,r.kt)("p",null,"You should obtain a response similar to:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 3323991011802671610,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.15",\n "state_root_hash": "9b43fd7388559c078f363403972cb079d69786259bf6c5cd9cd7adcc14029d74"\n }\n}\n')),(0,r.kt)("p",null,"An exemplary deploy to the Casper Testnet is as follows:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'\ncasper-client put-deploy \\\n--node-address http://78.46.32.13:7777 \\\n--chain-name casper-test \\\n--secret-key "./keys/secret_key.pem" \\\n--payment-amount 150000000000 \\\n--session-path "./target/wasm32-unknown-unknown/release/cep18.wasm" \\\n--session-arg "name:string=\'CHF Coin\'" \\\n--session-arg "symbol:string=\'CHFC\'" \\\n--session-arg "decimals:u8=\'10\'" \\\n--session-arg "total_supply:u256=\'1000\'"\n\n')),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Always be mindful of the ",(0,r.kt)("inlineCode",{parentName:"p"},"--secret-key")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-path")," arguments. Path provided to the arguments should always be with regard to the current folder, where the command is executed."),(0,r.kt)("p",{parentName:"admonition"},"The ",(0,r.kt)("inlineCode",{parentName:"p"},"keys")," folder is not a part of the CEP18 folder structure. Optionally you should provide a folder where your keys are stored.")),(0,r.kt)("p",null,"The response from the ",(0,r.kt)("inlineCode",{parentName:"p"},"put-deploy")," command should look like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 5066914343373494745,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.15",\n "deploy_hash": "19853d1569fec2b0fa36e81f2f24bea77ccf039a399071cb7d4b377202a073d6"\n }\n}\n\n')),(0,r.kt)("p",null,"Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," the state of the deploy can be checked:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"\ncasper-client get-deploy \\\n --node-address http://78.46.32.13:7777 19853d1569fec2b0fa36e81f2f24bea77ccf039a399071cb7d4b377202a073d6\n\n")),(0,r.kt)("p",null,"In the execution results we can see, that the deploy was successful:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'\n...\n "execution_results": [\n {\n "block_hash": "426a8823c1018e75f8c3823d580116269fd272f20e60561dff0565375a95316d",\n "result": {\n "Success": {\n "cost": "140416131900",\n "effect": {\n "operations": [],\n...\n\n')),(0,r.kt)("p",null,"Be always mindful of the payment amount during the deploy process. If the amount is too small, then the deploy will fail with ",(0,r.kt)("inlineCode",{parentName:"p"},"Out of gas error"),"."),(0,r.kt)("h3",{id:"cep18-contract-clone"},"Query the Entry Points in the CEP-18 contract"),(0,r.kt)("p",null,"Get the state root hash from the network:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address http://78.46.32.13:7777\n")),(0,r.kt)("p",null,"Your response should look similar to:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 2950480729544096556,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.15",\n "state_root_hash": "7706d906fce25dcdadb2a9453f5243a6c72c4444e6c826cf2941157333a48705"\n }\n}\n')),(0,r.kt)("p",null,"With the state root hash and the account hash which performed the deploy, you can query the contract arguments."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state --node-address http://78.46.32.13:7777 \\\n--state-root-hash 7706d906fce25dcdadb2a9453f5243a6c72c4444e6c826cf2941157333a48705 \\\n--key account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9 \\\n-q "cep18_contract_hash_CHF Coin/name"\n')),(0,r.kt)("p",null,"The above command will query the contract for the name. The template for the query is ",(0,r.kt)("inlineCode",{parentName:"p"},"contract_name/named_key"),"."),(0,r.kt)("p",null,"You will obtain the following response:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -7058786841478812744,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.15",\n "block_header": null,\n "merkle_proof": "[94526 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "0800000043484620436f696e",\n "cl_type": "String",\n "parsed": "CHF Coin"\n }\n }\n }\n}\n')),(0,r.kt)("p",null,"Try to query the contract for other Named Keys and check how the contract behaves."),(0,r.kt)("h2",{id:"summary"},"Summary"),(0,r.kt)("p",null,"In this tutorial, we:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Explained the ERC20 standard and what the implications are for not using the standard implementations."),(0,r.kt)("li",{parentName:"ul"},"Developed a CEP-18 Rust contract on a Casper network and defined the proper arguments for the deploy."),(0,r.kt)("li",{parentName:"ul"},"Installed the contract on the Testnet"),(0,r.kt)("li",{parentName:"ul"},"Called an entry point on the contract to get the value of the Named Key ",(0,r.kt)("inlineCode",{parentName:"li"},"name"),".")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e2ffc27a.9220c9f9.js b/assets/js/e2ffc27a.9220c9f9.js new file mode 100644 index 0000000000..aa9aa00d48 --- /dev/null +++ b/assets/js/e2ffc27a.9220c9f9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5036],{3905:function(e,t,n){n.d(t,{Zo:function(){return c},kt:function(){return m}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=p(n),h=o,m=d["".concat(s,".").concat(h)]||d[h]||u[h]||r;return n?a.createElement(m,l(l({ref:t},c),{},{components:n})):a.createElement(m,l({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,l=new Array(r);l[0]=h;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:o,l[1]=i;for(var p=2;p \\\n --chain-name [NETWORK_NAME]] \\\n --secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \\\n --payment-amount [AMOUNT] \\\n --session-path [WASM_FILE_PATH]/[File_Name].wasm\n --session-arg <"NAME:TYPE=\'VALUE\'" OR "NAME:TYPE=null">\n\n')),(0,r.kt)("p",null,"Check if the request to the Testnet can be made and get a snapshot of the network with the state root hash:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"\ncasper-client get-state-root-hash --node-address http://78.46.32.13:7777\n\n")),(0,r.kt)("p",null,"You should obtain a response similar to:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 3323991011802671610,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.15",\n "state_root_hash": "9b43fd7388559c078f363403972cb079d69786259bf6c5cd9cd7adcc14029d74"\n }\n}\n')),(0,r.kt)("p",null,"An exemplary deploy to the Casper Testnet is as follows:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'\ncasper-client put-deploy \\\n--node-address http://78.46.32.13:7777 \\\n--chain-name casper-test \\\n--secret-key "./keys/secret_key.pem" \\\n--payment-amount 150000000000 \\\n--session-path "./target/wasm32-unknown-unknown/release/cep18.wasm" \\\n--session-arg "name:string=\'CHF Coin\'" \\\n--session-arg "symbol:string=\'CHFC\'" \\\n--session-arg "decimals:u8=\'10\'" \\\n--session-arg "total_supply:u256=\'1000\'"\n\n')),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Always be mindful of the ",(0,r.kt)("inlineCode",{parentName:"p"},"--secret-key")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"--session-path")," arguments. Path provided to the arguments should always be with regard to the current folder, where the command is executed."),(0,r.kt)("p",{parentName:"admonition"},"The ",(0,r.kt)("inlineCode",{parentName:"p"},"keys")," folder is not a part of the CEP18 folder structure. Optionally you should provide a folder where your keys are stored.")),(0,r.kt)("p",null,"The response from the ",(0,r.kt)("inlineCode",{parentName:"p"},"put-deploy")," command should look like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'\n{\n "id": 5066914343373494745,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.15",\n "deploy_hash": "19853d1569fec2b0fa36e81f2f24bea77ccf039a399071cb7d4b377202a073d6"\n }\n}\n\n')),(0,r.kt)("p",null,"Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," the state of the deploy can be checked:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"\ncasper-client get-deploy \\\n --node-address http://78.46.32.13:7777 19853d1569fec2b0fa36e81f2f24bea77ccf039a399071cb7d4b377202a073d6\n\n")),(0,r.kt)("p",null,"In the execution results we can see, that the deploy was successful:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'\n...\n "execution_results": [\n {\n "block_hash": "426a8823c1018e75f8c3823d580116269fd272f20e60561dff0565375a95316d",\n "result": {\n "Success": {\n "cost": "140416131900",\n "effect": {\n "operations": [],\n...\n\n')),(0,r.kt)("p",null,"Be always mindful of the payment amount during the deploy process. If the amount is too small, then the deploy will fail with ",(0,r.kt)("inlineCode",{parentName:"p"},"Out of gas error"),"."),(0,r.kt)("h3",{id:"cep18-contract-clone"},"Query the Entry Points in the CEP-18 contract"),(0,r.kt)("p",null,"Get the state root hash from the network:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client get-state-root-hash --node-address http://78.46.32.13:7777\n")),(0,r.kt)("p",null,"Your response should look similar to:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": 2950480729544096556,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.15",\n "state_root_hash": "7706d906fce25dcdadb2a9453f5243a6c72c4444e6c826cf2941157333a48705"\n }\n}\n')),(0,r.kt)("p",null,"With the state root hash and the account hash which performed the deploy, you can query the contract arguments."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client query-global-state --node-address http://78.46.32.13:7777 \\\n--state-root-hash 7706d906fce25dcdadb2a9453f5243a6c72c4444e6c826cf2941157333a48705 \\\n--key account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9 \\\n-q "cep18_contract_hash_CHF Coin/name"\n')),(0,r.kt)("p",null,"The above command will query the contract for the name. The template for the query is ",(0,r.kt)("inlineCode",{parentName:"p"},"contract_name/named_key"),"."),(0,r.kt)("p",null,"You will obtain the following response:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'{\n "id": -7058786841478812744,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.4.15",\n "block_header": null,\n "merkle_proof": "[94526 hex chars]",\n "stored_value": {\n "CLValue": {\n "bytes": "0800000043484620436f696e",\n "cl_type": "String",\n "parsed": "CHF Coin"\n }\n }\n }\n}\n')),(0,r.kt)("p",null,"Try to query the contract for other Named Keys and check how the contract behaves."),(0,r.kt)("h2",{id:"summary"},"Summary"),(0,r.kt)("p",null,"In this tutorial, we:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Explained the ERC20 standard and what the implications are for not using the standard implementations."),(0,r.kt)("li",{parentName:"ul"},"Developed a CEP-18 Rust contract on a Casper network and defined the proper arguments for the deploy."),(0,r.kt)("li",{parentName:"ul"},"Installed the contract on the Testnet"),(0,r.kt)("li",{parentName:"ul"},"Called an entry point on the contract to get the value of the Named Key ",(0,r.kt)("inlineCode",{parentName:"li"},"name"),".")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e6ce8647.0c6000c5.js b/assets/js/e6ce8647.d7eb5eda.js similarity index 59% rename from assets/js/e6ce8647.0c6000c5.js rename to assets/js/e6ce8647.d7eb5eda.js index d0b0b386ba..fa84939ad9 100644 --- a/assets/js/e6ce8647.0c6000c5.js +++ b/assets/js/e6ce8647.d7eb5eda.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[6871],{3905:function(e,t,r){r.d(t,{Zo:function(){return p},kt:function(){return f}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),d=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),s=d(r),m=a,f=s["".concat(l,".").concat(m)]||s[m]||u[m]||o;return r?n.createElement(f,i(i({ref:t},p),{},{components:r})):n.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[s]="string"==typeof e?e:a,i[1]=c;for(var d=2;d=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),d=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(l.Provider,{value:t},e.children)},s="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),s=d(r),m=a,f=s["".concat(l,".").concat(m)]||s[m]||u[m]||o;return r?n.createElement(f,i(i({ref:t},p),{},{components:r})):n.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[s]="string"==typeof e?e:a,i[1]=c;for(var d=2;d=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=n.createContext({}),c=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(u.Provider,{value:t},e.children)},l="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,u=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),l=c(r),m=a,f=l["".concat(u,".").concat(m)]||l[m]||d[m]||o;return r?n.createElement(f,i(i({ref:t},p),{},{components:r})):n.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var s={};for(var u in t)hasOwnProperty.call(t,u)&&(s[u]=t[u]);s.originalType=e,s[l]="string"==typeof e?e:a,i[1]=s;for(var c=2;c=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=n.createContext({}),c=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return n.createElement(u.Provider,{value:t},e.children)},l="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,u=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),l=c(r),m=a,f=l["".concat(u,".").concat(m)]||l[m]||d[m]||o;return r?n.createElement(f,i(i({ref:t},p),{},{components:r})):n.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var s={};for(var u in t)hasOwnProperty.call(t,u)&&(s[u]=t[u]);s.originalType=e,s[l]="string"==typeof e?e:a,i[1]=s;for(var c=2;c=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=n.createContext({}),s=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(u.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,u=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=s(r),m=a,g=c["".concat(u,".").concat(m)]||c[m]||d[m]||o;return r?n.createElement(g,i(i({ref:t},p),{},{components:r})):n.createElement(g,i({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[c]="string"==typeof e?e:a,i[1]=l;for(var s=2;s=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var u=n.createContext({}),s=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(u.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,u=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=s(r),m=a,g=c["".concat(u,".").concat(m)]||c[m]||d[m]||o;return r?n.createElement(g,i(i({ref:t},p),{},{components:r})):n.createElement(g,i({ref:t},p))}));function g(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[c]="string"==typeof e?e:a,i[1]=l;for(var s=2;s=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),u=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=r,h=p["".concat(s,".").concat(d)]||p[d]||g[d]||i;return a?n.createElement(h,o(o({ref:t},c),{},{components:a})):n.createElement(h,o({ref:t},c))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var u=2;u=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),u=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",g={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=u(a),d=r,h=p["".concat(s,".").concat(d)]||p[d]||g[d]||i;return a?n.createElement(h,o(o({ref:t},c),{},{components:a})):n.createElement(h,o({ref:t},c))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,o[1]=l;for(var u=2;u=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var p=r.createContext({}),l=function(e){var t=r.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},i=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,s=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(a),f=n,g=u["".concat(p,".").concat(f)]||u[f]||h[f]||s;return a?r.createElement(g,o(o({ref:t},i),{},{components:a})):r.createElement(g,o({ref:t},i))}));function g(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var s=a.length,o=new Array(s);o[0]=f;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:n,o[1]=c;for(var l=2;l=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var p=r.createContext({}),l=function(e){var t=r.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},i=function(e){var t=l(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,s=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(a),f=n,g=u["".concat(p,".").concat(f)]||u[f]||h[f]||s;return a?r.createElement(g,o(o({ref:t},i),{},{components:a})):r.createElement(g,o({ref:t},i))}));function g(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var s=a.length,o=new Array(s);o[0]=f;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:n,o[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(r),m=a,k=p["".concat(s,".").concat(m)]||p[m]||d[m]||o;return r?n.createElement(k,l(l({ref:t},c),{},{components:r})):n.createElement(k,l({ref:t},c))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,l=new Array(o);l[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:a,l[1]=i;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),p=u(r),m=a,k=p["".concat(s,".").concat(m)]||p[m]||d[m]||o;return r?n.createElement(k,l(l({ref:t},c),{},{components:r})):n.createElement(k,l({ref:t},c))}));function k(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,l=new Array(o);l[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[p]="string"==typeof e?e:a,l[1]=i;for(var u=2;u=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(n),h=o,m=d["".concat(c,".").concat(h)]||d[h]||p[h]||r;return n?a.createElement(m,i(i({ref:t},u),{},{components:n})):a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var l=2;l:7777 \\\n--secret-key .pem \\\n--chain-name casper-test \\\n--payment-amount 2500000000 \\\n--session-path \\\n--session-arg \"deployment-account:account_hash='account-hash-'\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the main account"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the deploy (this example uses the Testnet)"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The cost of the deploy. This example uses 2.5 CSPR, which may need to be adjusted based on the network ",(0,r.kt)("a",{parentName:"li",href:"/concepts/glossary/C#chainspec"},"chainspec"),"."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the contract Wasm"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-arg")," - The contract takes the account hash of the associated account as an argument labeled ",(0,r.kt)("inlineCode",{parentName:"li"},"deployment-account"),". You can pass this argument using the ",(0,r.kt)("inlineCode",{parentName:"li"},"--session-arg")," flag in the command line client")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Important response fields:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},'"result"."deploy_hash"')," - the address of the executed deploy, needed to look up additional information about the transfer")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note"),": Save the returned ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," from the output to query information about execution status."),(0,r.kt)("h3",{id:"confirming-execution-and-account-status"},"Confirming Processing and Account Status"),(0,r.kt)("p",null,"Account configuration on a Casper blockchain is stored in a ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/M#merkle-tree"},"Merkle Tree")," and is a snapshot of the blockchain's ",(0,r.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#global-state-head"},"Global State"),". The representation of global state for a given block can be computed by executing the deploys (including transfers) within the block and its ancestors. The root node of the Merkle Tree identifying a particular state is called the ",(0,r.kt)("inlineCode",{parentName:"p"},"state-root-hash")," and is stored in every executed block."),(0,r.kt)("p",null,"To check that the account was configured correctly, you need the ",(0,r.kt)("inlineCode",{parentName:"p"},"state-root-hash")," corresponding to the block that contains your deploy. To obtain the ",(0,r.kt)("inlineCode",{parentName:"p"},"state-root-hash"),", you need to:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"/resources/tutorials/beginner/querying-network#querying-deploys"},"Confirm the execution status of the deploy")," and obtain the hash of the block containing it"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"/resources/tutorials/beginner/querying-network#querying-blocks"},"Query the block containing the deploy")," to obtain the corresponding ",(0,r.kt)("inlineCode",{parentName:"li"},"state_root_hash"))),(0,r.kt)("p",null,"Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"state_root_hash")," and the ",(0,r.kt)("inlineCode",{parentName:"p"},"hex-encoded-public-key")," of the main account, query the network and check the account's configuration."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n--node-address http://:7777 \\\n--state-root-hash \\\n--key \n")),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Example output"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": 1126043166167626077,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "merkle_proof": "2226 chars",\n "stored_value": {\n "Account": {\n "account_hash": "account-hash-dc88a1819381c5ebbc3432e5c1d94df18cdcd7253b85259eeebe0ec8661bb84a",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 2\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-12dee9fe535bfd8fd335fce1ba1f972f26bb60029a303b310d85419357d18f51",\n "weight": 1\n },\n {\n "account_hash": "account-hash-dc88a1819381c5ebbc3432e5c1d94df18cdcd7253b85259eeebe0ec8661bb84a",\n "weight": 1\n }\n ],\n "main_purse": "uref-74b20e9722d3f087f9dc431e9f0fcc6a803c256e005fa45b64a101512001cb78-007",\n "named_keys": []\n }\n }\n }\n}\n'))),(0,r.kt)("p",null,"In the example output, you can see the account hashes listed within the ",(0,r.kt)("inlineCode",{parentName:"p"},"associated_keys")," section. Each key has weight ",(0,r.kt)("inlineCode",{parentName:"p"},"1"),"; since the action threshold for ",(0,r.kt)("inlineCode",{parentName:"p"},"deployment")," is ",(0,r.kt)("inlineCode",{parentName:"p"},"2"),", neither account can sign and send a deploy individually. Thus, the deploy needs to be signed by the secret keys of each account to reach the required threshold."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/efa2c7c1.a1e3c8eb.js b/assets/js/efa2c7c1.a1e3c8eb.js deleted file mode 100644 index 87261b8861..0000000000 --- a/assets/js/efa2c7c1.a1e3c8eb.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5962],{3905:function(e,t,n){n.d(t,{Zo:function(){return u},kt:function(){return m}});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=a.createContext({}),l=function(e){var t=a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=l(e.components);return a.createElement(c.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=l(n),h=o,m=d["".concat(c,".").concat(h)]||d[h]||p[h]||r;return n?a.createElement(m,i(i({ref:t},u),{},{components:n})):a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=h;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:o,i[1]=s;for(var l=2;l:7777 \\\n--secret-key .pem \\\n--chain-name casper-test \\\n--payment-amount 2500000000 \\\n--session-path \\\n--session-arg \"deployment-account:account_hash='account-hash-'\"\n")),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"node-address")," - An IP address of a node on the network"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"secret-key")," - The file name containing the secret key of the main account"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"chain-name")," - The chain-name to the network where you wish to send the deploy (this example uses the Testnet)"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"payment-amount")," - The cost of the deploy. This example uses 2.5 CSPR, which may need to be adjusted based on the network ",(0,r.kt)("a",{parentName:"li",href:"/concepts/glossary/C#chainspec"},"chainspec"),"."),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-path")," - The path to the contract Wasm"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("inlineCode",{parentName:"li"},"session-arg")," - The contract takes the account hash of the associated account as an argument labeled ",(0,r.kt)("inlineCode",{parentName:"li"},"deployment-account"),". You can pass this argument using the ",(0,r.kt)("inlineCode",{parentName:"li"},"--session-arg")," flag in the command line client")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Important response fields:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},'"result"."deploy_hash"')," - the address of the executed deploy, needed to look up additional information about the transfer")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note"),": Save the returned ",(0,r.kt)("inlineCode",{parentName:"p"},"deploy_hash")," from the output to query information about execution status."),(0,r.kt)("h3",{id:"confirming-execution-and-account-status"},"Confirming Processing and Account Status"),(0,r.kt)("p",null,"Account configuration on a Casper blockchain is stored in a ",(0,r.kt)("a",{parentName:"p",href:"/concepts/glossary/M#merkle-tree"},"Merkle Tree")," and is a snapshot of the blockchain's ",(0,r.kt)("a",{parentName:"p",href:"/concepts/design/casper-design#global-state-head"},"Global State"),". The representation of global state for a given block can be computed by executing the deploys (including transfers) within the block and its ancestors. The root node of the Merkle Tree identifying a particular state is called the ",(0,r.kt)("inlineCode",{parentName:"p"},"state-root-hash")," and is stored in every executed block."),(0,r.kt)("p",null,"To check that the account was configured correctly, you need the ",(0,r.kt)("inlineCode",{parentName:"p"},"state-root-hash")," corresponding to the block that contains your deploy. To obtain the ",(0,r.kt)("inlineCode",{parentName:"p"},"state-root-hash"),", you need to:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"/resources/tutorials/beginner/querying-network#querying-deploys"},"Confirm the execution status of the deploy")," and obtain the hash of the block containing it"),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("a",{parentName:"li",href:"/resources/tutorials/beginner/querying-network#querying-blocks"},"Query the block containing the deploy")," to obtain the corresponding ",(0,r.kt)("inlineCode",{parentName:"li"},"state_root_hash"))),(0,r.kt)("p",null,"Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"state_root_hash")," and the ",(0,r.kt)("inlineCode",{parentName:"p"},"hex-encoded-public-key")," of the main account, query the network and check the account's configuration."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"casper-client query-global-state \\\n--node-address http://:7777 \\\n--state-root-hash \\\n--key \n")),(0,r.kt)("details",null,(0,r.kt)("summary",null,"Example output"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n "id": 1126043166167626077,\n "jsonrpc": "2.0",\n "result": {\n "api_version": "1.0.0",\n "merkle_proof": "2226 chars",\n "stored_value": {\n "Account": {\n "account_hash": "account-hash-dc88a1819381c5ebbc3432e5c1d94df18cdcd7253b85259eeebe0ec8661bb84a",\n "action_thresholds": {\n "deployment": 2,\n "key_management": 2\n },\n "associated_keys": [\n {\n "account_hash": "account-hash-12dee9fe535bfd8fd335fce1ba1f972f26bb60029a303b310d85419357d18f51",\n "weight": 1\n },\n {\n "account_hash": "account-hash-dc88a1819381c5ebbc3432e5c1d94df18cdcd7253b85259eeebe0ec8661bb84a",\n "weight": 1\n }\n ],\n "main_purse": "uref-74b20e9722d3f087f9dc431e9f0fcc6a803c256e005fa45b64a101512001cb78-007",\n "named_keys": []\n }\n }\n }\n}\n'))),(0,r.kt)("p",null,"In the example output, you can see the account hashes listed within the ",(0,r.kt)("inlineCode",{parentName:"p"},"associated_keys")," section. Each key has weight ",(0,r.kt)("inlineCode",{parentName:"p"},"1"),"; since the action threshold for ",(0,r.kt)("inlineCode",{parentName:"p"},"deployment")," is ",(0,r.kt)("inlineCode",{parentName:"p"},"2"),", neither account can sign and send a deploy individually. Thus, the deploy needs to be signed by the secret keys of each account to reach the required threshold."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f12850af.88a1f821.js b/assets/js/f12850af.e9eb2c4f.js similarity index 63% rename from assets/js/f12850af.88a1f821.js rename to assets/js/f12850af.e9eb2c4f.js index c4b64128f1..d1a970928f 100644 --- a/assets/js/f12850af.88a1f821.js +++ b/assets/js/f12850af.e9eb2c4f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[9964],{3905:function(e,t,r){r.d(t,{Zo:function(){return c},kt:function(){return m}});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},l="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),l=u(r),f=a,m=l["".concat(s,".").concat(f)]||l[f]||d[f]||o;return r?n.createElement(m,i(i({ref:t},c),{},{components:r})):n.createElement(m,i({ref:t},c))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[l]="string"==typeof e?e:a,i[1]=p;for(var u=2;u=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),u=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},l="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=p(e,["components","mdxType","originalType","parentName"]),l=u(r),f=a,m=l["".concat(s,".").concat(f)]||l[f]||d[f]||o;return r?n.createElement(m,i(i({ref:t},c),{},{components:r})):n.createElement(m,i({ref:t},c))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=f;var p={};for(var s in t)hasOwnProperty.call(t,s)&&(p[s]=t[s]);p.originalType=e,p[l]="string"==typeof e?e:a,i[1]=p;for(var u=2;u=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var i=n.createContext({}),l=function(t){var e=n.useContext(i),a=e;return t&&(a="function"==typeof t?t(e):o(o({},e),t)),a},h=function(t){var e=l(t.components);return n.createElement(i.Provider,{value:e},t.children)},p="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},d=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,c=t.originalType,i=t.parentName,h=s(t,["components","mdxType","originalType","parentName"]),p=l(a),d=r,k=p["".concat(i,".").concat(d)]||p[d]||u[d]||c;return a?n.createElement(k,o(o({ref:e},h),{},{components:a})):n.createElement(k,o({ref:e},h))}));function k(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var c=a.length,o=new Array(c);o[0]=d;var s={};for(var i in e)hasOwnProperty.call(e,i)&&(s[i]=e[i]);s.originalType=t,s[p]="string"==typeof t?t:r,o[1]=s;for(var l=2;l=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var c=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var i=n.createContext({}),l=function(t){var e=n.useContext(i),a=e;return t&&(a="function"==typeof t?t(e):o(o({},e),t)),a},h=function(t){var e=l(t.components);return n.createElement(i.Provider,{value:e},t.children)},p="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},d=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,c=t.originalType,i=t.parentName,h=s(t,["components","mdxType","originalType","parentName"]),p=l(a),d=r,k=p["".concat(i,".").concat(d)]||p[d]||u[d]||c;return a?n.createElement(k,o(o({ref:e},h),{},{components:a})):n.createElement(k,o({ref:e},h))}));function k(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var c=a.length,o=new Array(c);o[0]=d;var s={};for(var i in e)hasOwnProperty.call(e,i)&&(s[i]=e[i]);s.originalType=t,s[p]="string"==typeof t?t:r,o[1]=s;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),d=a,h=u["".concat(p,".").concat(d)]||u[d]||f[d]||o;return r?n.createElement(h,s(s({ref:t},i),{},{components:r})):n.createElement(h,s({ref:t},i))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},i=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,i=c(e,["components","mdxType","originalType","parentName"]),u=l(r),d=a,h=u["".concat(p,".").concat(d)]||u[d]||f[d]||o;return r?n.createElement(h,s(s({ref:t},i),{},{components:r})):n.createElement(h,s({ref:t},i))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var l=2;l=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),h=c(n),d=r,m=h["".concat(i,".").concat(d)]||h[d]||p[d]||o;return n?a.createElement(m,s(s({ref:t},u),{},{components:n})):a.createElement(m,s({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=d;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[h]="string"==typeof e?e:r,s[1]=l;for(var c=2;c=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),h=c(n),d=r,m=h["".concat(i,".").concat(d)]||h[d]||p[d]||o;return n?a.createElement(m,s(s({ref:t},u),{},{components:n})):a.createElement(m,s({ref:t},u))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=d;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[h]="string"==typeof e?e:r,s[1]=l;for(var c=2;c=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=n.createContext({}),l=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=l(e.components);return n.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=l(r),m=o,f=p["".concat(u,".").concat(m)]||p[m]||d[m]||a;return r?n.createElement(f,i(i({ref:t},s),{},{components:r})):n.createElement(f,i({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c[p]="string"==typeof e?e:o,i[1]=c;for(var l=2;l=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var u=n.createContext({}),l=function(e){var t=n.useContext(u),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},s=function(e){var t=l(e.components);return n.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,s=c(e,["components","mdxType","originalType","parentName"]),p=l(r),m=o,f=p["".concat(u,".").concat(m)]||p[m]||d[m]||a;return r?n.createElement(f,i(i({ref:t},s),{},{components:r})):n.createElement(f,i({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=m;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c[p]="string"==typeof e?e:o,i[1]=c;for(var l=2;l=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,s=e.mdxType,i=e.originalType,l=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),m=c(n),u=s,h=m["".concat(l,".").concat(u)]||m[u]||d[u]||i;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var i=n.length,r=new Array(i);r[0]=u;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[m]="string"==typeof e?e:s,r[1]=o;for(var c=2;c\'"` \\\n--session-arg "token_owner:key=\'account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb\'" \\\n--session-arg "token_meta_data:string=\'{\\"name\\": \\"John Doe\\",\\"token_uri\\": \\"https:\\/\\/www.barfoo.com\\",\\"checksum\\": \\"940bffb3f2bba35f84313aa26da09ece3ad47045c6a1292c2bbd2df4ab1a55fb\\"}\'"\n\n'))),(0,i.kt)("h2",{id:"transferring-nfts-between-users"},"Transferring NFTs Between Users"),(0,i.kt)("p",null,"Below is an example of a ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-client")," command that uses the ",(0,i.kt)("inlineCode",{parentName:"p"},"transfer")," function to transfer ownership of an NFT from one user to another. In this case, we are transferring the previously minted NFT from the user associated with ",(0,i.kt)("inlineCode",{parentName:"p"},"node-2")," to the user associated with ",(0,i.kt)("inlineCode",{parentName:"p"},"node-3"),"."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},'casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" --payment-amount 5000000000 -k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-2/keys/secret_key.pem --session-path ~/casper/enhanced-nft/client/transfer_session/target/wasm32-unknown-unknown/release/transfer_call.wasm'))),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"nft_contract_hash:key='hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5'\"")),(0,i.kt)("p",{parentName:"li"},"The contract hash of the CEP-78 NFT Contract associated with the NFT to be transferred.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"source_key:key='account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb'\"")),(0,i.kt)("p",{parentName:"li"},"The account hash of the user that currently owns the NFT and wishes to transfer it.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"target_key:key='account-hash-b4772e7c47e4deca5bd90b7adb2d6e884f2d331825d5419d6cbfb59e17642aab'\"")),(0,i.kt)("p",{parentName:"li"},"The account hash of the user that will receive the NFT.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"is_hash_identifier_mode:bool='false'\"")),(0,i.kt)("p",{parentName:"li"},"Argument that the hash identifier mode is ordinal, thereby requiring a ",(0,i.kt)("inlineCode",{parentName:"p"},"token_id")," rather than a ",(0,i.kt)("inlineCode",{parentName:"p"},"token_hash"),".")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"token_id:u64='0'\"")),(0,i.kt)("p",{parentName:"li"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"token_id")," of the NFT to be transferred."))),(0,i.kt)("details",null,(0,i.kt)("summary",null,(0,i.kt)("b",null,"Casper client command without comments")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" \\\n--payment-amount 5000000000 \\\n-k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-2/keys/secret_key.pem \\\n--session-path ~/casper/enhanced-nft/client/transfer_session/target/wasm32-unknown-unknown/release/transfer_call.wasm \\\n--session-arg "nft_contract_hash:key=\'hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5\'" \\\n--session-arg "source_key:key=\'account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb\'" \\\n--session-arg "target_key:key=\'account-hash-b4772e7c47e4deca5bd90b7adb2d6e884f2d331825d5419d6cbfb59e17642aab\'" \\\n--session-arg "is_hash_identifier_mode:bool=\'false\'" \\\n--session-arg "token_id:u64=\'0\'"\n'))),(0,i.kt)("h2",{id:"burning-an-nft"},"Burning an NFT"),(0,i.kt)("p",null,"Below is an example of a ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-client")," command that uses the ",(0,i.kt)("inlineCode",{parentName:"p"},"burn")," function to burn an NFT within a CEP-78 collection. If this command is used, the NFT in question will no longer be accessible by anyone."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},'casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" --payment-amount 5000000000 -k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem'))),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-hash hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5")),(0,i.kt)("p",{parentName:"li"},"The session hash corresponding to the NFT's contract hash.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},'--session-entry-point "burn"')),(0,i.kt)("p",{parentName:"li"},"The entrypoint corresponding to the ",(0,i.kt)("inlineCode",{parentName:"p"},"burn")," function.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"token_id:u64='1'\"")),(0,i.kt)("p",{parentName:"li"},"The token ID for the NFT to be burned. If the ",(0,i.kt)("inlineCode",{parentName:"p"},"identifier_mode")," is not set to ",(0,i.kt)("inlineCode",{parentName:"p"},"Ordinal"),", you must provide the ",(0,i.kt)("inlineCode",{parentName:"p"},"token_hash")," instead."))),(0,i.kt)("details",null,(0,i.kt)("summary",null,(0,i.kt)("b",null,"Casper client command without comments")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" \\\n--payment-amount 5000000000 \\\n-k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem \\\n--session-hash hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5 \\\n--session-entry-point "burn" \\\n--session-arg "token_id:u64=\'1\'"\n'))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f8f33652.97f1dcda.js b/assets/js/f8f33652.97f1dcda.js deleted file mode 100644 index e0536f6fae..0000000000 --- a/assets/js/f8f33652.97f1dcda.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[7022],{3905:function(e,t,n){n.d(t,{Zo:function(){return p},kt:function(){return h}});var a=n(7294);function s(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,s=e.mdxType,i=e.originalType,l=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),m=c(n),u=s,h=m["".concat(l,".").concat(u)]||m[u]||d[u]||i;return n?a.createElement(h,r(r({ref:t},p),{},{components:n})):a.createElement(h,r({ref:t},p))}));function h(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var i=n.length,r=new Array(i);r[0]=u;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[m]="string"==typeof e?e:s,r[1]=o;for(var c=2;c\'"` \\\n--session-arg "token_owner:key=\'account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb\'" \\\n--session-arg "token_meta_data:string=\'{\\"name\\": \\"John Doe\\",\\"token_uri\\": \\"https:\\/\\/www.barfoo.com\\",\\"checksum\\": \\"940bffb3f2bba35f84313aa26da09ece3ad47045c6a1292c2bbd2df4ab1a55fb\\"}\'"\n\n'))),(0,i.kt)("h2",{id:"transferring-nfts-between-users"},"Transferring NFTs Between Users"),(0,i.kt)("p",null,"Below is an example of a ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-client")," command that uses the ",(0,i.kt)("inlineCode",{parentName:"p"},"transfer")," function to transfer ownership of an NFT from one user to another. In this case, we are transferring the previously minted NFT from the user associated with ",(0,i.kt)("inlineCode",{parentName:"p"},"node-2")," to the user associated with ",(0,i.kt)("inlineCode",{parentName:"p"},"node-3"),"."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},'casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" --payment-amount 5000000000 -k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-2/keys/secret_key.pem --session-path ~/casper/enhanced-nft/client/transfer_session/target/wasm32-unknown-unknown/release/transfer_call.wasm'))),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"nft_contract_hash:key='hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5'\"")),(0,i.kt)("p",{parentName:"li"},"The contract hash of the CEP-78 NFT Contract associated with the NFT to be transferred.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"source_key:key='account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb'\"")),(0,i.kt)("p",{parentName:"li"},"The account hash of the user that currently owns the NFT and wishes to transfer it.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"target_key:key='account-hash-b4772e7c47e4deca5bd90b7adb2d6e884f2d331825d5419d6cbfb59e17642aab'\"")),(0,i.kt)("p",{parentName:"li"},"The account hash of the user that will receive the NFT.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"is_hash_identifier_mode:bool='false'\"")),(0,i.kt)("p",{parentName:"li"},"Argument that the hash identifier mode is ordinal, thereby requiring a ",(0,i.kt)("inlineCode",{parentName:"p"},"token_id")," rather than a ",(0,i.kt)("inlineCode",{parentName:"p"},"token_hash"),".")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"token_id:u64='0'\"")),(0,i.kt)("p",{parentName:"li"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"token_id")," of the NFT to be transferred."))),(0,i.kt)("details",null,(0,i.kt)("summary",null,(0,i.kt)("b",null,"Casper client command without comments")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" \\\n--payment-amount 5000000000 \\\n-k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-2/keys/secret_key.pem \\\n--session-path ~/casper/enhanced-nft/client/transfer_session/target/wasm32-unknown-unknown/release/transfer_call.wasm \\\n--session-arg "nft_contract_hash:key=\'hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5\'" \\\n--session-arg "source_key:key=\'account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb\'" \\\n--session-arg "target_key:key=\'account-hash-b4772e7c47e4deca5bd90b7adb2d6e884f2d331825d5419d6cbfb59e17642aab\'" \\\n--session-arg "is_hash_identifier_mode:bool=\'false\'" \\\n--session-arg "token_id:u64=\'0\'"\n'))),(0,i.kt)("h2",{id:"burning-an-nft"},"Burning an NFT"),(0,i.kt)("p",null,"Below is an example of a ",(0,i.kt)("inlineCode",{parentName:"p"},"casper-client")," command that uses the ",(0,i.kt)("inlineCode",{parentName:"p"},"burn")," function to burn an NFT within a CEP-78 collection. If this command is used, the NFT in question will no longer be accessible by anyone."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},'casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" --payment-amount 5000000000 -k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem'))),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-hash hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5")),(0,i.kt)("p",{parentName:"li"},"The session hash corresponding to the NFT's contract hash.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},'--session-entry-point "burn"')),(0,i.kt)("p",{parentName:"li"},"The entrypoint corresponding to the ",(0,i.kt)("inlineCode",{parentName:"p"},"burn")," function.")),(0,i.kt)("li",{parentName:"ol"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"p"},"--session-arg \"token_id:u64='1'\"")),(0,i.kt)("p",{parentName:"li"},"The token ID for the NFT to be burned. If the ",(0,i.kt)("inlineCode",{parentName:"p"},"identifier_mode")," is not set to ",(0,i.kt)("inlineCode",{parentName:"p"},"Ordinal"),", you must provide the ",(0,i.kt)("inlineCode",{parentName:"p"},"token_hash")," instead."))),(0,i.kt)("details",null,(0,i.kt)("summary",null,(0,i.kt)("b",null,"Casper client command without comments")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},'casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" \\\n--payment-amount 5000000000 \\\n-k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem \\\n--session-hash hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5 \\\n--session-entry-point "burn" \\\n--session-arg "token_id:u64=\'1\'"\n'))))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/fa593e9e.0d6b2eb1.js b/assets/js/fa593e9e.0d6b2eb1.js new file mode 100644 index 0000000000..a362766f1d --- /dev/null +++ b/assets/js/fa593e9e.0d6b2eb1.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[5199],{3905:function(e,t,r){r.d(t,{Zo:function(){return p},kt:function(){return h}});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=l(r),f=o,h=u["".concat(c,".").concat(f)]||u[f]||d[f]||a;return r?n.createElement(h,s(s({ref:t},p),{},{components:r})):n.createElement(h,s({ref:t},p))}));function h(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=f;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var l=2;l=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),u=l(r),f=o,h=u["".concat(c,".").concat(f)]||u[f]||d[f]||a;return r?n.createElement(h,s(s({ref:t},p),{},{components:r})):n.createElement(h,s({ref:t},p))}));function h(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,s=new Array(a);s[0]=f;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:o,s[1]=i;for(var l=2;l=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),i=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},l=function(e){var t=i(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=i(r),d=a,m=u["".concat(p,".").concat(d)]||u[d]||f[d]||o;return r?n.createElement(m,s(s({ref:t},l),{},{components:r})):n.createElement(m,s({ref:t},l))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var i=2;i=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),i=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):s(s({},t),e)),r},l=function(e){var t=i(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,p=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),u=i(r),d=a,m=u["".concat(p,".").concat(d)]||u[d]||f[d]||o;return r?n.createElement(m,s(s({ref:t},l),{},{components:r})):n.createElement(m,s({ref:t},l))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,s=new Array(o);s[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[u]="string"==typeof e?e:a,s[1]=c;for(var i=2;i=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var d=n.createContext({}),c=function(e){var t=n.useContext(d),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},l=function(e){var t=c(e.components);return n.createElement(d.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(a),m=r,f=p["".concat(d,".").concat(m)]||p[m]||u[m]||o;return a?n.createElement(f,i(i({ref:t},l),{},{components:a})):n.createElement(f,i({ref:t},l))}));function f(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=m;var s={};for(var d in t)hasOwnProperty.call(t,d)&&(s[d]=t[d]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;cruntime::put_key / runtime::get_key",id:"runtimeput_key--runtimeget_key",level:3},{value:"storage::write / storage::read",id:"storagewrite--storageread",level:3},{value:"storage:dictionary_put / storage::dictionary_get",id:"storagedictionary_put--storagedictionary_get",level:3},{value:"Example Code",id:"example-code",level:2},{value:"Example of put_key and storage::write",id:"example-of-put_key-and-storagewrite",level:3},{value:"Example of get_key and storage::read",id:"example-of-get_key-and-storageread",level:3},{value:"Example of dictionary_put and dictionary_get",id:"example-of-dictionary_put-and-dictionary_get",level:3},{value:"Additional Functions for Named Keys",id:"additional-functions-for-named-keys",level:2}],u={toc:p},m="wrapper";function f(e){var t=e.components,a=(0,r.Z)(e,i);return(0,o.kt)(m,(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"reading-and-writing-to-global-state-using-rust"},"Reading and Writing to Global State using Rust"),(0,o.kt)("p",null,"The following examples outline methods to read and write data to global state on a Casper network using the Rust programming language."),(0,o.kt)("p",null,"Essentially, there are three means of storage within the Casper ecosystem. These consist of ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime::put_key"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::write"),"(alongside ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::new_uref")," as explained below) and ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::dictionary_put"),". These stored values can be read using ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime::get_key"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::read")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::dictionary_get"),", respectively. Each method stores data in a specific way, and it's important to understand the differences."),(0,o.kt)("h2",{id:"description-of-functions"},"Description of Functions"),(0,o.kt)("h3",{id:"runtimeput_key--runtimeget_key"},(0,o.kt)("inlineCode",{parentName:"h3"},"runtime::put_key")," / ",(0,o.kt)("inlineCode",{parentName:"h3"},"runtime::get_key")),(0,o.kt)("p",null,"Both the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.put_key.html"},(0,o.kt)("inlineCode",{parentName:"a"},"put_key"))," and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.get_key.html"},(0,o.kt)("inlineCode",{parentName:"a"},"get_key"))," functions refer to Casper ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," types as outlined in both the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#serialization-standard-state-keys"},"Understanding Hash Types")," and ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#serialization-standard-state-keys"},"Serialization Standard"),". These keys are stored within a URef as a ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," type."),(0,o.kt)("h3",{id:"storagewrite--storageread"},(0,o.kt)("inlineCode",{parentName:"h3"},"storage::write")," / ",(0,o.kt)("inlineCode",{parentName:"h3"},"storage::read")),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.write.html"},(0,o.kt)("inlineCode",{parentName:"a"},"storage::write"))," writes a given value to a previously established URef (created using ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_uref.html"},(0,o.kt)("inlineCode",{parentName:"a"},"storage::new_uref")),"). Unlike ",(0,o.kt)("inlineCode",{parentName:"p"},"put_key"),", this value is not one of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," types listed above, but rather any of the potential ",(0,o.kt)("a",{parentName:"p",href:"https://docs.casperlabs.io/developers/json-rpc/types_cl/#cltype"},(0,o.kt)("inlineCode",{parentName:"a"},"CLType")),"s as outlined. ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.read.html"},(0,o.kt)("inlineCode",{parentName:"a"},"storage::read"))," provides a method to retrieve these values from the associated URef."),(0,o.kt)("h3",{id:"storagedictionary_put--storagedictionary_get"},(0,o.kt)("inlineCode",{parentName:"h3"},"storage:dictionary_put")," / ",(0,o.kt)("inlineCode",{parentName:"h3"},"storage::dictionary_get")),(0,o.kt)("p",null,"For most data storage needs on a Casper network, dictionaries are more efficient and provide lower gas costs than ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys"),". Each dictionary item exists independently, sharing a single dictionary seed URef for reference purposes."),(0,o.kt)("p",null,"More information on dictionaries can be found on the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/dictionaries"},"Reading and Writing to Dictionaries")," page."),(0,o.kt)("h2",{id:"example-code"},"Example Code"),(0,o.kt)("h3",{id:"example-of-put_key-and-storagewrite"},"Example of ",(0,o.kt)("inlineCode",{parentName:"h3"},"put_key")," and ",(0,o.kt)("inlineCode",{parentName:"h3"},"storage::write")),(0,o.kt)("p",null,"This sample code creates a new contract and stores the contract hash in global state using the ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime::put_key")," function."),(0,o.kt)("p",null,"Once the stored value has been initialized, the ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::write")," function overwrites the existing value with ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),". The URef is then stored in the current context as a ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKey")," titled ",(0,o.kt)("inlineCode",{parentName:"p"},"MY_STORED_VALUE_UREF"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"\n // Store contract hash under a Named key CONTRACT_HASH\n runtime::put_key(CONTRACT_HASH, contract_hash.into());\n\n // Store !MY_STORED_VALUE (false) as init value/type into a new URef\n let my_value_uref = storage::new_uref(!MY_STORED_VALUE);\n\n // Store MY_STORED_VALUE (true) under the URef value\n storage::write(my_value_uref, MY_STORED_VALUE);\n\n // Store the Uref under a Named key MY_STORED_VALUE_UREF\n let my_value_key: Key = my_value_uref.into();\n runtime::put_key(MY_STORED_VALUE_UREF, my_value_key);\n}\n\n")),(0,o.kt)("h3",{id:"example-of-get_key-and-storageread"},"Example of ",(0,o.kt)("inlineCode",{parentName:"h3"},"get_key")," and ",(0,o.kt)("inlineCode",{parentName:"h3"},"storage::read")),(0,o.kt)("p",null,"This example compliments the code sample above by retrieving the ",(0,o.kt)("inlineCode",{parentName:"p"},"CONTRACT_HASH")," using the ",(0,o.kt)("inlineCode",{parentName:"p"},"get_key")," function, before comparing a provided runtime argument ",(0,o.kt)("inlineCode",{parentName:"p"},"ARG_MY_STORED_VALUE")," against the previously stored ",(0,o.kt)("inlineCode",{parentName:"p"},"MY_STORED_VALUE_UREF")," using ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::read"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"\n let my_stored_value_uref: URef = runtime::get_key(MY_STORED_VALUE_UREF)\n .unwrap_or_revert()\n .into_uref()\n .map(|uref| URef::new(uref.addr(), AccessRights::default()))\n .unwrap_or_revert()\n .into_read();\n\n let my_actual_stored_value: bool = storage::read(my_stored_value_uref).unwrap().unwrap();\n\n // Compare my stored value with runtime arg\n let my_expected_stored_value: bool = runtime::get_named_arg(ARG_MY_STORED_VALUE);\n if my_actual_stored_value != my_expected_stored_value {\n // We revert if my stored value is not what is expected from caller argument\n runtime::revert(UserError::StoredValueError);\n }\n\n runtime::print(&my_actual_stored_value.to_string());\n}\n\n")),(0,o.kt)("h3",{id:"example-of-dictionary_put-and-dictionary_get"},"Example of ",(0,o.kt)("inlineCode",{parentName:"h3"},"dictionary_put")," and ",(0,o.kt)("inlineCode",{parentName:"h3"},"dictionary_get")),(0,o.kt)("p",null,"Examples of dictionary usage for storage can be found in the ",(0,o.kt)("em",{parentName:"p"},"Writing Entries into a Dictionary")," section of ",(0,o.kt)("a",{parentName:"p",href:"/concepts/dictionaries#writing-entries-into-a-dictionary"},"Reading and Writing to Dictionaries"),"."),(0,o.kt)("h2",{id:"additional-functions-for-named-keys"},"Additional Functions for Named Keys"),(0,o.kt)("p",null,"The following functions might also be of interest for working with named keys:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.list_named_keys.html"},"list_named_keys")," - Returns the named keys of the current context"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.has_key.html"},"has_key")," - Returns true if the key exists in the current context\u2019s named keys"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.remove_key.html"},"remove_key")," - Removes the requested ",(0,o.kt)("inlineCode",{parentName:"li"},"NamedKey")," from the current context")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/fec0de85.df3d6a30.js b/assets/js/fec0de85.df3d6a30.js new file mode 100644 index 0000000000..f2df4bff32 --- /dev/null +++ b/assets/js/fec0de85.df3d6a30.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[4875],{3905:function(e,t,a){a.d(t,{Zo:function(){return l},kt:function(){return f}});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var d=n.createContext({}),c=function(e){var t=n.useContext(d),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},l=function(e){var t=c(e.components);return n.createElement(d.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,d=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),p=c(a),m=r,f=p["".concat(d,".").concat(m)]||p[m]||u[m]||o;return a?n.createElement(f,i(i({ref:t},l),{},{components:a})):n.createElement(f,i({ref:t},l))}));function f(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=m;var s={};for(var d in t)hasOwnProperty.call(t,d)&&(s[d]=t[d]);s.originalType=e,s[p]="string"==typeof e?e:r,i[1]=s;for(var c=2;cruntime::put_key / runtime::get_key",id:"runtimeput_key--runtimeget_key",level:3},{value:"storage::write / storage::read",id:"storagewrite--storageread",level:3},{value:"storage:dictionary_put / storage::dictionary_get",id:"storagedictionary_put--storagedictionary_get",level:3},{value:"Example Code",id:"example-code",level:2},{value:"Example of put_key and storage::write",id:"example-of-put_key-and-storagewrite",level:3},{value:"Example of get_key and storage::read",id:"example-of-get_key-and-storageread",level:3},{value:"Example of dictionary_put and dictionary_get",id:"example-of-dictionary_put-and-dictionary_get",level:3},{value:"Additional Functions for Named Keys",id:"additional-functions-for-named-keys",level:2}],u={toc:p},m="wrapper";function f(e){var t=e.components,a=(0,r.Z)(e,i);return(0,o.kt)(m,(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"reading-and-writing-to-global-state-using-rust"},"Reading and Writing to Global State using Rust"),(0,o.kt)("p",null,"The following examples outline methods to read and write data to global state on a Casper network using the Rust programming language."),(0,o.kt)("p",null,"Essentially, there are three means of storage within the Casper ecosystem. These consist of ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime::put_key"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::write"),"(alongside ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::new_uref")," as explained below) and ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::dictionary_put"),". These stored values can be read using ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime::get_key"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::read")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::dictionary_get"),", respectively. Each method stores data in a specific way, and it's important to understand the differences."),(0,o.kt)("h2",{id:"description-of-functions"},"Description of Functions"),(0,o.kt)("h3",{id:"runtimeput_key--runtimeget_key"},(0,o.kt)("inlineCode",{parentName:"h3"},"runtime::put_key")," / ",(0,o.kt)("inlineCode",{parentName:"h3"},"runtime::get_key")),(0,o.kt)("p",null,"Both the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.put_key.html"},(0,o.kt)("inlineCode",{parentName:"a"},"put_key"))," and ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.get_key.html"},(0,o.kt)("inlineCode",{parentName:"a"},"get_key"))," functions refer to Casper ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," types as outlined in both the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#serialization-standard-state-keys"},"Understanding Hash Types")," and ",(0,o.kt)("a",{parentName:"p",href:"/concepts/serialization-standard#serialization-standard-state-keys"},"Serialization Standard"),". These keys are stored within a URef as a ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," type."),(0,o.kt)("h3",{id:"storagewrite--storageread"},(0,o.kt)("inlineCode",{parentName:"h3"},"storage::write")," / ",(0,o.kt)("inlineCode",{parentName:"h3"},"storage::read")),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.write.html"},(0,o.kt)("inlineCode",{parentName:"a"},"storage::write"))," writes a given value to a previously established URef (created using ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.new_uref.html"},(0,o.kt)("inlineCode",{parentName:"a"},"storage::new_uref")),"). Unlike ",(0,o.kt)("inlineCode",{parentName:"p"},"put_key"),", this value is not one of the ",(0,o.kt)("inlineCode",{parentName:"p"},"Key")," types listed above, but rather any of the potential ",(0,o.kt)("a",{parentName:"p",href:"https://docs.casperlabs.io/developers/json-rpc/types_cl/#cltype"},(0,o.kt)("inlineCode",{parentName:"a"},"CLType")),"s as outlined. ",(0,o.kt)("a",{parentName:"p",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/storage/fn.read.html"},(0,o.kt)("inlineCode",{parentName:"a"},"storage::read"))," provides a method to retrieve these values from the associated URef."),(0,o.kt)("h3",{id:"storagedictionary_put--storagedictionary_get"},(0,o.kt)("inlineCode",{parentName:"h3"},"storage:dictionary_put")," / ",(0,o.kt)("inlineCode",{parentName:"h3"},"storage::dictionary_get")),(0,o.kt)("p",null,"For most data storage needs on a Casper network, dictionaries are more efficient and provide lower gas costs than ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKeys"),". Each dictionary item exists independently, sharing a single dictionary seed URef for reference purposes."),(0,o.kt)("p",null,"More information on dictionaries can be found on the ",(0,o.kt)("a",{parentName:"p",href:"/concepts/dictionaries"},"Reading and Writing to Dictionaries")," page."),(0,o.kt)("h2",{id:"example-code"},"Example Code"),(0,o.kt)("h3",{id:"example-of-put_key-and-storagewrite"},"Example of ",(0,o.kt)("inlineCode",{parentName:"h3"},"put_key")," and ",(0,o.kt)("inlineCode",{parentName:"h3"},"storage::write")),(0,o.kt)("p",null,"This sample code creates a new contract and stores the contract hash in global state using the ",(0,o.kt)("inlineCode",{parentName:"p"},"runtime::put_key")," function."),(0,o.kt)("p",null,"Once the stored value has been initialized, the ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::write")," function overwrites the existing value with ",(0,o.kt)("inlineCode",{parentName:"p"},"true"),". The URef is then stored in the current context as a ",(0,o.kt)("inlineCode",{parentName:"p"},"NamedKey")," titled ",(0,o.kt)("inlineCode",{parentName:"p"},"MY_STORED_VALUE_UREF"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"\n // Store contract hash under a Named key CONTRACT_HASH\n runtime::put_key(CONTRACT_HASH, contract_hash.into());\n\n // Store !MY_STORED_VALUE (false) as init value/type into a new URef\n let my_value_uref = storage::new_uref(!MY_STORED_VALUE);\n\n // Store MY_STORED_VALUE (true) under the URef value\n storage::write(my_value_uref, MY_STORED_VALUE);\n\n // Store the Uref under a Named key MY_STORED_VALUE_UREF\n let my_value_key: Key = my_value_uref.into();\n runtime::put_key(MY_STORED_VALUE_UREF, my_value_key);\n}\n\n")),(0,o.kt)("h3",{id:"example-of-get_key-and-storageread"},"Example of ",(0,o.kt)("inlineCode",{parentName:"h3"},"get_key")," and ",(0,o.kt)("inlineCode",{parentName:"h3"},"storage::read")),(0,o.kt)("p",null,"This example compliments the code sample above by retrieving the ",(0,o.kt)("inlineCode",{parentName:"p"},"CONTRACT_HASH")," using the ",(0,o.kt)("inlineCode",{parentName:"p"},"get_key")," function, before comparing a provided runtime argument ",(0,o.kt)("inlineCode",{parentName:"p"},"ARG_MY_STORED_VALUE")," against the previously stored ",(0,o.kt)("inlineCode",{parentName:"p"},"MY_STORED_VALUE_UREF")," using ",(0,o.kt)("inlineCode",{parentName:"p"},"storage::read"),"."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-rust"},"\n let my_stored_value_uref: URef = runtime::get_key(MY_STORED_VALUE_UREF)\n .unwrap_or_revert()\n .into_uref()\n .map(|uref| URef::new(uref.addr(), AccessRights::default()))\n .unwrap_or_revert()\n .into_read();\n\n let my_actual_stored_value: bool = storage::read(my_stored_value_uref).unwrap().unwrap();\n\n // Compare my stored value with runtime arg\n let my_expected_stored_value: bool = runtime::get_named_arg(ARG_MY_STORED_VALUE);\n if my_actual_stored_value != my_expected_stored_value {\n // We revert if my stored value is not what is expected from caller argument\n runtime::revert(UserError::StoredValueError);\n }\n\n runtime::print(&my_actual_stored_value.to_string());\n}\n\n")),(0,o.kt)("h3",{id:"example-of-dictionary_put-and-dictionary_get"},"Example of ",(0,o.kt)("inlineCode",{parentName:"h3"},"dictionary_put")," and ",(0,o.kt)("inlineCode",{parentName:"h3"},"dictionary_get")),(0,o.kt)("p",null,"Examples of dictionary usage for storage can be found in the ",(0,o.kt)("em",{parentName:"p"},"Writing Entries into a Dictionary")," section of ",(0,o.kt)("a",{parentName:"p",href:"/concepts/dictionaries#writing-entries-into-a-dictionary"},"Reading and Writing to Dictionaries"),"."),(0,o.kt)("h2",{id:"additional-functions-for-named-keys"},"Additional Functions for Named Keys"),(0,o.kt)("p",null,"The following functions might also be of interest for working with named keys:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.list_named_keys.html"},"list_named_keys")," - Returns the named keys of the current context"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.has_key.html"},"has_key")," - Returns true if the key exists in the current context\u2019s named keys"),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("a",{parentName:"li",href:"https://docs.rs/casper-contract/latest/casper_contract/contract_api/runtime/fn.remove_key.html"},"remove_key")," - Removes the requested ",(0,o.kt)("inlineCode",{parentName:"li"},"NamedKey")," from the current context")))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.be4395c0.js b/assets/js/runtime~main.4c0d1c15.js similarity index 61% rename from assets/js/runtime~main.be4395c0.js rename to assets/js/runtime~main.4c0d1c15.js index 82c9660160..f191f97c45 100644 --- a/assets/js/runtime~main.be4395c0.js +++ b/assets/js/runtime~main.4c0d1c15.js @@ -1 +1 @@ -!function(){"use strict";var e,a,f,c,b,d={},t={};function n(e){var a=t[e];if(void 0!==a)return a.exports;var f=t[e]={exports:{}};return d[e].call(f.exports,f,f.exports,n),f.exports}n.m=d,e=[],n.O=function(a,f,c,b){if(!f){var d=1/0;for(u=0;u=b)&&Object.keys(n.O).every((function(e){return n.O[e](f[r])}))?f.splice(r--,1):(t=!1,b0&&e[u-1][2]>b;u--)e[u]=e[u-1];e[u]=[f,c,b]},n.n=function(e){var a=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(a,{a:a}),a},f=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},n.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var b=Object.create(null);n.r(b);var d={};a=a||[null,f({}),f([]),f(f)];for(var t=2&c&&e;"object"==typeof t&&!~a.indexOf(t);t=f(t))Object.getOwnPropertyNames(t).forEach((function(a){d[a]=function(){return e[a]}}));return d.default=function(){return e},n.d(b,d),b},n.d=function(e,a){for(var f in a)n.o(a,f)&&!n.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},n.f={},n.e=function(e){return Promise.all(Object.keys(n.f).reduce((function(a,f){return n.f[f](e,a),a}),[]))},n.u=function(e){return"assets/js/"+({53:"935f2afb",170:"be8830cf",244:"f14292ab",263:"0c853d41",282:"ef563e2a",299:"3b05c439",319:"9c5b046c",420:"b161625a",586:"78143ba1",716:"09666a94",870:"1afb40fe",875:"c860f7f3",972:"09f38b0b",984:"ac7d7524",999:"6b354c4b",1002:"7d846783",1132:"74ff8362",1258:"2c99ca03",1263:"6fc855ed",1268:"576aa6a1",1301:"dd0f338d",1472:"a4f33ee0",1547:"18ef2b36",1598:"03b7b368",1636:"b0120e2d",1677:"11fbf07d",1710:"9ebdaa52",1714:"3e7c0396",1752:"0501e40c",1918:"474a98da",1925:"8b4531bd",1942:"b74af8d8",2031:"2747ce3a",2092:"ad025532",2273:"d044d178",2354:"6a8ad950",2388:"6eee94da",2570:"5c6c4a57",2614:"c2a85b60",2627:"0b24d6cd",2691:"a6d4c72e",2733:"b9da5eb7",2807:"463fc8b8",2870:"39b6f026",2881:"298ce658",2882:"303f2c49",2894:"c5563497",3013:"796e8b5d",3055:"a27f3afe",3065:"92692c02",3174:"7dc1264b",3212:"5c5ab968",3274:"5879a27f",3355:"9ff556dd",3457:"41afe816",3532:"b53d104f",3549:"1c7bd663",3550:"5e4971e3",3564:"891ef04a",3582:"49d6b5ce",3605:"eda26e2d",3608:"8c2276de",3617:"d45ad3b6",3803:"fbd44d32",4007:"73a8655d",4052:"ed14c6f0",4056:"21770712",4080:"e2fa8c79",4266:"a86c8182",4316:"6af03f69",4372:"1d7d8775",4416:"84229592",4452:"3fe59759",4455:"04e20c99",4501:"48b3ccc5",4511:"86a6526c",4609:"6a94474d",4652:"590178a5",4685:"9df8dea5",4696:"b2eb857f",4809:"22bbf3ab",4835:"8f925d60",4875:"fec0de85",4896:"11199349",4970:"72301f79",5021:"49c9a6f7",5036:"e2ffc27a",5153:"de7cb1a1",5199:"fa593e9e",5240:"9ae83eb2",5390:"74bbf90e",5428:"0b57706a",5477:"9800de81",5607:"87ec732b",5611:"bb9efa25",5614:"08ab7f39",5677:"e7ae6dc5",5715:"5c51aefb",5779:"ae44828e",5811:"82798d79",5814:"46ca92b5",5826:"a2831d13",5863:"77f905e9",5870:"1c22d3ad",5962:"efa2c7c1",6061:"1ef5bb94",6099:"bcd2a870",6109:"27a494b1",6146:"50ce38df",6171:"9b4bb048",6263:"2a99fafe",6315:"625db580",6321:"007245cc",6385:"59b068d1",6439:"7c09a624",6494:"bc69d55a",6500:"bbb7efd1",6563:"a45056cf",6571:"fcd43aac",6621:"105579ae",6646:"c305f31a",6661:"401abd7a",6688:"000be755",6717:"23dd64d8",6776:"b643e154",6834:"cb836585",6871:"e6ce8647",6958:"725b7e74",6986:"6faae04c",6988:"a71eff7a",7022:"f8f33652",7059:"71e073ea",7063:"653a68bf",7080:"71c4e358",7156:"08478d9e",7214:"2f093b46",7218:"3f68fb95",7280:"0082beea",7364:"746691fd",7378:"14c517c6",7413:"6f629aff",7415:"ad774662",7562:"80eab72b",7576:"81637ed9",7594:"f70cc67e",7598:"a5ab1e83",7645:"a7434565",7698:"e00654fa",7711:"ca0cd80e",7806:"dc0ad5f4",7832:"1b581919",7918:"17896441",7920:"1a4e3797",7925:"19dcc625",8032:"4636fedf",8306:"d2361378",8422:"956d710b",8444:"db0e1f9a",8541:"a628b5be",8575:"a75f1f06",8610:"9ea0190f",8612:"2289c829",8638:"35a30807",8669:"99756d1f",8699:"043e2a1e",8717:"1ea27aee",8788:"51cfcb69",8829:"0f636bcb",8933:"2bee511f",8996:"9755a710",9012:"c7849882",9041:"b244b0e9",9065:"963db545",9156:"ea7bfaa8",9189:"5bab3e27",9203:"f5187c73",9212:"7157e7af",9334:"247783bb",9352:"b5850dcd",9415:"04253889",9421:"3668a89e",9427:"38517b34",9470:"cc2b34bc",9503:"1011242d",9508:"2d6bc0fd",9514:"1be78505",9575:"1ddf2da6",9630:"3e3fb99e",9662:"516aae92",9669:"f8b123d7",9751:"bb301b4e",9753:"bd4f9aad",9889:"7adc1d42",9921:"0b7d75ea",9964:"f12850af",9989:"a6f4e53a"}[e]||e)+"."+{53:"f5ea56af",170:"a2f80fe3",244:"13ce6f4b",263:"ac8422df",282:"d7592e9f",299:"e61c2b37",319:"47890976",420:"6fb73e78",586:"4c3cf503",716:"cad4ab5c",870:"fa9ecae2",875:"e0b57804",972:"1b642723",984:"fae12a2c",999:"f5e8b6c6",1002:"42c2fcea",1132:"809c279a",1258:"fac42c78",1263:"0d43a718",1268:"cb1b71f3",1301:"b2499a9b",1472:"d0c75230",1547:"2efa4826",1598:"e47e9670",1636:"d0f04cdc",1677:"7996dc0e",1710:"36cf61be",1714:"c615062c",1752:"8c53aa8d",1918:"3c5b93aa",1925:"705829c2",1942:"7bb584bc",2031:"aec386e3",2092:"be21ba9f",2273:"48e3f2a4",2354:"c929fd73",2388:"a6e1f425",2570:"8779d977",2614:"71642d54",2627:"c015e882",2691:"8da8528a",2733:"abad192b",2807:"f7eb6dea",2870:"c0b2dde4",2881:"4fb05371",2882:"05dcabb8",2894:"290bd4c4",3013:"3841f31f",3055:"ab134fd8",3065:"3a26c825",3174:"0823d86e",3212:"d4b1a01c",3274:"f5f63d72",3355:"aa8b8800",3457:"5118bf09",3532:"b653a47f",3549:"c551adb9",3550:"a84bc526",3564:"3663c192",3582:"f0ad73af",3605:"abd31ebf",3608:"9d5e5770",3617:"00942bb0",3719:"e703d1bf",3803:"f6b23afa",4007:"bf27603b",4052:"8fee890c",4056:"0cb59f88",4080:"5ab5ac7c",4266:"798ff254",4316:"4fa3e838",4372:"9099df44",4416:"7f659a23",4452:"e776ea84",4455:"1fca0c7b",4501:"01b83366",4511:"a1b6b5d6",4609:"2d199c18",4652:"1efa8f67",4685:"0d854a46",4696:"ed3247eb",4809:"9823a93f",4835:"a0b95ce7",4875:"d09ce572",4896:"ad99a74a",4970:"00a85676",4972:"34b62558",5021:"6f4000e2",5036:"0a9a921a",5153:"66494672",5199:"24fabd1c",5240:"4df50365",5390:"6e0cee92",5428:"c6dbfeef",5477:"415f2370",5607:"108a03b1",5611:"0ce98b96",5614:"82a7d3bb",5677:"b81c2649",5715:"8eec2d6b",5779:"f3054247",5811:"da8c57f9",5814:"8ec9abc4",5826:"7c52010a",5863:"1847015d",5870:"8cf6a072",5962:"a1e3c8eb",6061:"ff73c783",6099:"91f12037",6109:"33c693e7",6146:"af0a1cb4",6171:"4e65eeef",6263:"528c3d19",6315:"a2a8263e",6321:"c09728ad",6385:"258ccfae",6439:"9fc3f656",6494:"d418ff48",6500:"113b15d7",6563:"1c475a77",6571:"c0cb9b58",6621:"947c9778",6646:"66b93372",6661:"f39345fb",6672:"c30506e3",6688:"41e2af7c",6717:"c2310e27",6776:"6e1cc05f",6834:"538140a7",6871:"0c6000c5",6945:"0d7e2154",6958:"58efa18c",6986:"f9e4da13",6988:"c6cfce43",7022:"97f1dcda",7059:"c166d7d3",7063:"213acf0d",7080:"4e82d2d4",7156:"97b2823f",7214:"0235d9de",7218:"641fdb93",7280:"637680be",7364:"bd40f232",7378:"1da3d9fd",7413:"127b178f",7415:"b207f44c",7562:"0a8d9c72",7576:"698309df",7594:"27d9ccca",7598:"ab421cb5",7645:"d18deaf2",7698:"8a326d03",7711:"b8bf9164",7806:"76607654",7832:"482f87ce",7918:"99ada3c1",7920:"31e815ec",7925:"35a709c4",8032:"f9d193a0",8306:"8bc0121b",8422:"8469ddd6",8444:"56848ffd",8541:"14695ec9",8575:"07acbe4a",8610:"eb6410e9",8612:"3c70e4cd",8638:"18a52ef5",8669:"c3953897",8699:"21c0d9db",8717:"ba6f0332",8788:"0ba1530f",8829:"9bd1c5e0",8894:"c2db5230",8933:"5f6d74f7",8996:"a7300428",9012:"dab5ef44",9041:"efe68502",9065:"25eb7fe6",9156:"ca694eb3",9189:"97f36cb8",9203:"4407ea82",9212:"47128814",9334:"a382abff",9352:"f0924895",9415:"be4ad2e6",9421:"bd3a0e18",9427:"9f8aa3d4",9470:"1d3f4cf7",9503:"d5ca8fbc",9508:"f04f4469",9514:"71ea3410",9575:"08a6a6d6",9630:"48b0b1fc",9662:"0aeaced8",9669:"1e1ecee7",9751:"eaced0f6",9753:"7bdf90a9",9889:"a69324a3",9921:"0bcdbdf3",9964:"88a1f821",9989:"273888e4"}[e]+".js"},n.miniCssF=function(e){},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=function(e,a){return Object.prototype.hasOwnProperty.call(e,a)},c={},b="docusaurus:",n.l=function(e,a,f,d){if(c[e])c[e].push(a);else{var t,r;if(void 0!==f)for(var o=document.getElementsByTagName("script"),u=0;u=c)&&Object.keys(n.O).every((function(e){return n.O[e](f[r])}))?f.splice(r--,1):(t=!1,c0&&e[u-1][2]>c;u--)e[u]=e[u-1];e[u]=[f,b,c]},n.n=function(e){var a=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(a,{a:a}),a},f=Object.getPrototypeOf?function(e){return Object.getPrototypeOf(e)}:function(e){return e.__proto__},n.t=function(e,b){if(1&b&&(e=this(e)),8&b)return e;if("object"==typeof e&&e){if(4&b&&e.__esModule)return e;if(16&b&&"function"==typeof e.then)return e}var c=Object.create(null);n.r(c);var d={};a=a||[null,f({}),f([]),f(f)];for(var t=2&b&&e;"object"==typeof t&&!~a.indexOf(t);t=f(t))Object.getOwnPropertyNames(t).forEach((function(a){d[a]=function(){return e[a]}}));return d.default=function(){return e},n.d(c,d),c},n.d=function(e,a){for(var f in a)n.o(a,f)&&!n.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},n.f={},n.e=function(e){return Promise.all(Object.keys(n.f).reduce((function(a,f){return n.f[f](e,a),a}),[]))},n.u=function(e){return"assets/js/"+({53:"935f2afb",170:"be8830cf",244:"f14292ab",263:"0c853d41",282:"ef563e2a",299:"3b05c439",319:"9c5b046c",420:"b161625a",586:"78143ba1",716:"09666a94",870:"1afb40fe",875:"c860f7f3",972:"09f38b0b",984:"ac7d7524",999:"6b354c4b",1002:"7d846783",1132:"74ff8362",1258:"2c99ca03",1263:"6fc855ed",1268:"576aa6a1",1301:"dd0f338d",1472:"a4f33ee0",1547:"18ef2b36",1598:"03b7b368",1636:"b0120e2d",1677:"11fbf07d",1710:"9ebdaa52",1714:"3e7c0396",1752:"0501e40c",1918:"474a98da",1925:"8b4531bd",1942:"b74af8d8",2031:"2747ce3a",2092:"ad025532",2273:"d044d178",2354:"6a8ad950",2388:"6eee94da",2570:"5c6c4a57",2614:"c2a85b60",2627:"0b24d6cd",2691:"a6d4c72e",2733:"b9da5eb7",2807:"463fc8b8",2870:"39b6f026",2881:"298ce658",2882:"303f2c49",2894:"c5563497",3013:"796e8b5d",3055:"a27f3afe",3065:"92692c02",3174:"7dc1264b",3212:"5c5ab968",3274:"5879a27f",3355:"9ff556dd",3457:"41afe816",3532:"b53d104f",3549:"1c7bd663",3550:"5e4971e3",3564:"891ef04a",3582:"49d6b5ce",3605:"eda26e2d",3608:"8c2276de",3617:"d45ad3b6",3803:"fbd44d32",4007:"73a8655d",4052:"ed14c6f0",4056:"21770712",4080:"e2fa8c79",4266:"a86c8182",4316:"6af03f69",4372:"1d7d8775",4416:"84229592",4452:"3fe59759",4455:"04e20c99",4501:"48b3ccc5",4511:"86a6526c",4609:"6a94474d",4652:"590178a5",4685:"9df8dea5",4696:"b2eb857f",4809:"22bbf3ab",4835:"8f925d60",4875:"fec0de85",4896:"11199349",4970:"72301f79",5021:"49c9a6f7",5036:"e2ffc27a",5153:"de7cb1a1",5199:"fa593e9e",5240:"9ae83eb2",5390:"74bbf90e",5428:"0b57706a",5477:"9800de81",5607:"87ec732b",5611:"bb9efa25",5614:"08ab7f39",5677:"e7ae6dc5",5715:"5c51aefb",5779:"ae44828e",5811:"82798d79",5814:"46ca92b5",5826:"a2831d13",5863:"77f905e9",5870:"1c22d3ad",5962:"efa2c7c1",6061:"1ef5bb94",6099:"bcd2a870",6109:"27a494b1",6146:"50ce38df",6171:"9b4bb048",6263:"2a99fafe",6315:"625db580",6321:"007245cc",6385:"59b068d1",6439:"7c09a624",6494:"bc69d55a",6500:"bbb7efd1",6563:"a45056cf",6571:"fcd43aac",6621:"105579ae",6646:"c305f31a",6661:"401abd7a",6688:"000be755",6717:"23dd64d8",6776:"b643e154",6834:"cb836585",6871:"e6ce8647",6958:"725b7e74",6986:"6faae04c",6988:"a71eff7a",7022:"f8f33652",7059:"71e073ea",7063:"653a68bf",7080:"71c4e358",7156:"08478d9e",7214:"2f093b46",7218:"3f68fb95",7280:"0082beea",7364:"746691fd",7378:"14c517c6",7413:"6f629aff",7415:"ad774662",7562:"80eab72b",7576:"81637ed9",7594:"f70cc67e",7598:"a5ab1e83",7645:"a7434565",7698:"e00654fa",7711:"ca0cd80e",7806:"dc0ad5f4",7832:"1b581919",7918:"17896441",7920:"1a4e3797",7925:"19dcc625",8032:"4636fedf",8306:"d2361378",8422:"956d710b",8444:"db0e1f9a",8541:"a628b5be",8575:"a75f1f06",8610:"9ea0190f",8612:"2289c829",8638:"35a30807",8669:"99756d1f",8699:"043e2a1e",8717:"1ea27aee",8788:"51cfcb69",8829:"0f636bcb",8933:"2bee511f",8996:"9755a710",9012:"c7849882",9041:"b244b0e9",9065:"963db545",9156:"ea7bfaa8",9189:"5bab3e27",9203:"f5187c73",9212:"7157e7af",9334:"247783bb",9352:"b5850dcd",9415:"04253889",9421:"3668a89e",9427:"38517b34",9470:"cc2b34bc",9503:"1011242d",9508:"2d6bc0fd",9514:"1be78505",9575:"1ddf2da6",9630:"3e3fb99e",9662:"516aae92",9669:"f8b123d7",9751:"bb301b4e",9753:"bd4f9aad",9889:"7adc1d42",9921:"0b7d75ea",9964:"f12850af",9989:"a6f4e53a"}[e]||e)+"."+{53:"f5ea56af",170:"d854ceaf",244:"381607da",263:"4481642e",282:"16d112f1",299:"ca8c75d2",319:"401fc3c4",420:"b3b21cd9",586:"0d0f02a1",716:"648e341f",870:"b74d0572",875:"7f2139bc",972:"d87933eb",984:"0f843ebe",999:"b2e7f776",1002:"e1e79c9c",1132:"b4646ff4",1258:"bab7db00",1263:"1d44d10a",1268:"c66f0c4f",1301:"1add7a81",1472:"7707e13a",1547:"1f2fff83",1598:"2f8210cf",1636:"d0f70710",1677:"1244be9d",1710:"133f9c6c",1714:"79843fa2",1752:"9a467141",1918:"d53e36e3",1925:"6251ff31",1942:"eed0a88b",2031:"f2ba58ef",2092:"bdaa0f24",2273:"cdb51ab3",2354:"54fc340f",2388:"2730ca09",2570:"56ceb458",2614:"39ed60e3",2627:"d99584cd",2691:"d9f9eacc",2733:"245a3758",2807:"1fe31a4c",2870:"988988d0",2881:"9028325a",2882:"38a128da",2894:"4e4e7f6c",3013:"b35a5fde",3055:"1685f38a",3065:"16df54f2",3174:"07eb0592",3212:"e5b57295",3274:"6e4bc834",3355:"61db54d6",3457:"519480b3",3532:"c11cd0e0",3549:"d78af67e",3550:"afb2f7d6",3564:"93307222",3582:"61d44850",3605:"5e2b7029",3608:"bff6feb3",3617:"8b90874a",3719:"e703d1bf",3803:"f6b23afa",4007:"e03e7db6",4052:"b35d8d71",4056:"91865cf0",4080:"c9a19ee9",4266:"afaa631f",4316:"a30d487c",4372:"133e6378",4416:"f0ce099a",4452:"b28dc0c6",4455:"8d925a8d",4501:"a3a74fc2",4511:"da72e427",4609:"1c861f2c",4652:"1405868f",4685:"26dae446",4696:"28d03f2e",4809:"43841de7",4835:"a4d99eef",4875:"df3d6a30",4896:"f70bed30",4970:"47a57eba",4972:"34b62558",5021:"ff2f0b69",5036:"9220c9f9",5153:"9816e830",5199:"0d6b2eb1",5240:"19122969",5390:"b7a90c5c",5428:"1b8230b0",5477:"0851b4be",5607:"439ed684",5611:"78664f78",5614:"cda8d9b9",5677:"365d2fbc",5715:"e516abdd",5779:"7d30e0d8",5811:"77634979",5814:"4dcf13f1",5826:"c42a8c60",5863:"da79b5a8",5870:"a70828b6",5962:"1485b3ad",6061:"7c281eb7",6099:"07e2751a",6109:"43fa8b10",6146:"3d598a4b",6171:"a6783ade",6263:"d2eb3836",6315:"3767bcfa",6321:"88ca756d",6385:"258ccfae",6439:"6d653f8c",6494:"7b421405",6500:"3ad5f031",6563:"6482f7f0",6571:"93142dc7",6621:"e985d36f",6646:"43db811a",6661:"f21f56e0",6672:"c30506e3",6688:"0ead002c",6717:"3771aca1",6776:"6b17dc67",6834:"69f934b6",6871:"d7eb5eda",6945:"0d7e2154",6958:"ef17b217",6986:"3f306220",6988:"5141f7ca",7022:"61267410",7059:"e55ea1bc",7063:"108fafc5",7080:"6a76edb9",7156:"22b0cd6e",7214:"feda5c6e",7218:"f818d031",7280:"4b90d5ee",7364:"bd40f232",7378:"ade39fcb",7413:"127b178f",7415:"367848aa",7562:"d3aee779",7576:"637b21ae",7594:"b9f0f563",7598:"9ce6cacd",7645:"d18deaf2",7698:"08fe7795",7711:"71611a49",7806:"05dc6932",7832:"189083f6",7918:"99ada3c1",7920:"31e815ec",7925:"ad773672",8032:"b2a570c8",8306:"c78f5bed",8422:"ed13cd24",8444:"c940cb9f",8541:"f98fca22",8575:"86a51af4",8610:"6bb53897",8612:"557d1d42",8638:"332ce4d9",8669:"d2ce0dcd",8699:"3c76adb8",8717:"97ba152e",8788:"eb2ceac7",8829:"181aaf5d",8894:"c2db5230",8933:"7e5892e8",8996:"b1d3d828",9012:"3991c7ed",9041:"86cd11f8",9065:"f7c0fcf5",9156:"eafd168a",9189:"68b11943",9203:"cd338982",9212:"8c7a2f2d",9334:"a382abff",9352:"e1209bc5",9415:"efcb9c95",9421:"a88e61a9",9427:"07f96590",9470:"7e0061f9",9503:"b6dad235",9508:"a57abebc",9514:"71ea3410",9575:"e21bb536",9630:"913b371c",9662:"4742a34c",9669:"e93bf379",9751:"d4819f92",9753:"0d6ea978",9889:"2f67eb3e",9921:"7ebe5b4d",9964:"e9eb2c4f",9989:"8ba03a22"}[e]+".js"},n.miniCssF=function(e){},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=function(e,a){return Object.prototype.hasOwnProperty.call(e,a)},b={},c="docusaurus:",n.l=function(e,a,f,d){if(b[e])b[e].push(a);else{var t,r;if(void 0!==f)for(var o=document.getElementsByTagName("script"),u=0;u - + @@ -74,7 +74,7 @@

Accounts and Cryptographic Keys

The Casper blockchain uses an on-chain account-based model, uniquely identified by an AccountHash derived from a specific PublicKey. The AccountHash is a 32-byte hash derived from any of the supported PublicKey variants below to standardize keys that can vary in length.

By default, a transactional interaction with the blockchain takes the form of a Deploy cryptographically signed by the key-pair corresponding to the PublicKey used to create the account.

The Casper platform supports two types of keys for creating accounts and signing transactions:

  • Ed25519 keys, which use the Edwards-curve Digital Signature Algorithm (EdDSA) and are 66 bytes long
  • Secp256k1 keys, which use the Elliptic Curve Digital Signature Algorithm (ECDSA) with the P-256 curve; they are 68 bytes long and are also found on the Ethereum blockchain

You can generate keys using both formats, and it is also possible to work with existing Ethereum keys.

You can also generate an account hash from a public key with the Casper command-line client.

Creating Accounts and Keys

When you create an account on the Casper blockchain, a cryptographic key-pair will be created when using either the Casper command-line client or a block explorer.

note

SAVE your keys to a safe place, preferably offline.

Option 1: Generating keys using the Casper Client

This option describes how you can use the Casper command-line client to set up an account using either key type.

EdDSA Keys

The command-line client generates EdDSA keys by default. Use the command below to create the account.

mkdir ed25519-keys
casper-client keygen ed25519-keys/
tree ed25519-keys/

Sample output of the tree command shows the contents of the ed25519-keys folder:

ed25519-keys/
├── public_key.pem
├── public_key_hex
└── secret_key.pem

0 directories, 3 files

Here are some details about the files generated:

  1. public_key.pem is a PEM-encoded public key
  2. public_key_hex is a hexadecimal-encoded string of the public key
  3. secret_key.pem is the PEM-encoded secret key

The public-key-hex for Ed25519 keys starts with 01 and is 66 bytes long:

cat ed25519-keys/public_key_hex
011724c5c8e2404ca01c872e1bbd9202a0114e5d143760f685086a5cffe261dabd

ECDSA Keys

To create Secp256k1 keys, which use the ECDSA algorithm with the P-256 curve, follow these steps:

mkdir secp256k1-keys
casper-client keygen -a secp256k1 secp256k1-keys/
tree secp256k1-keys/

Sample output of the tree command shows the contents of the secp256k1-keys folder:

secp256k1-keys/
├── public_key.pem
├── public_key_hex
└── secret_key.pem

0 directories, 3 files

The public-key-hex for Secp256k1 keys starts with 02 and is 68 bytes long:

cat secp256k1-keys/public_key_hex
020287e1a79d0d9f3196391808a8b3e5007895f43cde679e4c960e7e9b92841bb98d
note

After generating keys for the account, you may add funds to the account's purse to finish the account creation process.

Option 2: Generating keys using a block explorer

This option is available on networks that have a block explorer.

For instance, on the official Testnet, the CSPR.live block explorer is available, and the following instructions assume you are using it.

Start by creating an account using the Casper Wallet, Ledger, or Torus Wallet.

caution

The Casper Signer has been replaced with the Casper Wallet and will be deprecated. We recommend migrating all your Casper accounts to the Casper Wallet as outlined here.

Funding your Account

Once you create your account, you can fund the account's main purse to finish the process of setting it up.

note

Until you fund your account's main purse, it does not exist on the blockchain.

Working with Existing Ethereum Keys

You can also use existing Ethereum keys in Casper. Here is an example set of Ethereum keys and their corresponding address:

Address:0x7863B6F7232D99FF80B74E4C8BB3BEE3BDE0291F
Public key:0470fecd1f7ae5c1cd53a52c4ca88cd5b76c2926d7e1d831addaa2a64bea9cc3ede6a8e9981c609ee7ab7e3fa37ba914f2fc52f6eea9b746b6fe663afa96750d66
Private key:29773906aef3ee1f5868371fd7c50f9092205df26f60e660cafacbf2b95fe086

To use existing Ethereum keys, the Casper virtual machine (VM) needs to know that the key is a Secp256k1 type. To achieve this, we will prefix the public key hex with 02, as shown in the example below.

The Casper command-line client provides an example of how this works.

Example:

The following transaction sends 10 CSPR.

casper-client transfer \
--transfer-id 1234567 \
--node-address http://localhost:7777 \
--chain-name casper \
--target-account 020470fecd1f7ae5c1cd53a52c4ca88cd5b76c2926d7e1d831addaa2a64bea9cc3ede6a8e9981c609ee7ab7e3fa37ba914f2fc52f6eea9b746b6fe663afa96750d66 \
--amount 10000000000 \
--secret-key <path-to-secret_key.pem> \
--payment-amount 100000000
tip

The payment amount varies based on each deploy and network chainspec.

The Casper command-line client requires the secret key in PEM format to send a Deploy from this account. If you want to use existing Ethereum keys with the command-line client, a conversion to PEM format is needed.

The following example is a JS script that generates a PEM file, using a key encoder and Node.js. To install these components, do the following:

sudo apt install nodejs
npm install key-encoder

Then create the JS script convert-to-pem.js using vi or nano, and include this content:

var KeyEncoder = require("key-encoder"),
keyEncoder = new KeyEncoder.default("secp256k1");
let priv_hex = "THE SECRET KEY TO ENCODE";
let priv_pem = keyEncoder.encodePrivate(priv_hex, "raw", "pem");
console.log(priv_pem);

Then run the script using Node.js and name the secret key.

node convert-to-pem.js > eth-secret.pem

To view the secret key, use cat <filename>:

cat eth-secret.pem

Below is the sample output showing the contents of the secret key.

-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIBjXY+7xZagzTjL4p8bGWS8FPRcW13mgytdu5c3e556MoAcGBSuBBAAK
oUQDQgAEpV4dVaPeAEaH0VXrQtLzjpGt1pui1q08311em6wDCchGNjzsnOY7stGF
tlKF2V5RFQn4rzkwipSYnrqaPf1pTA==
-----END EC PRIVATE KEY-----

Option 3: Generating keys using OpenSSL

You can generate keys without the Casper client using the openssl cryptography toolkit. The commands below are valid only for generating Ed25519 keys on a Linux operating system.

Generating the secret_key.pem file

openssl genpkey -algorithm ed25519 -out secret_key.pem

Generating public keys from the secret_key.pem file

For default Ed25519 keys, you can generate the public_key.pem and public_key_hex using these commands:

openssl pkey -in secret_key.pem -pubout -out public_key.pem

{ echo -n 01; openssl pkey -outform DER -pubout -in "secret_key.pem" | tail -c +13 | openssl base64 | openssl base64 -d | hexdump -ve '/1 "%02x" ' | tr -d "/n"; } > public_key_hex

Generating an Account Hash

To generate the account hash for a public key, use the account-address option of the Casper client. The argument for the public-key must be a properly formatted public key. The public key may also be read from a file, which should be one of the two files generated via the keygen command: public_key_hex or public_key.pem.

casper-client account-address --public-key <FORMATTED STRING or PATH>

Finding the Main Purse URef

You can use the Casper CLI client or a block explorer to find the URef identifying an account's main purse.

Using the Casper CLI client

With the casper-client, use the get-account-info subcommand.

casper-client get-account-info \
--node-address <HOST:PORT> \
--public-key <FORMATTED STRING or PATH>
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. public-key - This must be a properly formatted public key. The public key may instead be read in from a file, in which case, enter the path to the file as the argument. The file should be one of the two public key files generated via the keygen subcommand; "public_key_hex" or "public_key.pem"
Sample command and output
casper-client get-account-info --node-address http://65.21.75.254:7777  --public-key 0202ceafc0aa35f5a7bdda22f65c046b9b30b858459e18d3670f035839ad887fe5db
{
"id": -2018234245556346849,
"jsonrpc": "2.0",
"result": {
"account": {
"account_hash": "account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_hash": "account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34",
"weight": 1
}
],
"main_purse": "uref-974019c976b5f26412ce486158d2431967af35d91387dae8cbcd43c20fce6452-007",
"named_keys": []
},
"api_version": "1.4.15",
"merkle_proof": "[29712 hex chars]"
}
}

Run the following help command for more details:

casper-client get-account-info --help

Using a block explorer

Using the block explorer for Mainnet or Testnet, open the Account in question, and expand the Raw Data section. Look for the main_purse field and find the corresponding URef. If you do not see data in the Raw Data section, then the account has not been funded yet.

Image showing an account's main purse

Understanding Call Stacks

Users wishing to interact with a Casper network must do so through sending a Deploy. All Deploys consist of session code run in the context of the user account that sent the Deploy. The session code may install contract code to global state, or interact with previously installed contract code.

When the session code within a Deploy interacts with one or more contracts, this is the beginning of a Call Stack. A call stack is the chronological order in which contracts call other contracts, initiated by an instance of session code.

The Caller

In every instance of a call stack, the originating caller is the session code within the account's context that began the interaction. Contract code cannot spontaneously act without session code to activate it. As such, the session code represents the zeroth entity in each call stack. The account that initiated the deploy can be retrieved with the contract_api::runtime::get_caller function.

The Call Stack

Developers can access the call stack with the contract_api::runtime::get_call_stack function.

If session code calls a contract, which in turn calls another contract, then the session code would represent the zeroth entity in the stack, the contract called by the initiating session code would be the first and the contract called by the first contract would be the second.

In this example, the first contract would be the immediate caller of the second contract, meaning it interacted directly with it. The session code would remain the caller.

Call Stack

Limitations

Casper networks place a limitation on the maximum height of a call stack. This value can be set within the chainspec for the network in question. For the Casper Mainnet, this limit is set at 10 contracts. This does not include the initiating session code, which would still count as the zeroth instance within the stack.

As such, a call stack may consist of up to ten consecutive called smart contracts, assuming that the Casper network you are working with is set to the default call stack depth. Smart contract developers should consider it best practice to limit the depth of their call stack as much as practicable. If your contract calls a contract not under your direct control, it may call into any other contracts. You can avoid hitting the limitation by being efficient in your contracts and avoiding superfluous contract separation.

note

Contract code cannot call session code, only other contract code.

Casper Network Design

Introduction

Casper is a Proof-of-Stake blockchain platform with an account-based model that performs execution after consensus. A Casper network stores data in a structure known as Global State. Users interact with global state through session code sent in a Deploy. Deploys contain Wasm to be executed by the network, thus allowing developers to use their preferred programming language rather than a proprietary language.

A deploy executes in the context of the user's Account but can call stored Wasm that will execute in its own context. User-related information other than an account is stored in global state as an Unforgeable Reference or URef. After a node accepts a deploy as valid, it places the deploy in a proposed Block and gossips it among nodes until the network reaches consensus. At this point, the network executes the Wasm included within the deploy.

  1. Execution Semantics

  2. Accounts

  3. Unforgeable Reference (URef)

  4. Block Structure

  5. Tokens

Execution Semantics

A Casper network is a decentralized computation platform. This section describes aspects of the Casper computational model.

Measuring Computational Work

Computation is done in a WebAssembly (Wasm) interpreter, allowing any programming language which compiles to Wasm to become a smart contract language for the Casper blockchain. Similar to Ethereum, Casper uses Gas to measure computational work in a way that is consistent from node to node in a Casper network. Each Wasm opcode is assigned a Gas cost, and the amount of gas spent is tracked by the runtime with each opcode executed by the interpreter.

Costs for opcode instructions on the Casper Mainnet network can be found here.

All executions are finite because each has a finite gas limit that specifies the maximum amount of gas available to spend before the runtime terminates the computation. The payment executable session determines how to pay for the deploy. The gas limit is set by executing the payment code specified within the deploy.

Although the network measures costs in Gas, payment for computation occurs in motes. Therefore, there is a conversion rate between Gas and motes.

note

Please note that Casper will not refund any amount of unused gas.

This decision is taken to incentivize the Casper Runtime Economics by efficiently allocating the computational resources. The consensus-before-execution model implements the mechanism to encourage the optimized gas consumption from users and to prevent the overuse of block space by poorly handled deploys.

The Casper Network Runtime

A Wasm module is not natively able to create any effects outside of reading or writing from its own linear memory. Wasm modules must import functions from the host environment they are running in to enable other desired effects, such as reading or writing to global state.

Casper Network Runtime

All these features are accessible via functions in the Casper External FFI.

Generating URefs

URefs are generated using a cryptographically secure random number generator using the ChaCha algorithm. The random number generator is seeded by taking the blake2b256 hash of the deploy hash concatenated with an index representing the current phase of execution (to prevent collisions between URefs generated in different phases of the same deploy).

Generating URefs

Accounts

The Casper blockchain uses an on-chain account-based model, uniquely identified by an AccountHash derived from a specific PublicKey. The global state trie store requires all keys to be the same length, so the AccountHash is a 32-byte derivative used to abstract any of the supported public key variants.

The Casper platform supports two types of keys for creating accounts and signing transactions:

  • Ed25519 keys, which use the Edwards-curve Digital Signature Algorithm (EdDSA) and are 66 bytes long
  • Secp256k1 keys, commonly known as Ethereum keys, which are 68 bytes long

By default, a transactional interaction with the blockchain takes the form of a Deploy cryptographically signed by the key-pair corresponding to the PublicKey used to create the account. All user activity on the Casper blockchain (i.e., "deploys") must originate from an account. Each account has its own context where it can locally store information (e.g., references to useful contracts, metrics, and aggregated data from other parts of the blockchain). Each account also has a "main purse" where it can hold Casper tokens (see Tokens for more information).

This chapter describes the permission model for accounts and their local storage capabilities and briefly mentions some runtime functions for interacting with accounts.

Creating an account

Account creation automatically happens upon transferring tokens to a yet unused PublicKey. On account creation, the balance of its main purse is equal to the number of tokens transferred during the creation process. Its action thresholds are equal to 1, and there is one associated key. The associated key is the PublicKey used to create the account. In this way, an account is essentially a context object encapsulating the main purse, used to pay for transactions. However, an account may have an additional purse beyond the main purse.

Image showing the account data structure

An Account contains the following data:

Permissions Model

Actions and Thresholds

An account can perform two types of actions: sending deploys and managing keys. A deploy is simply executing some code on the blockchain, while key management involves changing the associated keys (which will be described in more detail later). Key management cannot be performed independently, as all effects on the blockchain must come via a deploy; therefore, a key management action implies that a deploy action is also taking place.

The ActionThresholds contained in the Account data structure set a Weight, which must be met to perform that action. The next section describes these weight thresholds. Since a key management action requires a deploy action, the key management threshold should always be greater than or equal to the deploy threshold.

Associated Keys and Weights

Accounts on a Casper network can associate other key pairs through a multiple signature scheme for sending transactions. An account's associated keys are the set of public keys allowed to provide signatures on deploys for that account. Each associated key has a weight; these weights combine to meet the action thresholds provided in the previous section. Each deploy must be signed by one or more keys associated with the account that deploy is for, and the sum of the weights of those keys must be greater than or equal to the deployment threshold weight for that account. We call the keys that have signed a deploy the "authorizing keys". Similarly, if a deploy contains key management actions (detailed below), the sum of the weights of the authorizing keys must be greater than or equal to the key management action threshold of the account.

note

Any key may help authorize any action; there are no "special keys". All keys contribute their weight in exactly the same way.

Key Management Actions

A key management action is a change to the account permissions, including:

  • Adding or removing an associated key
  • Changing the weight of an associated key
  • Changing the threshold of any action

Key management actions have validity rules preventing users from locking themselves out of their accounts. For example, one can set a threshold, at most, the sum of the weights of all associated keys.

Account security and recovery using key management

This permissions model's purpose is to keep accounts safe from lost or stolen keys while allowing the usage of modern mobile devices. For example, it may be convenient to sign deploys from a smartphone without worrying about the repercussions of losing the phone. The recommended setup is to have a low-weight key on the phone, enough for the deploy threshold but not enough for key management. If the phone is lost or stolen, a key management action using other associated keys from another device (e.g., a home computer) can be used to remove the lost associated key and add a key that resides on a replacement phone.

note

It is extremely important to ensure there will always be access to a sufficient number of keys to perform the key management action. Otherwise, future recovery will be impossible (Casper currently does not support "inactive recovery").

The Account Context

A deploy is a user request to perform some execution on the blockchain (see Execution Semantics for more information). It contains "payment code" and "session code", which are references to stored on-chain contracts or Wasm to be executed. For executable Wasm, its execution and the logic therein occur within the context of the account signing the deploy. This means that the executing Wasm has access to the named keys and main purse of the account's context.

note

In the case where there is a reference to stored on-chain Wasm (smart contracts), the execution of the on-chain Wasm will occur in its own separate runtime context. As a result, the stored Wasm will not have access to the named keys or main purse of the calling account.

Unforgeable Reference (URef)

This key type is used for storing any value except Account. Additionally, URefs used in Wasm carry permission information to prevent unauthorized usage of the value stored under the key. The runtime tracks this permission information. This means that if malicious Wasm attempts to produce a URef with permissions that the Wasm does not have, the Wasm has attempted to "forge" the unforgeable reference, and the runtime will raise a forged URef error. Permissions for a URef can be given across contract calls, allowing data stored under a URef to be shared in a controlled way. The 32-byte identifier representing the key is generated randomly by the runtime (see Execution Semantics for more information). The serialization for Access Rights that define the permissions for URefs is detailed in the CLValues section.

Permissions for URefs

In the runtime, a URef carries its permissions called AccessRights. Additionally, the runtime tracks what AccessRights would be valid for each URef in each context. The system assumes that a sent URef is invalid, regardless of declared AccessRights, and will check it against the executing context to determine validity on each usage. Only the host logic can add a URef, in the following ways:

  • It can exist in a set of "known" URefs
  • It can be freshly created by the runtime via the new_uref function
  • For called contracts, the caller can pass it in via the arguments to call_contract
  • It can be returned to the caller from call_contract via the ret function

Note that only valid URefs may be added to the known URefs or cross-call boundaries; this means the system cannot be tricked into accepting a forged URef by getting it through a contract or stashing it in the known URefs.

The ability to pass URefs between contexts via call_contract / ret, allows them to share state among a fixed number of parties while keeping it private from all others.

URefs and Purses

Purses represent a unique type of URef used for accounting measures within a Casper network. URefs exist as a top-level entity, meaning that individual accounts do not own ‘URef’s. As described above, accounts and contracts possess certain Access Rights, allowing them to interact with the given URef. While an account will possess an associated URef representing their main purse, this URef exists as a Unit and corresponds to a balance key within the Casper mint. The individual balance key within the Casper mint is the account's purse, with transfers authorized solely through the associated URef and the Access Rights granted to it.

Through this logic, the Casper mint holds all motes on the network and transfers between balance keys at the behest of accounts and contracts as required.

Block Structure

A block is the primary data structure by which network nodes communicate information about the state of a Casper network. We briefly describe here the format of this data structure.

Data Fields

A block consists of the following:

  • A block_hash
  • A header
  • A body

Each of these fields is detailed in the subsequent sections.

block_hash

The block_hash is the blake2b256 hash of the block header.

The block header contains the following fields:

  • parent_hash

    A list of block_hashes giving the parents of the block.

  • state_root_hash

    The global state root hash produced by executing this block's body.

  • body_hash

    The hash of the block body.

  • random_bit

    A boolean needed for initializing a future era.

  • accumulated_seed

    A seed needed for initializing a future era.

  • era_end

    Contains equivocation and reward information to be included in the terminal finalized block. It is an optional field.

  • timestamp

    The timestamp from when the block was proposed.

  • era_id

    Era ID in which this block was created.

  • height

    The height of this block, i.e., the number of ancestors.

  • protocol_version

    The version of the Casper network when this block was proposed.

Body

The block body contains an ordered list of DeployHashes which refer to deploys, and an ordered list of DeployHashes for native transfers (which are specialized deploys that only transfer tokens between accounts). All deploys, including a specialization such as native transfer, can be broadly categorized as some unit of work that, when executed and committed, affect change to Global State. A valid block may contain no deploys and / or native transfers.

The block body also contains the public key of the validator that proposed the block.

Refer to the Serialization Standard for additional information on how blocks and deploy are serialized.

Tokens

Casper is a decentralized Proof-of-Stake blockchain platform that uses a consensus algorithm called Highway. Having a unit of value is required to make this system work because users must pay for computation, and validators must have stake to bond. In the blockchain space, this unit of value is a token.

This chapter describes tokens and how one can use them on the Casper platform.

Token Generation and Distribution

A blockchain system generally needs a supply of tokens available to pay for computation and reward validators for processing transactions on the network. The initial supply at the launch of Mainnet was 10 billion CSPR. The current supply is available here. In addition to the initial supply, the system will have a low rate of inflation, the results of which will be paid out to validators in the form of seigniorage.

The number of tokens used to calculate seigniorage is the initial supply of tokens at genesis.

Image showing the token lifecycle

Divisibility of Tokens

Typically, a token is divisible into some number of parts. We call the indivisible units which make up the CSPR token motes. Each CSPR is divisible into 109 motes. To avoid rounding errors, it is essential to always represent token balances in motes. In comparison, Ether is divisible into 1018 parts called Wei.

The concept of CSPR is human-readable convenience and does not exist within the actual infrastructure of a Casper network. Instead, all transactions deal solely with motes.

Purses and Accounts

All accounts on the Casper system have a purse associated with the Casper system mint, called the main purse. However, for security reasons, the URef of the main purse is only available to code running in the context of that account (i.e. only in payment or session code). Therefore, the mint's transfer method that accepts URefs is not the most convenient when transferring between account main purses. For this reason, Casper supplies a transfer_to_account function, which takes the public key used to derive the identity key of the account. This function uses the mint transfer function with the current account's main purse as the source and the main purse of the account at the provided key as the target.

The Casper Mint Contract

The Casper mint is a system contract that manages the balance of motes within a Casper network. These motes are used to pay for computation and bonding on the network. The mint system contract holds all motes on a Casper network but maintains an internal ledger of the balances for each Account's main purse. Each balance is associated with a URef, which is a key to instruct the mint to perform actions on that balance (e.g., transfer motes). Informally, these balances are referred to as purses and conceptually represent a container for motes. The URef is how a purse is referenced externally, outside the mint.

The AccessRights of the URefs permissions model determines what actions can be performed when using a URef associated with a purse.

As all URefs are unforgeable, the only way to interact with a purse is for a URef with appropriate AccessRights to be validly given to the current context.

The basic global state options map onto more standard monetary operations according to the table below:

Global StateAction Monetary Action
AddDeposit (i.e. transfer to)
WriteWithdraw (i.e. transfer from)
ReadBalance check

The mint Contract Interface

The mint system contract exposes the following methods:

  • transfer(source: URef, target: URef, amount: Motes) -> TransferResult
    • source must have at least Write access rights, target must have at least Add access rights
    • TransferResult may be a success acknowledgment or an error in the case of invalid source or target or insufficient balance in the source purse
  • mint(amount: Motes) -> MintResult
    • MintResult either gives the created URef (with full access rights), which now has a balance equal to the given amount; or an error due to the minting of new motes not being allowed
    • In the Casper mint, only the system account can call mint, and it has no private key to produce valid cryptographic signatures, which means only the software itself can execute contracts in the context of the system account
  • create() -> URef
    • a convenience function for mint(0) which cannot fail because it is always allowed to create an empty purse
  • balance(purse: URef) -> Option<Motes>
    • purse must have at least Read access rights
    • BalanceResult either returns the number of motes held by the purse, or nothing if the URef is not valid

The Highway Consensus Protocol

What is Consensus?

Consensus is the backbone of any distributed network. The decentralized nature of a blockchain requires a method through which disparate entities can agree on one immutable truth. This involves determining the validity of transactions, resolving conflicts, and finalizing blocks to be added to the chain by the network. A consensus protocol is a set of mechanisms and rules within the distributed network with which all actors must comply.

These rules outline the type of messages sent over the network, when they are sent and how to process them. Within the context of a blockchain, the consensus protocol decides which blocks are added to the chain by the network and the order in which they are added. This determines the state of the distributed ledger and ensures that all nodes agree on that state.

The consensus mechanism will determine how a blockchain meets the following requirements:

  • Safety - All honest nodes eventually agree on the final value. The system is setup in a way where no two honest nodes will report two different blocks at the same height of the blockchain.

  • Liveness - The system continues running and adds new blocks to the chain indefinitely.

What is Highway Consensus?

Casper networks use a consensus protocol called Highway, ensuring the Safety and Liveness requirements of these networks. Highway is a Byzantine Fault Tolerant protocol requiring a partially synchronous network.

How does the Casper Mainnet use Highway?

The Casper Mainnet is a Proof-of-Stake network in which the on-chain auction contract determines validators participating in Highway. The protocol uses a decentralized network of nodes, either bonded or unbonded. Nodes actively participating in the consensus process must stake CSPR tokens and are known as Validator Nodes. The top 100 bidders are selected through the auction contract every era to act as validators in the era after the next (Current Era + 2). Nodes with a greater stake in the network's success have a greater weight in reaching consensus. Highway does not necessitate a Proof-of-Stake method of choosing validators and could theoretically be used alongside a private network with a different model.

These validators run a Casper network that will continue to function so long as the amount of faulty or dishonest nodes does not exceed one-third of the total number of nodes in the network. Nodes that are not faulty are honest nodes. In most cases, the system can assume that more than two-thirds of all nodes will actively collaborate to achieve consensus. Therefore, stronger-than-average finality guarantees occur during periods when all nodes are acting honestly. A block's fault tolerance increases beyond one-third as the protocol continues. If all validators are honest, it approaches 100%.

Dynamic Round Length

Within the Highway protocol, the length of a round is determined dynamically to ensure a suitable amount of time for nodes to gossip all messages through several round trips with honest validators. This ensures that the system maintains liveness by ensuring that all messages are properly gossiped while maintaining a timely addition of blocks to the chain.

Eras

The concept of eras allows Highway to reduce the overall operational storage requirements of participating nodes while also rotating validators. A new instance of Highway runs every two hours or approximately 220 blocks, depending on current network metrics. This allows for two benefits:

  • Data Reduction - Older "metadata" used in finalizing certain blocks is no longer useful and can be removed without compromising the immutability of the data stored on the blockchain.

  • Banning Equivocators - Dishonest nodes caught equivocating in a previous era are banned from participating in new eras. This allows honest nodes to begin a new era in the relaxed mode, no longer needing to send endorsements due to past equivocations.

  • Rotating Validators - Bonded nodes bid on validator spots each era, with the top 100 highest bidders becoming validators for the era after next (N+2).

In any given era, node operators will bid to become validators that will participate in the consensus mechanism for the era after next (N+2). Each time slot within the era will also determine a lead validator. The lead validator proposes new blocks to be added to the chain, which are then gossiped among the network's nodes. These messages show an implicit preference for the lead validator's block due to the GHOST (Greedy Heaviest Observed Sub-Tree) rule. Once this process reaches critical mass, with a sufficient interconnected pattern of messages, it becomes impossible to switch to another block. The selected block is then considered finalized and added to the chain.

The final block of an era is a switch block and forms the initial state of the next era. A new Highway instance begins with the new era, using information contained within the switch block and a new potential set of validators. More details on the auction process to determine an era's validators can be found within the Consensus Economics page.

Finality

Finality occurs when the network can be sure that a block will not be altered, reversed, or canceled after addition to the chain. This occurs via consensus, and as all transactions happen within a block, it allows for confirmation that a transaction cannot be changed. After finality, it would require greater than 1/3 of all validators to double-sign to cause a disparity between nodes. In this event, the network would shut down and require a manual restart.

On a Casper network, a transaction finalizes alongside the finalizing of the block in which it is included. Validators that equivocate risk eviction, in which the network removes them from the validator set. Therefore, honest nodes receive rewards for their participation, while equivocating nodes risk loss of revenue for acting maliciously.

Highway's criterion for detecting finality is the presence of a pattern of messages called a Summit. It is an improvement over previous CBC Casper finality criteria, which were more difficult to attain and computationally more expensive to detect. Summits preserve the advantage of tunable fault tolerance while being detected in polynomial time.

Casper Node Networking Protocol

Casper Node Networking Protocol (Mainnet Protocol Version 1.5.0)

This is a description of the casper-node's networking protocol. This document follows the conventions laid out in RFC2119.

Connection Level

Any casper-node taking part in the Casper network SHOULD open connections to every other casper-node it is aware of and has not blocked. These connections are established using TLS, presenting a client certificate.

Reciprocity, retries and data direction

A connection that was initiated by a node is considered an outgoing connection by the node itself, but an incoming connection by all other peers.

A node that created an outgoing connection SHOULD terminate the connection if it does not detect an incoming connection from the connected-to node within a short amount of time.

A node that receives an incoming connection MUST eventually establish an outgoing connection to the node.

A node SHOULD retry any failed outgoing connection periodically with exponential backoff. A node MUST NOT attempt to reconnect more than once per second.

Nodes MUST NOT send data through incoming connections, other than handshakes. Nodes MUST NOT accept any data coming through outgoing connections, other than handshakes.

TLS parameters

Any node creating a connection to a node MUST present a client certificate with the following properties:

  • Signature algorithm: ECDSA_WITH_SHA512
  • Subject name: Same as issuer name (self-signed certificate!)
  • Serial number: 1
  • Expiration ("not before"): Must be earlier than current time.
  • Expiration ("not after"): Must be later than current time.
  • Signature: Must be using SECP521R1 with SHA512 and valid.

The SHA512 fingerprint of the public key is considered the NodeID of the node.

Any node MUST immediately terminate a connection if it does not match the given parameters. The same certificate MUST be used as a server certificate for other clients connecting to this node.

An incoming connection with a valid TLS certificate SHOULD be accepted. As all certificates are self-signed, no further checking is done.

Discovery

A node address is defined as an IPv4 address and a port. A node's address is the publicly reachable IP address and port that it is listening on for node-to-node-communication.

Every node SHOULD have one or more so-called known node addresses of other nodes configured.

On start-up, a node SHOULD attempt to connect to all known nodes. A node SHOULD never forget a known node address.

Every node MUST periodically gossip its own node address to the network (see gossiping below).

A node learns new node addresses through receiving a gossiped node address, or being told of an address through the handshake.

Upon learning of a previously unknown node address, a node SHOULD attempt to connect to it.

After failing to connect to a node address, a node MAY forget it after a certain amount of retries, this process is called forgetting a node. An address that has been forgotten will be considered new the next time it is learned.

A node MUST NOT forget the known addresses it was configured with initially.

Framing

To send a message to a peer across an established TLS connection, a node MUST send a message length header consisting of a 32 byte big endian integer with the message length first.

A node receiving a message length header that exceeds the maximum message size specified in the chainspec MUST immediately terminate the connection.

Encoding

The node uses three encoding schemes: Handshakes (see below) are encoded using MessagePack, while regular messages are encoded using bincode. Many (but not all) data objects use bytesrepr for serialization.

The node uses the rmp-serde crate, version 0.14.4, which is kept fixed to ensure handshake compatibility with protocol version 1.0 of the node.

All nodes MUST use the following settings for bincode encoding of network messages:

  • Byte limit: Unlimited
  • Endianness: Little Endian
  • Integer Encoding: Varint
  • Trailing Bytes: Not allowed

Any other use of bincode encoding (e.g. for GetRequest payloads, see below) MUST use the following bincode encoding settings:

  • Byte limit: Unlimited
  • Endianness: Little Endian
  • Integer Encoding: Fixint
  • Trailing Bytes: Allowed

Unless noted otherwise, any structure encoded as MessagePack or bincode is serialized using the standard serde-derived encoding. For bytesrepr serialization refer to the specific implementations in the bytesrepr crate.

Any data types given from here on out are described using simplified Rust structure definitions.

The Message Type

The following data types make up the networking protocol:

enum Message {
Handshake {
network_name: String,
public_addr: SocketAddr,
// default: 1.0
protocol_version: ProtocolVersion,
// default: `None`
consensus_certificate: Option<ConsensusCertificate>,
// default: false
is_syncing: bool,
// default: `None`
chainspec_hash: Option<Digest>,
},
Payload(Payload),
}

struct ConsensusCertificate {
public_key: PublicKey,
signature: Signature,
}

struct Digest([u8; 32]);

For String, SocketAddr, ProtocolVersion, Option, PublicKey, Signature see the respective docs and details below.

Handshake Behavior

A node establishing a new connection MUST immediately send a handshake through said connection to the peer, regardless of whether an incoming or outgoing connection was established (this is an exception to the restriction of only sending data through outgoing connections).

A handshake MUST be encoded using the Message::Handshake structure. A node running version 1.5 SHOULD NOT omit any of the fields for which default values are available (protocol_version, consensus_certificate, is_syncing, chainspec_hash). A node MUST accept any handshake that omits one or more of these fields and fill them with defaults.

After receiving a handshake, a node MUST compare the network_name, protocol_version and chainspec_hash fields against its own configuration: If any of these do not match, it MUST disconnect from the node and SHOULD block it.

A node MUST mark any peer that connects to it (thus is an incoming connection from the perspective of the node) with a value of is_syncing set to true as "syncing" and MUST NOT allow any of its own messages that are marked unsafe-for-syncing to be sent to that node, by silently dropping them instead.

A node MAY compare peers that provide a consensus_certificate to the currently active set of validators and mark it as an active validator to give it preferential treatment when outgoing bandwidth is limited.

Upon handshake completion, the node SHOULD learn the provided public_addr.

Blocking Nodes

If a node blocks a peer, it MUST sever all incoming and outgoing connections to said node. It MUST take note of the NodeId of the node, marking it as blocked and MUST not allow any new connection to proceed past the handshake.

A node MUST NOT block peers based on IP address or port. Nodes MUST NOT block peers for more than an hour.

After a block on a node is expired, the node SHOULD forget the nodes IP address, allowing a later learning of said address again.

The Payload Type

The Payload (found in the node sources as Message in payload.rs) contains variants for all node-to-node communicating subsystems of a running node, which are described below. Note that some of the variants have been renamed for clarity in this specification. Since field names are not used in bincode encoding, this should have no effect on implementations.

enum Payload {
Consensus(ConsensusMessage),
DeployGossiper(DeployGossiperMessage),
AddressGossiper(AddressGossiperMessage),
GetRequest {
tag: Tag,
serialized_id: Vec<u8>,
},
GetResponse {
tag: Tag,
serialized_item: Vec<[u8]>,
},
FinalitySignature(FinalitySignature),
}

enum DeployGossiperMessage {
Gossip(DeployHash),
GossipResponse {
item_id: DeployHash,
is_already_held: bool,
},
}

enum AddressGossiperMessage {
Gossip(GossippedAddress),
GossipResponse {
item_id: GossippedAddress,
is_already_held: bool,
},
}

struct DeployHash(Digest);
struct GossipedAddress(SocketAddr);

Consensus

A consensus message is sent exclusively between instances of the consensus component, from one peer to another. A precise description of the Highway consensus protocol is out of scope of this document, see the consensus::Message type or an appropriate description of the underlying protocol for details.

Gossiping

Gossiping messages are sent by a node to a subset of its peers to announce the availability of new data items. Peers MUST be distinguished by NodeID, not by listening address.

A node must support a gossiper for deploys and one for GossippedAddress, which is an alias for the regular Rust standard library's SocketAddr.

A node SHOULD begin a gossiping process for all deploys previously unknown to it. A node MUST periodically send an AddressGossiperMessage::Gossip message to a random subset selected in a similar manner as the one for deploy gossip to make its own address known, see the gossiping process section below for details.

Unsafe-for-syncing

A node that is syncing MUST indicate this by setting is_syncing to true.

A node MAY implement a scheme for request throttling/backpressure for GetRequests (see below) of TrieNodes that can cause issues with peers that are also sending GetRequests.

A node that succeeds in a handshake with a peer that has set is_syncing MUST make note of this flag. If the node itself is implementing the feature described above, it MUST NOT make any GetRequests directed at this peer for TrieNodes.

Gossiping

Gossiping is distributing items across the network by sending it to a subset of known peers that do not have the item already, and having them repeat this process until a certain degree of saturation is observed.

Any item has an associated ID type which denotes what is used to uniquely identify it when gossiping. If an item is small enough, the ID may just be the item itself.

Gossiper messages have the following structure:

enum GossiperMessage {
Gossip(Id),
GossipResponse {
item_id: Id,
is_already_held: bool,
},
}

To gossip, a node MAY send a GossiperMessage::Gossip message to a random subset of configurable size of peers to announce that it has received and validated a new item. Any peer receiving such a message SHOULD answer with a GossiperMessage:GossipResponse, citing the given id and using is_already_held to indicate whether it already possessed the given item.

The node SHOULD attempt to continue to find peers with a negative response, up to a configurable limit of attempts and/or success rate, or until running out of valid peers.

The node that initiated the gossip MUST keep track of which peer replied with a positive (is_already_held being true) response and MUST NOT send another Gossip message for same ID to any of these peers during this gossip process. However, it MAY restart gossiping the same item at a later time, considering these peers again.

If a node receives a negative GossiperMessage::GossipResponse (i.e. is_already_held being false), and the item's ID is not the item itself, it MUST handle that repsponse as if the peer had sent a GetRequest for the item (see GetRequests section below).

GetRequests

The "GetRequests" mechanism allows retrieving various items through primary or derived keys from peers.

A peer MAY send a GetRequest (see Payload::GetRequest) with a Tag and serialized_id payload. Both serialized_id and serialized_item MUST be encoded using bincode (see "Encoding" section for details).

pub enum Tag {
Deploy,
FinalizedApprovals,
Block,
GossipedAddress,
BlockAndMetadataByHeight,
BlockHeaderByHash,
BlockHeaderAndFinalitySignaturesByHeight,
TrieOrChunk,
BlockAndDeploysByHash,
BlockHeaderBatch,
FinalitySignaturesByHash,
}

The tag dictates which item is being retrieved, and which key (ID type) is being used.

A node that receives a GetRequest from a peer SHOULD return a GetResponse (see Payload::GetResponse). The GetResponse MUST use the same Tag.

pub enum FetchedOrNotFound<T, Id> {
Fetched(T),
NotFound(Id),
}

If the item was found, serialized_item MUST contain a serialized FetchedOrNotFound::Fetched instance, with the inner value T being the item.

If the item was not found, serialized_item MUST contain a FetchedOrNotFound::NotFound instance, with the inner value Id being the ID found in the originating GetRequest.

A node MUST not send any items to a peer that it itself has not verified.

The following table shows which tag corresponds to which ID and item type. Type definitions for DeployHash and GossippedAddress can be found earlier in this document, other types are described following this section. Further details of many of these types can be found in the Serialization Standard, but be aware that those docs describe serializing using bytesrepr rather than bincode.

TagID typePayload (item) type
DeployDeployHashDeploy
FinalizedApprovalsDeployHashFinalizedApprovalsWithId
BlockBlockHashBlock
GossipedAddressGossipedAddressGossipedAddress
BlockAndMetadataByHeightu64BlockWithMetadata
BlockHeaderByHashBlockHashBlockHeader
BlockHeaderAndFinalitySignaturesByHeightu64BlockHeaderWithMetadata
TrieOrChunkTrieOrChunkIdTrieOrChunk
BlockAndDeploysByHashBlockHashBlockAndDeploys
BlockHeaderBatchBlockHeadersBatchIdBlockHeadersBatch
FinalitySignaturesByHashBlockHashBlockSignatures
pub struct Deploy {
hash: DeployHash,
header: DeployHeader,
payment: ExecutableDeployItem,
session: ExecutableDeployItem,
approvals: BTreeSet<Approval>,
}

struct DeployHeader {
account: PublicKey,
timestamp: u64,
ttl: u64,
gas_price: u64,
body_hash: Digest,
dependencies: Vec<DeployHash>,
chain_name: String,
}

enum PublicKey {
System,
Ed25519(Vec<u8>),
Secp256k1(Vec<u8>),
}

enum ExecutableDeployItem {
ModuleBytes {
module_bytes: Vec<u8>,
args: RuntimeArgs,
},
StoredContractByHash {
hash: [u8; 32],
entry_point: String,
args: RuntimeArgs,
},
StoredContractByName {
name: String,
entry_point: String,
args: RuntimeArgs,
},
StoredVersionedContractByHash {
hash: [u8; 32],
version: Option<u32>,
entry_point: String,
args: RuntimeArgs,
},
StoredVersionedContractByName {
name: String,
version: Option<u32>,
entry_point: String,
args: RuntimeArgs,
},
Transfer { args: RuntimeArgs },
}

struct RuntimeArgs(Vec<NamedArg>);

struct NamedArg(String, CLValue);

struct CLValue(CLType, Vec<u8>);

enum CLType {
Bool,
I32,
I64,
U8,
U32,
U64,
U128,
U256,
U512,
Unit,
String,
Key,
URef,
PublicKey,
Option(Box<CLType>),
List(Box<CLType>),
ByteArray(u32),
Result { ok: Box<CLType>, err: Box<CLType> },
Map { key: Box<CLType>, value: Box<CLType> },
Tuple1([Box<CLType>; 1]),
Tuple2([Box<CLType>; 2]),
Tuple3([Box<CLType>; 3]),
Any,
}

struct Approval {
signer: PublicKey,
signature: Signature,
}

enum Signature {
System,
Ed25519(Vec<u8>),
Secp256k1(Vec<u8>),
}

struct FinalizedApprovalsWithId {
id: DeployHash,
approvals: FinalizedApprovals,
}

struct FinalizedApprovals(BTreeSet<Approval>);

struct Block {
hash: BlockHash,
header: BlockHeader,
body: BlockBody,
}

struct BlockHash(Digest);

struct BlockHeader {
parent_hash: BlockHash,
state_root_hash: Digest,
body_hash: Digest,
random_bit: bool,
accumulated_seed: Digest,
era_end: Option<EraEnd>,
timestamp: u64,
era_id: u64,
height: u64,
protocol_version: ProtocolVersion,
}

struct EraEnd {
era_report: EraReport,
next_era_validator_weights: BTreeMap<PublicKey, U512>,
}

struct EraReport<VID> {
equivocators: Vec<PublicKey>,
rewards: BTreeMap<PublicKey, u64>,
inactive_validators: Vec<PublicKey>,
}

struct ProtocolVersion {
major: u32,
minor: u32,
patch: u32,
}

struct BlockBody {
proposer: PublicKey,
deploy_hashes: Vec<DeployHash>,
transfer_hashes: Vec<DeployHash>,
}

Custom variable length encoding is used when serializing U512, U256 and U128 types. They are encoded in a way equivalent to encoding the following pseudo struct:

struct Bigint {
serialized_length: u8,
little_endian_unpadded_bytes: [u8, serialized_length - 1],
}

In other words, the following steps are taken:

  • convert the bigint to an array of bytes in little-endian form
  • strip the contiguous range of irrelevant padding 0 bytes from the right hand end, if any
  • prefix this remaining array with a byte holding the number of remaining bytes + 1, to indicate the length of the final byte array including the length byte itself

For a description explaining the use of TrieOrChunk and related types, see the "Trie chunking" section. The relevant types are:

struct TrieOrChunkId(u64, Digest);

enum TrieOrChunk {
Trie(Bytes),
ChunkWithProof(ChunkWithProof),
}

struct ChunkWithProof {
proof: IndexedMerkleProof,
chunk: Bytes,
}

struct IndexedMerkleProof {
index: u64,
count: u64,
merkle_proof: Vec<Digest>,
}

BlockHeadersBatchId is used to request multiple BlockHeaders with a single request.

struct BlockHeadersBatchId {
highest: u64,
lowest: u64,
}

struct BlockWithMetadata {
block: Block,
finality_signatures: BlockSignatures,
}

struct BlockHeaderWithMetadata {
block_header: BlockHeader,
block_signatures: BlockSignatures,
}

struct BlockSignatures {
block_hash: BlockHash,
era_id: u64,
proofs: BTreeMap<PublicKey, Signature>,
}

struct BlockAndDeploys {
block: Block,
deploys: Vec<Deploy>,
}

struct BlockHeadersBatch(Vec<BlockHeader>);

Finality Signatures

The Payload::FinalitySignature variant is used when broadcasting finality signatures.

A node that is an active validator MUST create and broadcast, i.e. send to all connected peers, a finality signature for every valid block it receives or creates.

Trie Chunking

Large trie nodes are split when transferred across the network, according to CHUNK_SIZE_BYTES, which is set to 8388608 bytes (8 megabytes). Any trie node that is less than 8388608 in size will be represented by a TrieOrChunk::Trie instance.

Should a trie node be larger than this, a Merkle tree is constructed with CHUNK_SIZE_BYTES sized chunks and is identified by the root hash of the resulting tree instead.

Peers MUST only request chunks. The TrieOrChunkId type allows for requesting the n-th chunk of a given trie node. See the casper-hashing crate for details.

A node receiving a TrieOrChunk item from a peer MUST validate it by checking the given Merkle proof against the item hash (which is the tree's root hash), before accepting it.

Network Communication

Identity

Each node has an identity on the network (which is not the same as its identity in the consensus process). The network identity (ID) is based on the fingerprint of the public key of a TLS certificate. A node generates a new private key each time it starts, ensuring a unique ID.

Each identity is linked with an address, which is an IP and port pair where the node is reachable. This address is also called an endpoint.

Inter-node connections

Should a node want to connect to another node with a known endpoint, it opens a TLS connection to the endpoint's address. In the context of common TLS terminology, this makes the connecting node the client and the remote node the server for this connection.

During connection setup, the client checks the server's certificate, matching the endpoint's expected public identity to ensure we have connected to the right node. Additionally, the TLS parameters of the connection and certificate are required to contain the same ciphers, digests, etc., to protect against downgrade attacks.

Simultaneously, the connecting node sends its certificate as the client certificate, allowing the server to perform the same check-in reverse and establish the client's ID. At the end of the process, both nodes can be sure to which peer they are connected.

Once a connection is established, the server will immediately seek to connect back to the client based on its endpoint (see Node Discovery on how the server finds endpoints).

Connections are used for sending messages one-way only; only the node initiating a connection will send messages on it.

Network

As soon as a node has connected to one node in the network, it partakes in Node Discovery. In general, any node will attempt to connect to any other node on the network it finds as described above, leading to a fully connected network.

Two classes of data transfers happen in the network; broadcasts and gossiping. A broadcast message is sent once, without guarantees, to all the nodes connected to it. The process of gossiping is described further below.

In general, only consensus messages, which are only sent by active validators, are broadcast. Everything else is gossipped.

Gossiping

Multiple types of objects are gossipped, the most prominent ones being blocks, deploys, and endpoints (see Identity). Each of these objects is immutable and can be identified by a unique hash.

Gossiping is a process of distributing a value across the entire network without directly sending it to each node. This process allows only a subset of nodes to be connected to the original sender and spreading the bandwidth and processing requirements across the network at the cost of latency and overall bandwidth consumed.

The process can be summarized as follows:

Given a message M to gossip, the desired saturation S, and an infection limit L:

  1. Pick a subset T of K nodes from all currently connected nodes.
  2. Send M to each node in T, noting which nodes were already infected (a node is considered infected if it already had received or known M).
  3. For every node shown as already infected, add another random node outside to T and send it M, again noting the response.
  4. End when we confirm infection of L new nodes or encountered S already infected nodes.

Through this process, a message will spread to almost all nodes over time.

Requesting missing data

While gossiping and broadcasting are sufficient to distribute data across the network in most cases, nodes can also request missing data from peers should they require it. A common example is a missing deploy from a block.

Validation

Objects have a concept of dependencies. For example, a block depends on all the deploys whose hashes are listed inside it. A node considers any object valid if all of its dependencies are available on the local node.

Should a node receive an object from a peer that is not valid yet, it will attempt to complete its validation before processing it further. In the case of gossiping, this means pausing the gossiping of the object until all its dependencies can be retrieved.

Any node is responsible for only propagating valid objects. Should a node not retrieve all missing dependencies of an object from the peer that sent it, it may punish the peer for doing so.

Node Discovery

Node discovery happens by each node periodically gossiping its public address. Upon receiving an address via gossip, each node immediately tries to establish a connection to it and notes the resulting endpoint, if successful.

Reading and Writing Data to Global State

Casper features several means of reading and writing data to global state, depending on user needs and complexity. Reading data from global state can be done by dApps off-chain or by smart contracts on-chain. Writing data requires on-chain interactions due to the nature of the system. Storage in global state can be accomplished using Dictionaries or NamedKeys.

note

Due to the nature of Casper's serialization standard, NamedKeys should be used sparingly and only for small data sets. Developers should use dictionaries for larger mapped structures.

Using the Casper JSON-RPC

The query_global_state method available through the JSON-RPC allows users to read data from global state without performing on-chain actions. For more details, see the Querying a Casper Network tutorial.

Using the Casper Rust API

The Casper API includes the following functions for reading and writing to global state:

  • put_key - Stores the given Key under the given name in the current context's named keys
  • get_key - Returns the requested NamedKey from the current context
  • storage::new_uref - Creates a new URef in the current context
  • storage::write - Writes a given value under a previously created URef
  • storage::read - Reads the value from a URef in global state
  • dictionary_put - Writes the given value under the given dictionary_item_key
  • dictionary_get - Retrieves the value stored under a dictionary_item_key

For more details, see the Reading and Writing to Global State using Rust tutorial.

Understanding Dictionaries

In a Casper network, you can now store sets of data under Keys. Previously, URefs were the exclusive means by which users could store data in global state. To maintain persistent access to these URefs, they would have to be stored within an Account or Contract context. In the case of Contracts, sustained and continuous use of URefs would result in the expansion of the associated NamedKeys structures.

Individual value changes to data stored within the NamedKeys would require deserializing the entire NamedKeys data structure, increasing gas costs over time and thus having a negative impact. Additionally, users storing large subsets of mapped data structures would face the same deep copy problem where minor or single updates required the complete deserialization of the map structure, also leading to increased gas costs.

As a solution to this problem, the Casper platform provides the Dictionary feature, which allows users a more efficient and scalable means to aggregate data over time.

In almost all cases, dictionaries are the better form of data storage. They allow greater flexibility in altering stored data at a lower cost.

Seed URefs

Items within a dictionary exist as individual records stored underneath their unique dictionary address in global state. In other words, items associated with a specific dictionary share the same seed URef but are otherwise independent of each other. Dictionary items are not stored beneath this URef, it is only used to create the dictionary key.

As each dictionary item exists as a stand-alone entity in global state, regularly used dictionary keys may be used directly without referencing their seed URef.

Using Dictionaries

Dictionaries are ideal for storing larger volumes of data for which NamedKeys would be less suitable.

Creating a new dictionary is fairly simple and done within the context of a Deploy sent to a Casper network. The associated code is included within the casper_contract crate. Creating a dictionary also stores the associated seed URef within the named keys of the current context.

Developers should always consider context when creating dictionaries. We recommend creating a dictionary within the context of a Contract.

While you can create a dictionary in the context of an Account and then pass associated access rights to a Contract, this approach can create potential security issues. If a third party uses the Contract, the initiating Account with access rights to the dictionary may be undesirable. To rectify this, you may send an additional Deploy removing those access rights, but it is better to create the dictionary within the context of the Contract.

Dictionaries allow a contract to store additional data without drastically expanding the size of the NamedKeys within their context. If a contract's NamedKeys expand too far, they may run into system limitations that would unintentionally disable the contract's functionality.

A dictionary item key can be no longer than 64 bytes in length.

Practical Dictionary Examples

The Casper CEP-78 Enhanced NFT Standard includes several practical applications of dictionaries.

Simple examples for dictionary use within CEP-78 include the approve dictionary.

More advanced dictionary functionality can be found in the CEP-78 Page System, which uses a series of dictionaries to keep track of token ownership. These dictionaries form the basis of the reverse lookup mode, which allows users to easily view a list of owned tokens by account or contract.

Creating Dictionaries in a Contract's Context

The following code snippet shows the most basic example of creating a dictionary.


casper_contract::contract_api::storage::new_dictionary(dict_name)

The following example includes the creation of a dictionary "ledger" within a contract's context. In this instance, the dictionary will be used to track donations made to a fundraising purse also created by the init entry point. In any case where you want to use a dictionary within your contract, it should be set up within the initializing entry point.


#[no_mangle]
pub extern "C" fn init() {
let fundraising_purse = system::create_purse();
runtime::put_key("fundraising_purse", fundraising_purse.into());
// Create a dictionary to track the mapping of account hashes to number of donations made.
storage::new_dictionary("ledger").unwrap_or_revert();
}

Writing Entries into a Dictionary

After the creation of a dictionary, you may then add entries through the use of the following code:


storage::dictionary_put(dictionary_uref, &dictionary_item_key, value);

The dictionary_uref refers to the seed URef established during the dictionary creation process. The key is the unique identifier for this dictionary item, and the value is the data to be stored within the dictionary.

As stated above, these dictionary items do not require the seed URef, and they exist as individual keys in global state. If you know an individual key's address, you do not need to go through the process of identifying the seed URef first.

The following function serves to add an entry to the dictionary. If the item already exists, the entry point will update the value stored and referenced by that key. In this case, the code is storing the number of donations made. Any Rust structure may be stored under a dictionary item, but when updating a value within a larger structure (i.e., a list), the entire structure will be overwritten as part of the update. Updating a larger structure will incur the full cost of writing the structure to a dictionary item.

The first section acquiring the LEDGER seed URef to assign the new dictionary item to the proper dictionary.


fn update_ledger_record(dictionary_item_key: String) {
// Acquiring the LEDGER seed URef to properly assign the dictionary item.
let ledger_seed_uref = *runtime::get_key("ledger")
.unwrap_or_revert_with(FundRaisingError::MissingLedgerSeedURef)
.as_uref()
.unwrap_or_revert();

The second section uses dictionary_get to read an entry within the LEDGER dictionary. If the entry does not exist on global state, it will create the entry. If it already exists, the entry is updated with the current value using a dictionary_put operation. As stated above, regardless of the size of the change within the entry, the entire dictionary entry will need to be overwritten and will incur the associated cost.


// This identifies an item within the dictionary and either creates or updates the associated value.
match storage::dictionary_get::<u64>(ledger_seed_uref, &dictionary_item_key).unwrap_or_revert()
{
None => storage::dictionary_put(ledger_seed_uref, &dictionary_item_key, 1u64),
Some(current_number_of_donations) => storage::dictionary_put(
ledger_seed_uref,
&dictionary_item_key,
current_number_of_donations + 1u64,
),
}
}

Reading Items from a Dictionary using the JSON-RPC

The Casper platform provides several means of looking up a dictionary item. These means are explained within the DictionaryIdentifier JSON-RPC type. The following explains how to query the dictionary items using the Casper client.

ContractNamedKey lookup via a Contract's named keys.

Reading a dictionary item using the Contract's NamedKeys requires the following parameters:

  • Node Address - The IP and port of a node on a Casper network. In the example below, the node address is pointing to a local NCTL network.

  • State Root Hash - The current state root hash of a Casper network hosting the dictionary item you are attempting to read.

  • Contract Hash - The hash of the contract that references the dictionary in its NamedKeys.

  • Dictionary Name - The name of the dictionary as a String stored in the Contract's NamedKeys.

  • Dictionary Item Key - The specific dictionary item key to be read, as a String.


casper-client get-dictionary-item \
--node-address http://localhost:11101 \
--state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \
--contract-hash hash-09c8fa7c1441ae7c1cbe27ae3a722fd4ffc5290315f8546454454c1b9f85c842 \
--dictionary-name <String> \
--dictionary-item-key <String>

URef lookup via the dictionary's seed URef.

Reading a dictionary item using the dictionary's seed URef requires the Node Address, State Root Hash and Dictionary Item Key as above. However, it does not require the Contract Hash or Dictionary Name. Instead, it requires:

  • Seed URef - The Seed URef of the dictionary to reference.

casper-client get-dictionary-item \
--node-address http://localhost:11101 \
--state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \
--dictionary-item-key <String> \
--seed-uref uref-90b4a8d936b881d3b45b73a102adb2b652181d75c76b7547ae9d1bb213f8db6b-007

Dictionary lookup via the unique dictionary item key.

In the event that you know the dictionary address of the dictionary item key you need to read, you can read it directly using the following Casper client command.


casper-client get-dictionary-item \
--node-address http://localhost:11101 \
--state-root-hash 50c34ccbe1315d58ce22bf7518071164d16acd20a1becb0b423293418297416d \
--dictionary-address dictionary-<string>

Staking Concepts

The Casper network is a Proof-of-Stake blockchain that allows validators to stake the Casper native token CSPR on the network. Validators receive CSPR as an incentive for continuing to maintain and secure the network. CSPR rewards are distributed as blocks are validated into existence and organized into eras.

Consensus mechanism: Casper operates using a Proof-of-Stake consensus mechanism per the Highway Protocol, a specification of Correct-by-Construction Casper (CBC Casper).

Number of validators: The Casper Mainnet supports up to 100 validators on the network. This number is chosen to strike a balance between performance and decentralization. This platform parameter can be increased through upgrades as development continues and performance improves. In addition, validators can stake on the Casper Mainnet through a process of permission-less bonding by participating in an auction for the validator slot.

Permission-less bonding: For validators to begin staking and earning rewards, they must win a staking auction by competing with current and prospective validators to supply one of the forthcoming top stakes for a given era. This process is permission-less, meaning validators can join and leave the auction without restrictions, except for a waiting period to unlock staked tokens.

Unbonding: To detach from a Casper network, it takes seven eras for both validators and delegators. Neither validators nor delegators receive rewards during the seven eras required for unbonding, as they are not actively contributing to the network's security during that time.

Eras and block times: An era on Casper is roughly 2 hours long. Casper's Highway protocol allows validators to propose blocks as quickly as network conditions allow, subject to a platform-wide limit that may be adjusted with upgrades. We anticipate block times to last between thirty seconds and eight minutes.

Block rewards: Block time is orthogonal to rewards, so there is no precise reward per block. Instead, the number of rewards is split proportionally among stakes and reduced for failure to participate in the protocol promptly.

Reward cycle: Rewards are distributed to validators and delegators once per era.

Token supply and inflation: Mainnet launched with ten billion CSPR at the time of genesis. The target annual supply growth rate is 8%.

Annual reward percentage: Validators on the Casper Mainnet earn between 10% and 20% of their staked CSPR in the first year of the Mainnet operation, with regular participation under expected network conditions. The growth of individual stakes is dependent on total active stake, as only a fixed number of tokens is created per era.

Please visit the Staking Guide for further details on the staking mechanism.

Consensus Economics

Highway consensus is a continuous, trust-less process where a fixed set of validators engage in scheduled communication to advance the linear chain of finalized blocks, representing the history of changes to the global state of the blockchain. The fixed set of validators may change at each era boundary. The economics of this layer revolve around validator selection and incentivization of participation according to the schedule.

Entry

After genesis, the system selects a set of validators using a stake auction process. The auction takes place in the last block of an era, also called a switch block. An auction contract governs the validator selection process, and a chainspec configuration file specifies a few key parameters:

  • The auction_delay specifies the amount of time that needs to pass before the system enables a new set of validators. For example, the auction_delay is 1 for Mainnet. Therefore, after a delay of 1 era, the winning validators become the validating set for the new era.
  • The validator_slots parameter specifies how many validators can win an auction. The auction selects a fixed number of validators based on their highest bids.

Bids

Each bid is a collection of tokens from a prospective or current validator and its delegators, considered in the auction as a single total. Bids and delegations can increase freely, but withdrawals are subject to an unbonding period governed by the unbonding_delay chainspec parameter. Tokens that are in the unbonding period are not part of the sum total considered in the auction. Consequently, the exact amount of the bid, which translates into protocol weight for winning validators, can vary within an era. The bids are visible in the switch block that determines the winners.

Each bid contains a delegation rate and activity status. The delegation rate can change at any time. Both of these properties are described further in this document.

Delegation

Delegation allows third parties to participate in consensus by adding weight to their preferred validators. Rewards received by validators are distributed in proportion to tokens bid and delegated. The current or prospective validator responsible for the bid receives a portion of the delegator rewards set by the delegation rate.

Currently, delegation is unrestricted. Please visit Delegation details page to check more about delegation cost and related details.

Incentives

Correct operation of the Highway protocol requires the economics of the platform to discourage equivocation for safety and incentivize participation for liveness. Participation consists of on-time block proposals and timely responses to block proposals.

Safety may be incentivized through slashing for equivocation. This feature is currently disabled but may be reactivated in the future.

The network incentivizes participation by scaling rewards for on-time proposals and responses, taking into account the speed of finalizing blocks. All rewards are added directly to the corresponding bids and delegations.

Participation

Issuance of new tokens and their distribution to validators incentivizes work even under low transaction load.

CSPR is issued at a fixed rate and distributed to validators (and, indirectly, delegators) in proportion to their stake. This is analogous to block rewards in Proof-of-Work blockchains, outlining the following:

  • The growth of CSPR supply is exponential
  • Issuance takes into account slashed CSPR

With slashing disabled, we can compute block rewards starting with the formula below, where we have these parameters:

  • i - the era's index as a positive integer [0, 1, 2, ..., n]
  • initial_supply - the number of CSPR at genesis
  • issuance_rate - the annual rate at which new CSPR tokens are minted
  • ticks_per_year - the number of milliseconds in a year equal to 31,536,000,000
supply(i) = initial_supply * (1 + issuance_rate)^(tick_at_era_start(i) / ticks_per_year)

We introduce the round issuance rate (corresponding to the chainspec parameter round_seigniorage_rate) with this formula:

round_issuance_rate = (1 + issuance_rate)^(2^minimum_round_exponent / ticks_per_year) - 1

The round issuance rate is the annual issuance rate adjusted to a single round of length determined by the chainspec parameter minimum_round_exponent. For illustration, an exponent of 14 corresponds to a round length of roughly 16 seconds.

Finally, the base round reward is computed as:

base_round_reward(i) = round_issuance_rate * supply(i)

This value gives us the maximum amount of CSPR that the validators can collectively receive from a proposed block.

Distribution

Validators receive tokens for proposing and finalizing blocks according to their performance. The concept of weight is crucial for understanding this distribution scheme:

  • Weight: A validator's bonded stake, used in consensus
  • Assigned weight of a block/round: The total stake of validators scheduled to participate in a block
  • Participated weight of a block/round: The total stake of validators that end up participating or sending messages to finalize a block before the end of their respective round

To determine eligibility, we look at on-time finalization (OTF). Validators should finalize blocks on time by sending required messages before the end of their respective round.

Switch blocks are not visible to the issuance calculation (as this calculation is performed in the switch block itself for each era), and, consequently, no tokens are issued for switch blocks.

Participation schedule

The participation schedule is segmented into rounds, which are allocated dynamically according to the validators' exponents and a deterministic (randomized at era start) assignment of validators to milliseconds of an era. Thus, a validator with the round exponent n must participate in rounds that repeat every 2^n ticks.

Each validator is assessed according to its round exponent. All assigned validators become eligible to receive tokens as long as the block gets finalized with messages sent within each validator's round.

Eligibility

Once a block has been proposed and enough time has passed, the history of protocol messages can be examined to detect whether the block was finalized on time, according to the conditions given above. If the block was not finalized on time, validators receive a fraction of the expected tokens, governed by the reduced_reward_multiplier chainspec parameter. If the block was finalized on time, assigned validators share the reward proportionally to their stake, regardless of whether they have sent messages or not.

Inactivity

Validators who send no messages during an entire era are marked as inactive and cease participating in the auction until they send a special deploy that reactivates their bid.

Slashing

Please review our Equivocator Policy. We are currently conducting research into the utility of slashing as an incentive mechanism.

Founding validators

Founding validators are subject to token lock-up, which prevents them from withdrawing any tokens from their bids for 90 days, then releases their genesis bid tokens in weekly steps, linearly, over an additional 90 days.

Delegation Details

This section provides a detailed explanation of the delegation cost mechanism, how the gas cost relates with delegations, where to find the details etc. Please note that the cost amounts are likely to change with time and you may have to check the latest release details to get the most up-to-date and accurate details.

Delegation Cost

The delegation cost is defined in the chainspec.toml file for each Casper network. In this example chainspec, the delegation is set to cost 2.5 CSPR. However, when you perform the delegation, you see that it costs a little more than what is specified in the chainspec. Let’s discuss why this happens.

When you delegate, the system automatically charges some gas to set up related data in the global state of the network to track your delegation. This cost is addition to the delegation cost defined in the chainspec file.

For example, the chainspec file in release 1.3.2 will contain the following information. This is how the delegation cost is defined in the chainspec.toml file of a Casper network.

cost

Figure 1: Delegation cost is defined in the chainspec.toml file of a Casper network

Delegation fees may change over time, so, it is essential to stay up to date. To do so, select the latest release in Github, and navigate to the chainspec.toml file.

If you are unsure about anything, please join the Discord channel to ask us questions.

First-time Delegation

If you perform the delegation for the first time, the system charges some gas to create a purse to hold the delegated tokens.

Example: The system can charge 0.5 CSPR in addition to the base delegation fee of 2.5 CSPR, resulting in a delegation cost of 3 CSPR on Mainnet

It is essential to have enough funds in your account's main purse when you set up a delegation transaction. Otherwise, the transaction will fail, and you will lose the transfer cost. For example, if you have 200 CSPR in your purse, delegate at most 197 CSPR and leave at least 3 CSPR for the delegation cost. Another option is to delegate 195 CSPR and leave some additional buffer.

As a result, when performing a delegation using the command line, we recommend you specify a little more than the base transaction payment to ensure that the transaction will go through without failure.

details

Figure 2 : On Testnet or Mainnet, the transaction fee for a delegation is a little bit higher than 2.5 CSPR


NOTE:

Transaction costs depend on each Casper network and the cost tables defined in the chainspec. The examples you will find in the documentation are general.


Lastly, we recommend that you try out delegations on the Casper Testnet before making actual transactions on the Casper Mainnet. This way, you will understand the costs involved in delegating tokens.

Gas and Resources

What is gas?

Gas is a conceptual measure of resources utilized when executing transactions on the blockchain. Gas cost is the amount of gas consumed during the processing cycles that execute a transaction on the network. It is directly correlated with the amount of computer processing a validator needs to provide in order to execute a transaction.

Gas fees are consumed on the network irrespective of whether your transaction was successful or not. Even when a transaction fails, you have to pay the transaction fee because your deploy consumed resources and space on the block as the validator attempted to execute it on your behalf.

How is gas cost determined?

The amount of gas required for a transaction is determined by how much code is executed on the blockchain. Currently, gas is priced at a fixed price of 1 mote (1 CSPR is 10^9 motes) per 1 unit of gas. The gas charged for a transaction on the blockchain is paid to the network's validators.

Why do we need gas cost?

Casper is a decentralized network of individual validators supplying their computational resources to keep the network live. As such, computations must be rate-limited and priced for the following reasons:

  • Rate-limiting is used to ensure a secure and live network:
    • It prevents a specific kind of denial-of-service (DoS) attack. In computer networks, rate-limiting is used to control the rate of requests sent or received by a network to prevent DoS attacks. Gas behaves in a similar fashion, because each block permits only a fixed amount of transactions (gas) to be included in the era.
    • It explicitly quantifies the system load. The gas cost helps us evaluate the use of computational resources and measure the amount of computational work that validators need to perform for each transaction. With this knowledge, we can specify minimum system requirements for validators.
  • Pricing leads to more meaningful transactions:
    • Issuers of transactions and smart contract writers will be more aware of the limited network resources because there is a cost associated with each transaction. Pricing prevents users from spamming arbitrary amounts of empty transactions because there is a price to pay for each deploy.

Why do I see an ‘Out of gas error’?

You might encounter an ‘Out of gas error’ when the gas payment you supplied for the transaction was insufficient to cover the actual cost of computation for the transaction. The amount of gas required for a transaction is determined by how much code is executed on the blockchain and also the storage utilized.

Here is an example of a transaction resulting in an ‘Out of gas error’ on the Mainnet.

Figure 1: In the Deploys tab of an account on cspr.live, a red exclamation mark is shown. By moving the cursor over it, the tooltip displays an 'Out of gas error'.

Out of gas error

Figure 2: Click the specific deploy to see more details such as the deploy hash, cost, and the status as an 'Out of gas error'. This indicates that the transaction did not have sufficient payment to cover the gas required for it to complete successfully.

Gas error in account

Figure 3: Click the Show raw data button, to see more details about the deploy. Towards the end of the raw data, you can see the error message.

Gas error in raw data

How do I determine the gas cost for a transaction?

Currently, we are hard at work to create tools to help you estimate gas costs. Meanwhile, we recommend using the NCTL tool on your local machine or the Testnet to deploy your contracts in a test environment. You can check a deploy status and roughly see how much it would actually cost when deployed. You can estimate the costs in this way and then add a small buffer if the network state has changed. Note that when estimating gas cost locally or on the Testnet, the blockchain specification needs to match the specification of the Mainnet, where you will need to pay for the transaction with actual Casper (CSPR) tokens.

Why do I see a gas limit error?

You may sometimes see an error such as ‘payment: 2.5, cost: 2.5, Error::GasLimit’, This message seems to say that the transaction cost is 2.5 CSPR and you paid 2.5 CSPR, yet the transaction resulted in an error. Let’s explore this error message a little further.

When a smart contract hits its gas limit (the payment amount), execution stops. If your limit is 2.5 CSPR, execution stops and that is the computation cost even if the smart contract did not run to completion. So, the error message tries to communicate to you that execution stopped at 2.5 CSPR. The computation resulted in an error because there were not enough funds to run to completion. It would have cost more than 2.5 CSPR to complete execution, but since you only supplied a payment of 2.5 CSPR worth of computation, the network stopped execution there and charged you that much, even though it was a failed transaction. The execution engine does not actually know how much it would have cost if allowed to run to completion, because it did not allow the contract to finish since the contract would have run over its gas limit.

Global State

Introduction

The storage layer for the Casper blockchain is called global state and has the semantics of a key-value store with additional permissions logic. All accounts, contracts, and any associated data they have are stored in global state. Not all users can access all data, so permissions need to be set accordingly.

note

Refer to Keys and Permissions for further information on keys.

Each finalized block causes changes to the network's global state because of the execution of the deploys it contains. For validators to efficiently judge the correctness of these changes, information about the new state needs to be communicated succinctly. Moreover, the network must communicate portions of global state to users while allowing them to verify the correctness of the parts they receive. For these reasons, the key-value store is implemented as a Merkle trie.

Merkle Trie Structure

Global State

At a high level, a Merkle trie is a key-value store data structure that can be shared piece-wise in a verifiable way (via a construction called a Merkle proof). Each node is labeled by the hash of its data. Leaf nodes are labeled with the hash of their data. Non-leaf nodes are labeled with the hash of the labels of their child nodes.

Casper's implementation of the trie has radix of 256, meaning each branch node can have up to 256 children. A path through the tree can be an array of bytes, and serialization directly links a key with a path through the tree as its associated value.

Formally, a trie node is one of the following:

  • a leaf, which includes a key and a value
  • a branch, which has up to 256 blake2b256 hashes, pointing to up to 256 other nodes in the trie (recall each node is labeled by its hash)
  • an extension node, which includes a byte array (called the affix) and a blake2b256 hash pointing to another node in the trie

The purpose of the extension node is to allow path compression. Consider an example where all keys use the same first four bytes for values in the trie. In this case, it would be inefficient to traverse through four branch nodes where there is only one choice; instead, the root node of the trie could be an extension node with an affix equal to those first four bytes and a pointer to the first non-trivial branch node.

The Rust implementation of Casper's trie can be found on GitHub:

note

Conceptually, each block has its trie because the state changes based on the deploys it contains. For this reason, Casper's implementation has a notion of a TrieStore, which allows us to look up the root node for each trie.

A


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Account

An Account is a structure that represents a user on a Casper network. Information on creating an account can be found here.

Account Hash

The account hash is a 32-byte hash of the public key representing the user account. Information on generating an account hash can be found here.

AssemblyScript

AssemblyScript is a TypeScript-based programming language (JavaScript with static types) that is optimized for WebAssembly and compiled to WebAssembly using asc, the reference AssemblyScript compiler. It is developed by the AssemblyScript Project and the AssemblyScript community.

Auction

The auction determines the composition of the validator set for each era of the protocol. It is a "first-price" auction (where winning bids become stakes) with a fixed number of spots chosen to balance security with performance. Because rewards are proportional to the stake, it is expected that this competitive mechanism will provide a powerful impetus for staking as many tokens as possible.

Auction contract

The auction contract acts as a front-end user interface to the auction by directly accepting bids from validators and delegators. It also contains the logic necessary for carrying out the auction.

Auction delay

The number of full eras that pass between the booking block and the era whose validator set it defines. The auction delay is configurable and can be several eras long.

B


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Blake2b

A function used within the Casper platform to create cryptographic hashes. More information can be found here.

Block

Used in two contexts:

  1. A data structure containing a collection of transactions. Blocks form the primary structure of the blockchain.
  2. A message that is exchanged between nodes containing the data structure as explained in (1).

Each block has a globally unique ID, achieved by hashing the contents of the block.

Each block points to its parent. An exception is the first block, which has no parent.

Block creation

Block creation means computing the deployment results and collecting the results that belong together into a block. We follow a process called execution after consensus.

The block proposal happens first, and the proposed proto block contains a set of deploys that have not been executed yet.

Only after consensus on a proto block has been reached, the deploys are executed. The resulting new global state root hash is put into an actual block, together with the executed deploys.

Note that only validators can create valid blocks.

Block finality

A block is "finalized" if the validators agree on adding it to the blockchain.

There are different levels of finality in the Highway protocol. A finalized block has a fault-tolerance F, expressed as a fraction of the total stake. For an observer to see a conflicting block as finalized, several validators whose total stake exceeds F would have to collude and show different information in a way that would ultimately be detected and punished (see slashing).

Block gossiping

Block gossiping occurs when a message containing a block is sent to one or more nodes on the network. In other words, block gossiping is sending a block validated by the current node but created by another node. The terms block gossiping and block passing are interchangeable.

Block height

Block height is an identifier for a given block based on the number of blocks completed prior to that block.

Block passing

See block gossiping.

Block processing

Block processing consists of running the deploys in a block received from another node to determine updates to the global state. Note that this is an essential part of validating blocks.

Block proposal

Sending a (newly) created block to the other nodes on the network for potential inclusion in the blockchain. Note that this term applies to NEW blocks only.

Block validation

The process of determining the validity of a block obtained from another node on the network.

Blockchain

Blockchain is a P2P network where the collection of nodes (validators) concurrently updates a decentralized, shared database. They do this collectively, building an ever-growing chain of transactions. For performance reasons, transactions are bundled in blocks. According to a particular cooperation protocol (consensus protocol), the collection of nodes connected via a P2P network cooperate to maintain this shared database as a single source of truth. The database's current state is called the global state and has a sizeable map-like collection.

Block store

The layer of the node software responsible for storing blocks. This layer is persisted and can be used to allow a node to recover its state after a crash.

Bond

The amount of money (in crypto-currency) that is allocated by a node in order to participate in consensus (and to be a validator).

Bonding

Depositing money in the auction contract and try to become a staker. The bonding request is a transaction that transfers tokens to the auction contract. In the next booking block, a new set of validators is determined, with weights according to their deposits. This new set becomes active in the era(s) using that booking block.

Booking block

The booking block for an era is the block that determines the era's validator set. In it, the auction contract selects the highest bidders to be the future era's validators. There is a configurable delay, the auction_delay, which is the number of eras between the booking block and the era to which it applies. The booking block is always a switch block, so the booking block for era N + auction_delay + 1 is the last block of era N.

C


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Cargo

Cargo is Rust's build system and package manager. This tool manages Rust projects, such as building code and downloading dependencies.

Casper network

Casper is a Proof-of-Stake blockchain platform with an account-based model that performs execution after consensus. More information on the design of a Casper network can be found here.

CBC

Correct-by-construction (CBC) protocols are consensus protocols meeting the following properties:

  • All the nodes share the same proof of asynchronous liveness, which means that the protocol will continue to produce blocks at some interval.
  • The consensus has mathematically provable safety, which means that once a block is committed, it cannot be reverted.

Chainspec

A collection of configuration settings describing the state of the system at genesis and upgrades to basic system functionality (including system contracts and gas costs) occurring after genesis. Here is an example chainspec, which will change with newer releases.

Consensus

An algorithm used to mandate agreement on the blockchain between all nodes. The blockchain, although being built in a decentralized way, eventually converges so that all nodes eventually agree on whether a given block is part of the chain or not.

Casper uses the Highway algorithm in the CBC Casper family of consensus algorithms. The algorithm for securing an agreement is what is known as consensus. The consensus layer contains the algorithm, but the algorithm should not be confused with the consensus layer.

Contract runtime

Enables developers to use a seamless workflow for authoring and testing their smart contracts. This environment can also be used for continuous integration, enabling Rust smart contracts to be managed using development best practices.

Correct by construction

See CBC.

Crate

A compilation unit in Rust. A crate can be compiled into a binary or into a library. By default, rustc, the compiler for the Rust programming language, will produce a binary from a crate.

CSPR

CSPR is the Casper token pre-defined on the Casper Mainnet and used to pay for transaction execution and for staking (securing the network).

D


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


dApp

A decentralized application (dApp) employs smart contracts installed on a decentralized peer-to-peer network such as a blockchain.

Delegation rate

Node operators (validators) define a delegation rate that they take in exchange for providing staking services. This delegation rate is a percentage of the rewards that the node operator retains for their services.

Delegator

Delegators are users who participate in the platform's security by delegating their tokens to validators (which adds to their weight) and collecting a part of the rewards proportional to their delegations, net of a cut ("delegation rate") that is collected by the validator.

Deploy

Deploys are units of work when executed cause global state to be altered. Deploys can contain Wasm to be executed and/or Wasm to be stored on chain. Among many examples, Deploys can transfer tokens from one Account's purse to another, reward node validation, or execute Wasm on the network.

All deploys on a Casper network can be broadly categorized as some unit of work that, when executed and committed, affects change to the global state.

Review the deploy data structure and the deploy implementation for more details.

Dictionary

A Dictionary is a storage data structure on a Casper network. Dictionaries represent a more efficient and scalable form of data storage when compared to NamedKeys.

More information can be found in the Reading and Writing to Dictionaries document.

E


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Ecosystem

The ecosystem layer in Casper encompasses dApp design and operation.

Entry point

See EntryPoint and Defining the Contract Entry Points.

Era

A period of time during which the validator set does not change.

In a Casper network, validators cannot join and leave at any point in time, but only at era boundaries. An era's validators are determined using an auction. At the beginning of the era, the validators create a new instance of the Highway protocol and run this consensus protocol until they finalize the era's last block (see booking block).

Eviction

Validators that fail to participate in era will have their bid deactivated by the protocol, suspending their participation until they signal readiness to resume participation by invoking a method in the auction contract.

External client

Any hardware/software connecting to a Node for the purpose of sending deploys or querying the state of the blockchain.

G


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Gas

Gas is the virtual currency for calculating the cost of transaction execution. The transaction cost is expressed as a given amount of gas consumed and can be seen intuitively as some cycles of the virtual processor that has to be used to run the computation defined as the transaction's code.

Genesis

The state of the virtual machine at the beginning of the blockchain.

Groups

The user groups feature provides access control to the entry points of a contract by creating a new user group for that contract (versioned or not). This feature restricts the use of the constructor entry_point, which sets up the necessary data storage in the runtime context that belongs to the contract. Here is how it works:

  • User groups associate a set of URefs with a label.
  • The entry points on a contract can accept a list of labels
  • The runtime checks that a URef from at least one of the allowed groups is present in the caller's context before execution.

Global state

When thinking of a blockchain as a decentralized computer, the global state is its memory state.

When thinking of a blockchain as a shared database, the global state is the snapshot of the database's data.

Technically, a global state is a (possibly extensive) collection of key-value pairs, where the keys are references (Refs), and the values are large binary objects (BLOBs).

For every block B in the blockchain, one can compute the global state achieved by executing all transactions in this block and its ancestors. The root hash identifying this state is stored in every executed block.

H


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Hash

A hash is the output of a cryptographic function that creates a fixed-length output from an input of any length. Casper networks use the blake2b function.

Highway

A consensus protocol that allows clients to use different confidence thresholds to convince themselves that a given block is finalized. The full paper is found in GitHub: https://github.com/casper-network/highway.

L


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Liveness

A necessary property of a consensus protocol: that agreement is always eventually achieved (under certain assumptions).

If the protocol is not live, the blockchain does not grow anymore, and the network stalls.

M


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Mainnet

The live, decentralized, and public Casper platform, with version 1.0.

Merkle tree

A hash tree in which every leaf node is labelled with the cryptographic hash of a data block, and every non-leaf node is labelled with the cryptographic hash of the labels of its child nodes.

Motes

A mote is the native accounting unit for a Casper network. All accounting done within a Casper network occurs through motes, with the CSPR token existing as a human-readable convenience wherein a single CSPR consists of 1,000,000,000 motes.

Multi-Sig

Short for Multi-Signature. Accounts on a Casper network can associate other accounts to allow or require a multiple signature scheme for deploys. More information on the use of Multi-Sig can be found here.

N


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


NamedKeys

NamedKeys are a collection of String-Key pairs used to easily identify some data on the network.

  • The String is the name given to identify the data
  • The Key is the data to be referenced

Node

A Casper node is a physical or virtual device that is participating in a Casper network. They store, validate, and preserve the blockchain data.

You will encounter different types of nodes on the network:

  • Bonded node: a node that has tokens staked as bond and is part of the validator set participating in consensus in that particular era.
  • Unbonded node: a type of node on the network that receives and processes blocks but does not create blocks and is not a validator. It is otherwise a fully functioning node, following the consensus protocol to know the current status of the blockchain (and therefore also the VM state). Such nodes are useful for querying the status of the blockchain (e.g., to learn information about transaction finalization).

Node operator

See operator.

Non-Fungible Token (NFT)

Cryptographic assets on a blockchain with unique identification codes and metadata that distinguish them from each other. They cannot be traded or exchanged at equivalency. This differs from fungible tokens like cryptocurrencies, which are identical to each other and, therefore, can be used as a medium for commercial transactions.

O


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Operator

Anyone running a node is an operator.

An operator that has staked a bid but does not currently have a validator slot is a *staked operator*.

An operator whose bid has won a validator slot in the auction for a specific era is a validator in that era.

It is common for a staked operator to win an auction slot for many eras in a row and thus be a validator for a range of eras.

P


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Partial synchrony

Partial synchrony is used to define the fault tolerance of a consensus protocol, which is a time-bound mechanism to note suspicions or problems (failure, crashes, etc.). When a protocol is provably live under partial synchrony, it means that the nodes will make a decision within a fixed time period. Once the decision is made and a block is committed, it cannot be reverted. Also, see CBC.

Participate in consensus

The process of following the consensus algorithm. The primary participants are validators, bonded with their stake and part of the validator set for that particular era. Delegators participate indirectly by delegating their tokens to one or more of these validators and contributing by increasing the total stake that ensures the security of the network.

Payment code

The payment code is the Wasm program that pays the transaction execution fee.

Peer node

A node on a peer-to-peer (P2P) network.

Permissionless

A permissionless blockchain network has its consensus and transaction validation process open and available for anyone to participate. Being permissionless is an essential characteristic of most public blockchains, enabling decentralization, transparency, and value exchange between participants.

Primary token

See CSPR.

Private key

See secret key.

Proof-of-Stake

Proof-of-Stake (PoS) is a mechanism by which a cryptocurrency blockchain network achieves permissionless-ness. The voting power in consensus is proportional to the number of staked tokens (digital currency specific to this system). The validator vouches with their tokens for the correct operation of their node. A popular choice in such systems is to periodically (once per era, in our case) delegate a fixed size committee of participants, which then is responsible for running the consensus on which blocks to add to the blockchain.

Proof-of-Work

A mechanism used in Bitcoin and Etherium for incentivizing participation and securing the system. In these protocols, a participant's voting power is proportional to the amount of computational power possessed.

Proof-of-Stake contract

The Proof-of-Stake (PoS) contract holds on to transaction fees for the time while the state transition is happening (contracts are being executed). The PoS contract remits the transaction fees to the block proposer.

Proposer

The proposer is a selected validator by a Casper network to propose the next block. A validator becomes a proposer by proposing a block to be added to the chain and receiving the appropriate reward. The proposing process assures that new blocks will be added to the blockchain.

Proto block

The block proposed by the leader, which the consensus processes (in highway). Only after consensus is complete, the proto block is executed, and the global state is updated.

A leader is selected from the validator set of that era for each round. The chance of getting selected as a leader is in proportion to the stake one has in that era.

Purse

A purse is a unique type of URef representing a token balance. An account's main purse represents the balance of CSPR tokens (in motes) the account has access to on a Casper network. An account may have more than one purse in some instances. More information on purses can be found here.

R


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Reward

Validators receive rewards for participating in consensus and finalizing blocks. There is no precise per-block reward. Rewards are split proportionally among stakes within an era. If a validator is offline or cannot vote on many blocks, the rewards earned are also reduced. Delegators can only receive a proportional amount of the validator's rewards minus the validator's delegation rate. Rewards are distributed at the end of each era.

Root hash

The root hash, or Merkle Root, is a representation of all the data in a given hash tree. Refer to Merkle tree if you wish to learn more.

Rust

A programming language similar to C++, designed for performance and safety, especially safe concurrency.

Rustdocs

As part of the Rust development environment, the Rustdocs describe the Casper contracts library, the Casper types library, and the Casper test support library.

S


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Safe

When a protocol is provably safe, it means that all the participating nodes will make the same decision and continue to produce blocks at some interval. Also, see CBC.

Secret key

A cryptographic and confidential key that signs transactions to ensure their correct execution (carrying out only the user's intended operations).

Seigniorage

The reward mechanism by which validators are rewarded for participating in consensus. New tokens are minted and given to validators.

Session code

Session code is Wasm executed in the context of an account through sending a Deploy. The session code contains code the user wishes to execute against the blockchain. When the session code executes, it performs changes to global state.

Slashing

In Proof-of-Stake, the deposit acts as collateral. The validator guarantees that it correctly follows the protocol. If the validator node violates the protocol, the deposited amount gets slashed, i.e., a part of it is removed.

Smart contract

Smart contracts are self-executing computer programs that perform specific actions based on pre-programmed terms stored on the blockchain. Once the pre-programmed terms are met, the smart contract executes the action and eliminates the need for a centralized third party.

On a Casper network, a smart contract is a WebAssembly (Wasm) program that the network stores as a value in the global state. The execution of a smart contract causes changes to the global state.

A smart contract can be invoked by a transaction or by another smart contract. Smart contracts can declare input data as the arguments of a function. When invoking a smart contract, one must provide the input values.

Smart-contract platform

A smart contract platform provides the required blockchain environment for the creation, deployment, and execution of smart contracts.

Staker

A person that deposits tokens in the proof-of-stake contract. A staker is either a validator or a delegator. Stakers take on the slashing risk in exchange for rewards. Stakers will deposit their tokens by sending a bonding request in the form of a transaction (deployment) to the system. If a validator is slashed, the staker will lose their tokens.

Staking

A feature of Proof-of-Stake protocols that allows token holders to actively participate in the protocol, thus securing the network. The Staking Guide highlights the steps required to stake CSPR tokens on the Casper Mainnet.

State root hash

The state root hash is an identifier of the network's global state at a moment in time. The state root hash changes with each block executed, containing deploys. Normally, empty blocks do not modify global state. But, if the empty block is the last one in an era, it will also change the state root hash due to changes introduced by the auction contract calculating the validators for future eras.

Stateful

Stateful execution depends on a previous state, which makes the output differ each time. Such executions are performed with the context of previous executions and the current execution may be affected by what happened during previous executions.

Stateless

Stateless means that the execution doesn't depend on a previous state, so the output of the execution is the same each time. It does not save or reference information about previous executions. Each execution is from scratch as if for the first time.

Switch Block

A Switch Block is the final block in an era, which contains the era_summary. See also booking block.

T


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Token

A type of cryptocurrency that represents an asset. See CSPR.

Transaction

See deploy.

Turing-complete blockchain

Turing completeness refers to the ability of a machine to execute computational problems on its own by deciding or recognizing data manipulation rule sets.

For a blockchain to be Turing-complete, it means that it can understand and execute any smart contract given enough resources such as a robust code-base (necessary instructions), time, processing power, memory, etc. without human interaction or interference.

U


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Unbonding

Withdrawing money from the auction contract with withdraw bid and possibly ceasing to be a validator. The unbonding request is a transaction that informs the auction contract that the sender wants to decrease their deposit. In the next booking block, only the decreased deposit is considered when determining a future validator set. If it has been decreased to 0, the sender will not be included in the validator set anymore. However, the amount only gets transferred to the sender after the unbonding period. If during that period their node exhibits a fault, the unbonded amount can still be slashed.

URef

An Unforgeable Reference, used by a Casper network to store any value other than Account. More information can be found here.

Users

Users execute session and contract code using the platform's computational resources.

V


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Validator

Validators are responsible for maintaining platform security by building an ever-growing chain of finalized blocks, backing this chain's security with their stakes. Their importance (often referred to as "weight") both to protocol operation and security is, in fact, equal to their stake, which includes both their own and delegated tokens.

The responsibilities of a validator include:

Validators are bonded because they are responsible for progressing the system's state as clients use it (e.g., sending deploys). Validators and stakers can lose their bond (be slashed) for not following the protocol correctly. Validators are also paid for by creating blocks (also by validating blocks -- though this is only indirectly; validators cannot be paid for if they do not validate by design), giving them more incentive to serve the network correctly.

W


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


Web3

An advanced version of the internet based on decentralization and trustless interactions.

WebAssembly

WebAssembly (sometimes abbreviated Wasm) is an open standard that defines a portable binary-code format for executable programs and a corresponding textual assembly language and interfaces for facilitating interactions between such programs and their host environment. The main goal of WebAssembly is to enable high-performance applications on web pages. The format is designed to be executed and integrated into other environments, including standalone ones.

Understanding Hash Types

For the sake of user convenience and compatibility, we expect the delivery of hashes and similar data in the form of a prefixed string when using the node. The following is a list of string representations used.

Table of Associated Hash Types

TypePrefixExample
PublicKey018a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c
AccountHashaccount-hash-account-hash-ef4687f74d465826239bab05c4e1bdd2223dd8c201b96f361f775125e624ef70
ContractHashcontract-contract-0101010101010101010101010101010101010101010101010101010101010101
ContractPackageHashcontract-package-contract-package-0101010101010101010101010101010101010101010101010101010101010101
Key::Accountaccount-hash-account-hash-ef4687f74d465826239bab05c4e1bdd2223dd8c201b96f361f775125e624ef70
Key::Hashhash-hash-0101010101010101010101010101010101010101010101010101010101010101
Key::URefuref-uref-0101010101010101010101010101010101010101010101010101010101010101-001
Key::Transfertransfer-transfer-0101010101010101010101010101010101010101010101010101010101010101
Key::DeployInfodeploy-deploy-0101010101010101010101010101010101010101010101010101010101010101
Key::EraInfoera-era-1
Key::Balancebalance-balance-0101010101010101010101010101010101010101010101010101010101010101
Key::Bidbid-bid-ef4687f74d465826239bab05c4e1bdd2223dd8c201b96f361f775125e624ef70
Key::Withdrawwithdraw-withdraw-ef4687f74d465826239bab05c4e1bdd2223dd8c201b96f361f775125e624ef70
Key::Dictionarydictionary-dictionary-0101010101010101010101010101010101010101010101010101010101010101
Key::SystemContractRegistrysystem-contract-registry-system-contract-registry-00000000000000000000000000000000
Key::EraSummaryera-summary-era-summary-00000000000000000000000000000000

Hash and Key Explanations

PublicKey is a 32 byte asymmetric public key, preceded by a one-byte prefix that tells whether the key is ed25519 or secp256k1. There is a third type of PublicKey that refers to the system and it is a single 00.

AccountHash is a 32 byte hash of the PublicKey serving to identify user accounts.

ContractHash is the 32 byte hash of specific smart contract versions. You can use this to call specific contract versions.

ContractPackageHash is a 32 byte hash of the smart contract package. This hash directs you to the contract package. The function call_versioned_contract uses ContractPackageHash and allows you to call the latest version of the contract (by default). It also allows you to call any version stored previously to the package.

Key is a wrapper type that may contain one of several possible sets of data.

  • Key::Account contains an AccountHash.
  • Key::Hash contains a byte array with a length of 32, and as such can be used to pass any of the hashes. Please take note that the developer of the contract is responsible for implementation of any checks necessary on the receiving side.
  • Key::URef contains an URef suffixed by access rights.
  • Key::Transfer should contain the address hash for a transfer.
  • Key::DeployInfo retains the address hash of deploy information.
  • Key::EraInfo is the integer number of the associated era.
  • Key::Balance is the balance of a purse.
  • Key::Bid is used to keep track of bids for the auction contract. It is not generally used by users.
  • Key::Withdraw is used to keep track of withdraws for the auction contract. It is not generally used by users and exists in a historical context.
  • Key::Dictionary is the hash derived from a URef and a piece of arbitrary data and leads to a dictionary.
  • Key::SystemContractRegistry is a unique Key under which a mapping of the names and ContractHashes for system contracts, including Mint, Auction, HandlePayment and StandardPayment, is stored.
  • Key::EraSummary is a Key under which we store current era info.

Concepts Overview

The Casper blockchain is a Turing-complete smart-contracting platform using a Proof-of-Stake (PoS) consensus algorithm and WebAssembly (Wasm). The Casper Mainnet is permissionless, decentralized, and public. Network administrators can also create private or hybrid Casper networks as described here.

Concepts

This section of the documentation covers the core concepts underpinning the Casper blockchain. Working with Casper requires an understanding of blockchain technology, as well as some Casper-specific features. We recommend starting with the topics below if you are new to Casper.

TopicDescription
Introduction to the Casper BlockchainHigh-level details about the Casper blockchain
Introduction to dAppsDeveloping distributed applications on the Casper blockchain
Accounts and Cryptographic KeysThe Casper programming model is account-based. Learn how Casper accounts work and how they are secured
Hash TypesHashes are used throughout the Casper ecosystem for keys, addresses, packaging data, and more
Global StateLearn about the storage layer for the Casper blockchain. All accounts, contracts, and data are stored in global state
Call StacksLearn how Casper manages the calling of a contract
Deploys and the Deploy LifecycleDeploys are a concept fundamental to the Casper blockchain. Learn about deploys, what they are for, how to create and send them
Smart ContractsLearn how to develop smart contracts on Casper
DictionariesLearn about dictionaries, which are a primary construct for storing and retrieving data on the Casper platform
SerializationLearn about serializing data types and the Casper Serialization Standard
DesignThe high-level design of a Casper network
EconomicsLearn about the Casper on-chain economics
GlossaryA compendium of all the terms used in Casper, in alphabetical order

Next Steps

After learning the basic concepts underpinning the Casper protocol, you may wish to look into the following categories.

Developers

The Developers area caters to those interested in building dApps and writing smart contracts, including information about specific features or Casper APIs.

Operators

The Operators section caters to those who want to run and administrate a Casper node or network.

Users

The Users section contains tutorials for those interested in interacting with the Casper blockchain using a block explorer or a Ledger device.

Resources

Navigate to Resources to try various tutorials. If you are just getting started and looking to build your first Casper-based dApp, start with the beginner tutorials. Afterward, continue with more advanced tutorials to explore the multi-signature feature, runtime return values, and other essential features.

Introduction to dApps

What is a dApp?

DApp stands for Decentralized Application. Specifically, it refers to an application built on a blockchain network which combines smart contracts and a user interface.

A decentralized network consists of a group of interchangeable machines (nodes) that can perform as a full system or distributed database. Additional machines strengthen the overall system by adding redundancy and computational power.

A dApp is not just a client-server application where the application can do some work offline, nor is it a web application which can operate in a disconnected mode. A dApp is conceived and built using a distributed architecture where a network of nodes does the processing of smart contracts instead of a single central server.

Any dApp will need access to a decentralized network, in one form or another. In a Casper network, this means connecting to a node. The decentralized nature of the network means that node is fundamentally interchangeable for this purpose. If the connected node fails, the dApp can switch to a different node and continue operating without losing data or functionality.

Interacting with a Casper Decentralized Network

For a dApp to integrate with a Casper network, it must be able to send Deploys via the JSON-RPC. Business logic specific to the dApp can then be executed on chain via the Deploy. Sending a Deploy to a node will result in that node gossiping that Deploy to other nodes, assuming that the Deploy is valid and accepted. The Deploy will then be enqueued for execution.

A Deploy contains session code in the form of Wasm to be executed in the context of the sending account. Therefore, developers may use any programming language that can compile to Wasm when building a dApp for a Casper network. This session code may consist of Wasm to be executed once, or Wasm which will install contract code to be stored in global state. If the dApp requires periodic execution of the same Wasm, it is more efficient from both a gas and execution perspective to install the Wasm as a contract to be called later. As gas costs operate on a per-byte basis, smart contracts will incur less gas costs over time when compared against executing the same session code repeatedly. A dApp may send a Deploy simultaneously to each node it is connected to, but can only do so once per node, per Deploy.

Updating data in a Casper dApp

Sending a Deploy is the only means by which a dApp can change global state. All associated changes to global state occur after successful execution of the Deploy. In the case of a failed execution, the stack is unwound and any changes to global state as part of executing the Deploy are reverted. However, as there is a penalty payment that must be incurred, there is a change in global state through reducing the balance of the sending account. To send a Deploy, an account must hold a minimum balance greater than the network's penalty payment. This penalty payment can vary from network to network. On the public Casper Mainnet, the penalty payment is set to 2.5 CSPR.

Post-Consensus Execution in a Casper network

Unlike other blockchain networks, a Casper network performs execution after consensus. This means that observing the execution of the Deploy is sufficient proof of finality for most cases. For a stronger finality requirement, you can observe the finality signatures for the block that includes the given Deploy.

Deploy lifecycle

There is an inherent timing consideration when sending a Deploy, from the point where it is sent to when it is executed. The Deploy Lifecycle results in a delay longer than would be expected from a centralized application. The Deploy must be sent, accepted, gossiped, included in a finalized block and executed. This process varies from network to network. This delay should be taken into consideration when designing dApps for use with a Casper network, as the number of connected peers and the number of Deploys currently being sent may cause it to increase.

Authorization Keys

This topic explains the usage of authorization keys when signing a deploy and how to access them from a smart contract. Try the Working with Authorization Keys tutorial for an example.

Associated Keys vs. Authorization Keys

Let's review the difference between associated keys to an Account and authorization keys for a Deploy.

  • Associated keys are public keys that are associated with a given account. To understand associated keys and how they are linked to an account, read about associated keys and weights and try the Two-Party Multi-Signature tutorial.
  • Authorization keys are public keys used to sign a deploy and are listed in the Deploy's approvals. Authorization keys are a subset of the associated keys of the account under which the deploy is executed.
  • When a node receives a deploy, it checks that the deploy has the required authorization keys under approvals before including it in a block.
  • Different deploys executing the same smart contract can have different authorization keys.

Image showing associated keys and authorization keys

Here is a sample JSON representation of an Account's associated keys:

"associated_keys": [
{
"account_hash": "account-hash-1ab…11",
"weight": 1
},
{
"account_hash": "account-hash-2cd…22",
"weight": 1
},
{
"account_hash": "account-hash-3de…33",
"weight": 1
},
{
"account_hash": "account-hash-4fg…44",
"weight": 1
}
], ...

Here is a sample JSON representation of a Deploy's authorization keys:

"approvals": [
{
"signer": " 2cd...22",
"signature": "02df8c...f481"
},
{
"signer": "4fg...44",
"signature": "02ef21...756a"
}
]

Accessing Authorization Keys from a Smart Contract

Contract code can retrieve the set of authorization keys for a given deploy by calling the contract_api::runtime::list_authorization_keys function, which returns the set of account hashes representing the keys used to sign the deploy.

When to Use Authorization Keys

Authorization keys give developers more fine-grained control within their smart contracts. For example, developers can define a hierarchy within an account's associated keys. Then, they can use this hierarchy and the current execution's authorization keys to limit access for certain operations.

Try the Working with Authorization Keys tutorial to view an example workflow.

Serialization Standard

We provide a custom implementation to serialize data structures used by the Casper node to their byte representation. This document details how this custom serialization is implemented, allowing developers to build a library that implements the custom serialization.

In your smart contracts, you can implement serialization using cltype-any.

Account

An Account is a structure that represents a user on a Casper network. The account structure consists of the following fields:

Account Hash

A blake2b hash of the public key, representing the address of a user's account. The account hash serializes as a 32-byte buffer containing the bytes of the account hash.

Action Thresholds

The minimum weight thresholds that have to be met when executing an action of a certain type. It serializes as two consecutive u8 values as follows.

  • deployment The minimum weight threshold required to perform deployment actions as a u8 value.

  • key_management The minimum weight threshold required to perform key management actions as a u8 value.

Activation Point

The first era to which the associated protocol version applies. It serializes as a single u8 tag indicating if the era in question is genesis. If it is the genesis era, the following bytes will be a timestamp. If not, the bytes represent an era_id.

  • era_id An Era ID newtype identifying the era when the protocol version will activate.

  • timestamp A timestamp if the activation point is of the Genesis variant.

Approval

A struct containing a signature and the public key of the signer.

  • signature The approval signature, which serializes as the byte representation of the Signature. The first byte within the signature is 1 in the case of an Ed25519 signature or 2 in the case of Secp256k1.

  • signer The public key of the approvals signer. It serializes to the byte representation of the PublicKey. If the PublicKey is an Ed25519 key, then the first byte within the serialized buffer is 1 followed by the bytes of the key itself; else, in the case of Secp256k1, the first byte is 2.

AssociatedKey

A key granted limited permissions to an Account, for purposes such as multisig. It is serialized as a BTreeMap where the first 4 bytes represent a u32 value describing the number of keys and weights held within. The remainder consists of a repeating pattern of serialized named keys and then weights of the length dictated by the first four bytes.

  • account_hash The account hash of the associated key.

  • weight The weight of an associated key. The weight serializes as a u8 value.

AvailableBlockRange

An unbroken, inclusive range of blocks. It serializes as two consecutive u64 values containing the following two fields:

  • low The inclusive lower bound of the range.

  • high - The inclusive upper bound of the range.

Bid

An entry in the validator map. The structure consists of the following fields:

  • validator_public_key The validator's public key. It serializes as a PublicKey.

  • bonding_purse The purse used for bonding. It serializes as a Uref.

  • staked_amount The amount of tokens staked by a validator (not including delegators). It serializes as a U512 value.

  • delegation_rate The delegation rate of the bid. It serializes as an i32 signed 32-bit integer primitive.

  • vesting_schedule The vesting schedule for a genesis validator. None if it is a non-genesis validator. It serializes as an Option.

  • delegators The validator's delegators, indexed by their public keys. They are serialized as a BTreeMap where the first 4 bytes represent a u32 value describing the number of PublicKeys and delegators held within. The remainder consists of a repeating pattern of serialized PublicKeys and then delegators of the length dictated by the first four bytes.

  • inactive If the validator has been evicted. A boolean value that serializes as a single byte; true maps to 1, while false maps to 0.

Block

A block is the core component of the Casper linear blockchain, used in two contexts:

  1. A data structure containing a collection of transactions. Blocks form the primary structure of the blockchain.
  2. A message that is exchanged between nodes containing the data structure as explained in (1).

Each block has a globally unique ID, achieved by hashing the contents of the block.

Each block points to its parent. An exception is the first block, which has no parent.

A block is structurally defined as follows:

  • hash: A hash over the header of the block.
  • header: The header of the block that contains information about the contents of the block with additional metadata.
  • body: The block's body contains the proposer of the block and hashes of deploys and transfers contained within it.

Block hash

The block hash is a Digest over the contents of the block Header. The BlockHash serializes as the byte representation of the hash itself.

Block header

The header portion of a block, structurally, is defined as follows:

  • parent_hash: is the hash of the parent block. It serializes to the byte representation of the parent hash. The serialized buffer of the parent_hash is 32 bytes long.
  • state_root_hash: is the global state root hash produced by executing this block's body. It serializes to the byte representation of the state root hash. The serialized buffer of the state_root_hash is 32 bytes long.
  • body_hash: the hash of the block body. It serializes to the byte representation of the body hash. The serialized buffer of the body_hash is 32 bytes long.
  • random_bit: is a boolean needed for initializing a future era. It is serialized as a single byte; true maps to 1, while false maps to 0.
  • accumulated_seed: A seed needed for initializing a future era. It serializes to the byte representation of the parent Hash. The serialized buffer of the accumulated_hash is 32 bytes long.
  • era_end: contains equivocation and reward information to be included in the terminal finalized block. It is an optional field. Thus if the field is set as None, it serializes to 0. The serialization of the other case is described in the EraEnd.
  • timestamp: The timestamp from when the block was proposed. It serializes as a single u64 value. The serialization of a u64 value is described in the CLValues section.
  • era_id: Era ID in which this block was created. It serializes as a single u64 value.
  • height: The height of this block, i.e., the number of ancestors. It serializes as a single u64 value.
  • protocol_version: The version of the Casper network when this block was proposed. It is 3-element tuple containing u32 values. It serializes as a buffer containing the three u32 serialized values. Refer to the CLValues section on how u32 values are serialized.

EraEnd

EraEnd as represented within the block header, is a struct containing two fields.

  • era_report: The first field is termed as EraReport and contains information about equivocators and rewards for an era.
  • next_era_validator_weights: The second field is map for the validators and their weights for the era to follow.

EraReport itself contains two fields:

  • equivocators: A vector of PublicKey.
  • rewards: A Binary Tree Map of PublicKey and u64.

When serializing an EraReport, the buffer is first filled with the individual serialization of the PublicKey contained within the vector.

  • If the PublicKey is an Ed25519 key, the first byte within the buffer is a 1 followed by the individual bytes of the serialized key.
  • If the PublicKey is an Secp256k1 key, the first byte within the buffer is a 2 followed by the individual bytes of the serialized key.

When serializing the overarching struct of EraEnd, we first allocate a buffer, which contains the serialized representation of the EraReport as described above, followed by the serialized BTreeMap.

Note that EraEnd is an optional field. Thus the above scheme only applies if there is an EraEnd; if there is no era end, the field simply serializes to 0.

Body

The body portion of the block is structurally defined as:

  • proposer: The PublicKey which proposed this block.
  • deploy_hashes: Is a vector of hex-encoded hashes identifying Deploys included in this block.
  • transfer_hashes: Is a vector of hex-encoded hashes identifying Transfers included in this block.

When we serialize the BlockBody, we create a buffer that contains the serialized representations of the individual fields present within the block.

  • proposer: serializes to the byte representation of the PublicKey. If the PublicKey is an Ed25519 key, then the first byte within the serialized buffer is 1 followed by the bytes of the key itself; else, in the case of Secp256k1, the first byte is 2.
  • deploy_hashes: serializes to the byte representation of all the deploy_hashes within the block header. Its length is 32 * n, where n denotes the number of deploy hashes present within the body.
  • transfer_hashes: serializes to the byte representation of all the deploy_hashes within the block header. Its length is 32 * n, where n denotes the number of transfers present within the body.

BlockIdentifier

Identifier for possible ways to retrieve a Block. It can consist of any of the following in most situations:

  • hash Identify and retrieve a Block with its hash. The BlockHash serializes as the byte representation of the hash itself.

  • height Identify and retrieve the Block with its height. Height serializes as a single u64 value.

  • state_root_hash Identify and retrieve the Block with its state root hash. It serializes to the byte representation of the state root hash. The serialized buffer of the state_root_hash is 32 bytes long.

ChainspecRegistry

ChainspecRegistry is a unique key variant which contains a mapping of file names to the hash of the file itself. This map includes Chainspec.toml and may include Accounts.toml and GlobalState.toml. It is serialized as a BTreeMap where the first 4 bytes represent a u32 value describing the number of names as strings and digests held within. The remainder consists of a repeating pattern of serialized strings and then digests of the length dictated by the first four bytes. Digests and their inclusion criteria are as follows:

  • chainspec_raw_hash will always be included.

  • genesis_accounts_raw_hash may be included in specific circumstances.

  • global_state_raw_hash may be included in specific circumstances.

Contract

A contract struct containing the following fields:

ContractHash

A blake2b hash of a contract. The contract hash serializes as a 32-byte buffer containing the bytes of the contract hash.

ContractPackageHash

A blake2b hash of a contract package. The contract package hash serializes as a 32-byte buffer containing the bytes of the contract package hash.

ContractVersion

The version of the contract.

  • contract_hash The contract hash of the contract.

  • contract_version The version of the contract within the protocol major version. It serializes as a u32 value.

  • protocol_version_major The major element of the protocol version this contract is compatible with. It serializes as a u32 value.

ContractWasmHash

A blake2b hash of a contract's Wasm. The contract's Wasm hash serializes as a 32-byte buffer containing the bytes of the contract's Wasm hash.

Delegator

Represents a party delegating their stake to a validator (or "delegatee"). The structure consists of the following fields:

  • delegator_public_key The public key of the delegator, serialized as a PublicKey.

  • staked_amount The amount staked by the delegator, serialized as a U512 value.

  • bonding_purse The bonding purse associated with the delegation. It serializes as a URef value.

  • validator_public_key The public key of the validator that the delegator will be delegating to, serialized as a PublicKey.

  • vesting_schedule The vesting schedule for the provided delegator bid. None if it is a non-genesis validator. It serializes as an Option.

Deploy

A deploy is a data structure containing a smart contract and the requester's signature(s). Additionally, the deploy header contains additional metadata about the deploy itself. A deploy is structurally defined as follows:

  • hash: The hash of the deploy header.
  • header: Contains metadata about the deploy. The structure of the header is detailed further in this document.
  • payment: The payment code for contained smart contract.
  • session: The stored contract itself.
  • approvals: A list of signatures:

Deploy-Hash

The deploy hash is a digest over the contents of the deploy header. The deploy hash serializes as the byte representation of the hash itself.

Deploy-Header

  • account: A supported public key variant (currently either Ed25519 or Secp256k1). An Ed25519 key is serialized as a buffer of bytes, with the leading byte being 1 for Ed25519, with remainder of the buffer containing the byte representation of the signature. Correspondingly, a Secp256k1 key is serialized as a buffer of bytes, with the leading byte being 2.
  • timestamp: A timestamp is a struct that is a unary tuple containing a u64 value. This value is a count of the milliseconds since the UNIX epoch. Thus the value 1603994401469 serializes as 0xbd3a847575010000
  • ttl: The Time to live is defined as the amount of time for which deploy is considered valid. The ttl serializes in the same manner as the timestamp.
  • gas_price: The gas is u64 value which is serialized as u64 CLValue discussed below.
  • body_hash: Body hash is a hash over the contents of the deploy body, which includes the payment, session, and approval fields. Its serialization is the byte representation of the hash itself.
  • dependencies: Dependencies is a vector of deploy hashes referencing deploys that must execute before the current deploy can be executed. It serializes as a buffer containing the individual serialization of each DeployHash within the Vector.
  • chain_name: Chain name is a human-readable string describing the name of the chain as detailed in the chainspec. It is serialized as a String CLValue described below.

Payment & Session

Payment and Session are both defined as ExecutableDeployItems. More information on ExecutableDeployItems can be found here

  • Module Bytes are serialized such that the first byte within the serialized buffer is 0 with the rest of the buffer containing the bytes present.

    • ModuleBytes { module_bytes: "[72 bytes]", args: 434705a38470ec2b008bb693426f47f330802f3bd63588ee275e943407649d3bab1898897ab0400d7fa09fe02ab7b7e8ea443d28069ca557e206916515a7e21d15e5be5eb46235f5 } will serialize to
    • 0x0048000000420481b0d5a665c8a7678398103d4333c684461a71e9ee2a13f6e859fb6cd419ed5f8876fc6c3e12dce4385acc777edf42dcf8d8d844bf6a704e5b2446750559911a4a328d649ddd48000000434705a38470ec2b008bb693426f47f330802f3bd63588ee275e943407649d3bab1898897ab0400d7fa09fe02ab7b7e8ea443d28069ca557e206916515a7e21d15e5be5eb46235f5
  • StoredContractByHash serializes such that the first byte within the serialized buffer is 1u8. This is followed by the byte representation of the remaining fields.

    • StoredContractByHash { hash: c4c411864f7b717c27839e56f6f1ebe5da3f35ec0043f437324325d65a22afa4, entry_point: "pclphXwfYmCmdITj8hnh", args: d8b59728274edd2334ea328b3292ed15eaf9134f9a00dce31a87d9050570fb0267a4002c85f3a8384d2502733b2e46f44981df85fed5e4854200bbca313e3bca8d888a84a76a1c5b1b3d236a12401a2999d3cad003c9b9d98c92ab1850 }
    • 0x01c4c411864f7b717c27839e56f6f1ebe5da3f35ec0043f437324325d65a22afa41400000070636c7068587766596d436d6449546a38686e685d000000d8b59728274edd2334ea328b3292ed15eaf9134f9a00dce31a87d9050570fb0267a4002c85f3a8384d2502733b2e46f44981df85fed5e4854200bbca313e3bca8d888a84a76a1c5b1b3d236a12401a2999d3cad003c9b9d98c92ab1850
  • StoredContractByName serializes such that the first byte within the serialized buffer is 2u8. This is followed by the individual byte representation of the remaining fields.

    • StoredContractByName { name: "U5A74bSZH8abT8HqVaK9", entry_point: "gIetSxltnRDvMhWdxTqQ", args: 07beadc3da884faa17454a }
    • 0x0214000000553541373462535a483861625438487156614b39140000006749657453786c746e5244764d685764785471510b00000007beadc3da884faa17454a
  • StoredVersionedContractByHash serializes such that the first byte within the serialized buffer is 3u8. However, the field version within the enum serializes as an Option CLValue.

    • StoredVersionedContractByHash { hash: b348fdd0d0b3f66468687df93141b5924f6bb957d5893c08b60d5a78d0b9a423, version: None, entry_point: "PsLz5c7JsqT8BK8ll0kF", args: 3d0d7f193f70740386cb78b383e2e30c4f976cf3fa834bafbda4ed9dbfeb52ce1777817e8ed8868cfac6462b7cd31028aa5a7a60066db35371a2f8 }
    • 0x03b348fdd0d0b3f66468687df93141b5924f6bb957d5893c08b60d5a78d0b9a423001400000050734c7a3563374a73715438424b386c6c306b463b0000003d0d7f193f70740386cb78b383e2e30c4f976cf3fa834bafbda4ed9dbfeb52ce1777817e8ed8868cfac6462b7cd31028aa5a7a60066db35371a2f8
  • StoredVersionedContractByName serializes such that the first byte within the serialized buffer is 4u8. The name and entry_point are serialized as a String CLValue, with the version field serializing as an Option.

    • StoredVersionedContractByName { name: "lWJWKdZUEudSakJzw1tn", version: Some(1632552656), entry_point: "S1cXRT3E1jyFlWBAIVQ8", args: 9975e6957ea6b07176c7d8471478fb28df9f02a61689ef58234b1a3cffaebf9f303e3ef60ae0d8 }
    • 0x04140000006c574a574b645a5545756453616b4a7a7731746e01d0c64e61140000005331635852543345316a79466c57424149565138270000009975e6957ea6b07176c7d8471478fb28df9f02a61689ef58234b1a3cffaebf9f303e3ef60ae0d8
  • Transfer serializes such that the first byte within the serialized buffer contains is 5u8, with the remaining bytes of the buffer containing the bytes contained within the args field of Transfer.

Approval

Approval contains two fields:

  • signer: The public key of the approvals signer. It serializes to the byte representation of the PublicKey. If the PublicKey is an Ed25519 key, then the first byte within the serialized buffer is 1 followed by the bytes of the key itself; else, in the case of Secp256k1, the first byte is 2.
  • signature: The approval signature, which serializes as the byte representation of the Signature. The first byte within the signature is 1 in the case of an Ed25519 signature or 2 in the case of Secp256k1.

DeployInfo

Information relating to a given deploy. The structure consists of the following fields:

  • deploy_hash The hash of the relevant deploy, serialized as a byte representation of the hash itself.

  • transfers Transfers performed by the deploy, serialized as a List.

  • from The account identifier of the creator of the deploy, serialized as an account_hash.

  • source The source purse used for payment of the deploy, serialized as a URef.

  • gas The gas cost of executing the deploy, serialized as a U512.

Digest

A blake2b hash digest. The digest serializes as a byte representation of the hash itself.

DisabledVersions

Disabled contract versions, containing the following:

  • contract_version The version of the contract within the protocol major version. It serializes as a u32 value.

  • protocol_version_major The major element of the protocol version this contract is compatible with. It serializes as a u32 value.

EntryPoint

A type of signature method. Order of arguments matters, since this can be referenced by index as well as name.

  • name The name of the entry point, serialized as a String.

  • args Arguments for this method. They serialize as a list of the Parameters, where each parameter represents an argument passed to the entrypoint.

  • ret The return type of the method, serialized as a Unit.

  • access An enum describing the possible access control options for a contract entry point. It serializes as a 1 for public or a 1 followed by a List of authorized users.

  • entry_point_type Identifies the type of entry point. It serializes as a 0 for Session and a 1 for Contract.

EraID

An Era ID newtype. It serializes as a single u64 value.

EraInfo

Auction metadata, intended to be recorded each era. It serializes as a List of seigniorage allocations.

ExecutionEffect

The journal of execution transforms from a single deploy.

  • operations The resulting operations, serialized as a List of operations.

  • transforms The actual transformation performed while executing a deploy.

ExecutionResult

The result of a single deploy. It serializes as a u8 tag indicating either Failure as a 0 or Success as a 1. This is followed by the appropriate structure below:

Failure

The result of a failed execution.

  • effect The effect of executing the deploy.

  • transfers A record of transfers performed while executing the deploy, serialized as a List.

  • cost The cost of executing the deploy, serializes as a U512 value.

  • error_message The error message associated with executing the deploy, serialized as a String.

Success

The result of a successful execution.

  • effect The effect of executing the deploy.

  • transfers A record of transfers performed while executing the deploy, serialized as a List.

  • cost The cost of executing the deploy, serializes as a U512 value.

Group

A (labeled) "user group". Each method of a versioned contract may be associated with one or more user groups which are allowed to call it. User groups are serialized as a String.

Groups

They are serialized as a BTreeMap where the first 4 bytes represent a u32 value describing the number of user groups and BTreeSets of URefs held within. The remainder consists of a repeating pattern of serialized user groups and BTreeSets of the length dictated by the first four bytes.

Keys

In this chapter, we describe what constitutes a "key", the permissions model for the keys, and how they are serialized.

A key in Global State is one of the following data types:

  • 32-byte account identifier (called an "account identity key")
  • 32-byte immutable contract identifier (called a "hash key")
  • 32-byte reference identifier (called an "unforgeable reference")
  • 32-byte transfer identifier
  • 32-byte deploy information identifier
  • 32-byte purse balance identifier
  • 32-byte Auction bid identifier
  • 32-byte Auction withdrawal identifier
  • 32-byte Dictionary identifier
  • 32-byte System Contract Registry
  • 32-byte Auction unbond identifier
  • 32-byte Chainspec Registry

The one exception to note here is the identifier for EraInfo, which actually serializes as a u64 value with an additional byte for the tag.

Account identity key

This key type is used specifically for accounts in the global state. All accounts in the system must be stored under an account identity key, and no other types. The 32-byte identifier which represents this key is derived from the blake2b256 hash of the public key used to create the associated account (see Accounts for more information).

Hash key

This key type is used for storing contracts immutably. Once a contract is written under a hash key, that contract can never change. The 32-byte identifier representing this key is derived from the blake2b256 hash of the deploy hash (see block-structure-head for more information) concatenated with a 4-byte sequential ID. The ID begins at zero for each deploy and increments by one each time a contract is stored. The purpose of this ID is to allow each contract stored in the same deploy to have a unique key.

Unforgeable Reference (URef)

URef broadly speaking can be used to store values and manage permissions to interact with the value stored under the URef. URef is a tuple which contains the address under which the values are stored and the Access rights to the URef. Refer to the Unforgeable Reference section for details on how URefs are managed.

Transfer Key

This key type is used specifically for transfers in the global state. All transfers in the system must be stored under a transfer key and no other type. The 32-byte identifier which represents this key is derived from the blake2b256 hash of the transfer address associated with the given transfer

DeployInfo Key

This key type is used specifically for storing information related to deploys in the global state. Information for a given deploy is stored under this key only. The 32-byte identifier which represents this key is derived from the blake2b256 hash of the deploy itself.

EraInfo Key

This key type is used specifically for storing information related to the Auction metadata for a particular era. The underlying data type stored under this is a vector of the allocation of seigniorage for that given era. The identifier for this key is a new type that wraps around the primitive u64 data type and co-relates to the era number when the auction information was stored.

This key type is used specifically for storing information related to auction bids in the global state. Information for the bids is stored under this key only. The 32-byte identifier which represents this key is derived from the blake2b256 hash of the public key used to create the associated account (see Accounts for more information).

This key type is used specifically for storing information related to auction withdraws in the global state. Information for the withdrawals is stored under this key only. The 32-byte identifier which represents this key is derived from the blake2b256 hash of the public key used to create the associated account (see Accounts for more information).

Serialization for Key

Given the different variants for the over-arching Key data-type, each of the different variants is serialized differently. This section of this chapter details how the individual variants are serialized. The leading byte of the serialized buffer acts as a tag indicating the serialized variant.

KeySerialization Tag
Account0
Hash1
URef2
Transfer3
DeployInfo4
EraInfo5
Balance6
Bid7
Withdraw8
Dictionary9
SystemContractRegistry10
Unbond11
ChainspecRegistry12
  • Account serializes as a 32 byte long buffer containing the byte representation of the underlying AccountHash
  • Hash serializes as a 32 byte long buffer containing the byte representation of the underlying Hash itself.
  • URef is a tuple that contains the address of the URef and the access rights to that URef. The serialized representation of the URef is 33 bytes long. The first 32 bytes are the byte representation of the URef address, and the last byte contains the bits corresponding to the access rights of the URef. Refer to the CLValue section of this chapter for details on how AccessRights are serialized.
  • Transfer serializes as a 32 byte long buffer containing the byte representation of the hash of the transfer.
  • DeployInfo serializes as 32 byte long buffer containing the byte representation of the Deploy hash. See the Deploy section above for how Deploy hashes are serialized.
  • EraInfo serializes a u64 primitive type containing the little-endian byte representation of u64.
  • Balance serializes as 32 byte long buffer containing the byte representation of the URef address.
  • Bid and Withdraw both contain the AccountHash as their identifier; therefore, they serialize in the same manner as the Account variant.
  • Dictionary as the 32 byte long buffer containing the byte representation of the seed URef hashed with the identifying name of the dictionary item.
  • SystemContractRegistry as a 32 byte long buffer of zeros.
  • Unbond contains the AccountHash as its identifier; therefore, it serialize in the same manner as the Account variant.
  • ChainspecRegistry as a 32 byte long buffer of ones.

Permissions

There are three types of actions that can be done on a value: read, write, add. The reason for add to be called out separately from write is to allow for commutativity checking. The available actions depend on the key type and the context. Some key types only allow controlled access by smart contracts via the contract API, and other key types refer to values produced and used by the system itself and are not accessible to smart contracts at all but can be read via off-chain queries. This is summarized in the table below:

KeyType Available Actions
AccountRead + Add (via API)
HashRead
URefRead + Write and/or Add
TransferSystem
DeploySystem
EraInfoSystem
BalanceRead (via API)
BidSystem
WithdrawSystem
DictionaryRead (via API)
SystemContractRegistryRead (via API)
UnbondSystem
ChainspecRegistryRead (via API)

Refer to URef permissions on how permissions are handled in the case of URefs.

NamedArg

Named arguments to a contract. It is serialized by the combination of a String followed by the associated CLValue.

NamedKey

A mapping of string identifiers to a Casper Key type. It is serialized as a BTreeMap where the first 4 bytes represent a u32 value describing the number of named keys and values held within. The remainder consists of a repeating pattern of serialized named keys and then values of the length dictated by the first four bytes.

  • name The name of the entry. It serializes as a string.

  • key The value of the entry, which is a Casper Key type.

The named keys portion of the account structure serializes as a mapping of a string to Casper Key values as described here.

Operation

An operation performed while executing a deploy. It contains:

  • key The formatted string of the key, serialized as a String.

  • kind OpKind, The type of operation performed. It serializes as a single byte based on the following table:

OpKindSerialization
Read0
Write1
Add2
NoOp3

Parameter

Parameter to a method, structured as a name followed by a CLType. It is serialized as a String followed by a CLType.

ProtocolVersion

A newtype indicating the Casper Platform protocol version. It is serialized as three u32 values indicating major, minor and patch versions in that order.

PublicKey

Hex-encoded cryptographic public key, including the algorithm tag prefix. Serialization can be found under PublicKey.

RuntimeArgs

Represents a collection of arguments passed to a smart contract. They serialize as a List comprised of Tuples.

SeigniorageAllocation

Information about seigniorage allocation.

If the seigniorage allocation in question is for a validator, it serializes as the validator's PublicKey followed by the U512 amount.

If it is a delegator, it serializes as the delegator's PublicKey, followed by the validator's PublicKey and finally the U512 amount.

Signature

The signature serializes the byte representation of the underlying cryptographic primitive signature. The first byte within the signature is 1 in the case of an Ed25519 signature or 2 in the case of Secp256k1.

SystemContractRegistry

SystemContractRegistry is a unique Key under which a mapping of the names and ContractHashes for system contracts. This includes Mint, Auction, HandlePayment and StandardPayment. It is serialized as a BTreeMap where the first 4 bytes represent a u32 value describing the number of names as strings and ContractHashes held within. The remainder consists of a repeating pattern of serialized strings and then ContractHashes of the length dictated by the first four bytes.

TimeDiff

A human-readable duration between two timestamps. It serializes as a single u64 value.

Timestamp

A timestamp formatted as per RFC 3339 and serialized as a single u64 value.

TransferAddr

Hex-encoded transfer address, which serializes as a byte representation of itself.

Transform

The actual transformation performed while executing a deploy. It serializes as a single u8 value indicating the type of transform performed as per the following table. The remaining bytes represent the information and serialization as listed.

Transform TypeSerializationDescription
Identity0A transform having no effect.
Write_CLValue1Writes the given CLValue to global state.
Write_Account2Write the given Account to global state.
Write_Contract_WASM3Writes a smart contract as Wasm to global state.
Write_Contract4Writes a smart contract to global state.
Write_Contract_Package5Writes a smart contract package to global state.
Write_Deploy_Info6Writes the given DeployInfo to global state.
Write_Transfer7Writes the given Transfer to global state.
Write_Era_Info8Writes the given EraInfo to global state.
Write_Bid9Writes the given Bid to global state.
Write_Withdraw10Writes the given Withdraw to global state.
Add_INT3211Adds the given i32.
Add_UINT6412Adds the given u64.
Add_UINT12813Adds the given U128.
Add_UINT25614Adds the given U256.
Add_UINT51215Adds the given U512.
Add_Keys16Adds the given collection of named keys.
Failure17A failed transformation, containing an error message.

TransformEntry

A transformation performed while executing a deploy.

UnbondingPurse

A purse used for unbonding. The structure consists of the following:

  • bonding_purse The bonding purse, serialized as a URef.

  • validator_public_key The public key of the validator, serialized as a PublicKey.

  • unbonder_public_key The public key of the unbonder, serialized as a PublicKey.

  • era_of_creation Era in which this unbonding request was created, as an EraId newtype, which serializes as a u64 value.

  • amount The unbonding amount, serialized as a U512 value.

  • new_validator The validator public key to redelegate to, serialized as an Option containing the public key.

Values

A value stored in the global state is a StoredValue. A StoredValue is one of three possible variants:

  • A CLValue
  • A contract
  • An account

We discuss CLValue and contract in more detail below. Details about accounts can be found in accounts-head.

Each StoredValue is serialized when written to the global state. The serialization format consists of a single byte tag, indicating which variant of StoredValue it is, followed by the serialization of that variant. The tag for each variant is as follows:

  • CLValue is 0
  • Account is 1
  • Contract is 2

The details of CLType serialization are in the following section. Using the serialization format for CLValue as a basis, we can succinctly write the serialization rules for contracts and accounts:

  • contracts serialize in the same way as data with CLType equal to Tuple3(List(U8), Map(String, Key), Tuple3(U32, U32, U32));
  • accounts serialize in the same way as data with CLType equal to Tuple5(ByteArray(U8, 32), Map(String, Key), URef, Map(ByteArray(U8, 32), U8), Tuple2(U8, U8)).

Note: Tuple5 is not a presently supported CLType. However, it is clear how to generalize the rules for Tuple1, Tuple2, Tuple3 to any size tuple.

CLValue

CLValue is used to describe data that is used by smart contracts. This could be as a local state variable, input argument, or return value. A CLValue consists of two parts: a CLType describing the type of the value and an array of bytes representing the data in our serialization format.

CLType is described by the following recursive data type:

enum CLType {
Bool, // boolean primitive
I32, // signed 32-bit integer primitive
I64, // signed 64-bit integer primitive
U8, // unsigned 8-bit integer primitive
U32, // unsigned 32-bit integer primitive
U64, // unsigned 64-bit integer primitive
U128, // unsigned 128-bit integer primitive
U256, // unsigned 256-bit integer primitive
U512, // unsigned 512-bit integer primitive
Unit, // singleton value without additional semantics
String, // e.g. "Hello, World!"
URef, // unforgeable reference (see above)
Key, // global state key (see above)
PublicKey // A Casper system PublicKey type
Option(CLType), // optional value of the given type
List(CLType), // list of values of the given type (e.g. Vec in rust)
ByteArray(CLType, u32), // same as `List` above, but number of elements
// is statically known (e.g. arrays in rust)
Result(CLType, CLType), // co-product of the given types;
// one variant meaning success, the other failure
Map(CLType, CLType), // key-value association where keys and values have the given types
Tuple1(CLType), // single value of the given type
Tuple2(CLType, CLType), // pair consisting of elements of the given types
Tuple3(CLType, CLType, CLType), // triple consisting of elements of the given types
Any // Indicates the type is not known
}

All data which can be assigned a (non-Any) CLType can be serialized according to the following rules (this defines the Casper serialization format):

Boolean

Boolean values serialize as a single byte; true maps to 1, while false maps to 0.

Numeric

Numeric values consisting of 64 bits or less serialize in the two's complement representation with little-endian byte order, and the appropriate number of bytes for the bit-width.

  • E.g. 7u8 serializes as 0x07

  • E.g. 7u32 serializes as 0x07000000

  • E.g. 1024u32 serializes as 0x00040000

  • Wider numeric values (i.e. U128, U256, U512) serialize as one byte given the length of the next number (in bytes), followed by the two's complement representation with little-endian byte order. The number of bytes should be chosen as small as possible to represent the given number. This is done to reduce the serialization size when small numbers are represented within a wide data type.

  • E.g. U512::from(7) serializes as 0x0107

  • E.g. U512::from(1024) serializes as 0x020004

  • E.g. U512::from("123456789101112131415") serializes as 0x0957ff1ada959f4eb106

Unit

Unit serializes to an empty byte array.

String

Strings serialize as a 32-bit integer representing the length in bytes (note: this might be different than the number of characters since special characters, such as emojis, take more than one byte), followed by the UTF-8 encoding of the characters in the string.

  • E.g. "Hello, World!" serializes as 0x0d00000048656c6c6f2c20576f726c6421

Option

Optional values serialize with a single byte tag, followed by the serialization of the value itself. The tag is equal to 0 if the value is missing, and 1 if it is present.

  • E.g. None serializes as 0x00
  • E.g. Some(10u32) serializes as 0x010a000000

List

A list of values serializes as a 32-bit integer representing the number of elements in the list (note this differs from strings where it gives the number of bytes), followed by the concatenation of each serialized element.

  • E.g. List() serializes as 0x00000000
  • E.g. List(1u32, 2u32, 3u32) serializes as 0x03000000010000000200000003000000

ByteArray

A fixed-length list of values serializes as the concatenation of the serialized elements. Unlike a variable-length list, the length is not included in the serialization because it is statically known by the type of the value.

  • E.g. [1u32, 2u32, 3u32] serializes as 0x010000000200000003000000

Result

A Result serializes as a single byte tag followed by the serialization of the contained value. The tag is equal to 1 for the success variant and 0 for the error variant.

-   E.g. `Ok(314u64)` serializes as `0x013a01000000000000`
- E.g. `Err("Uh oh")` serializes as `0x00050000005568206f68`

Tuple

Tuples serialize as the concatenation of their serialized elements. Similar to ByteArray the number of elements is not included in the serialization because it is statically known in the type.

-   E.g. `(1u32, "Hello, World!", true)` serializes as `0x010000000d00000048656c6c6f2c20576f726c642101`

Map

A Map serializes as a list of key-value tuples. There must be a well-defined ordering on the keys, and in the serialization, the pairs are listed in ascending order. This is done to ensure determinism in the serialization, as Map data structures can be unordered.

URef

URef values serialize as the concatenation of its address (which is a fixed-length list of u8) and a single byte tag representing the access rights. Access rights are converted as follows:

Access RightsSerialization
NONE0
READ1
WRITE2
READ_WRITE3
ADD4
READ_ADD5
ADD_WRITE6
READ_ADD_WRITE7
-   E.g. `uref-974019c976b5f26412ce486158d2431967af35d91387dae8cbcd43c20fce6452-007` shows a `URef` with full `READ_ADD_WRITE` rights.
danger

When passing a URef to another entity on chain, you must ensure that the AccessRights are set correctly. If the URef represents a purse, AccessRights impact who can deposit and withdraw CSPR.

If a passed URef contains ADD permissions, the entity receiving the URef will then be able to deposit CSPR into the associated purse. WRITE permissions allow for withdrawing CSPR. As of 1.4.5, passing a main purse URef as a runtime argument will cause the host to automatically remove WRITE permissions. In this event, READ and ADD permissions will remain. Regardless, all due diligence should be performed to avoid passing a URef with WRITE permissions unintentionally.

PublicKey

PublicKey serializes as a single byte tag representing the algorithm followed by 32 bytes of the PublicKey itself:

  • If the PublicKey is a System key, the single tag byte is 0. With this variant, the single byte of 0 is the entire key.
  • If the PublicKey is an Ed25519 key, the single tag byte is 1 followed by the individual bytes of the serialized key.
  • If the PublicKey is a Secp256k1 key, the single tag byte is a 2 followed by the individual bytes of the serialized key.

Key

Key values serialize as a single byte tag representing the variant, followed by the serialization of the data that variant contains. For most variants, this is simply a fixed-length 32-byte array. The exception is Key::URef, which contains a URef; so its data serializes per the description above. The tags are as follows: Key::Account serializes as 0, Key::Hash as 1, Key::URef as 2.

CLType

CLType itself also has rules for serialization. A CLType serializes as a single-byte tag, followed by the concatenation of serialized inner types, if any (e.g., lists and tuples have inner types). ByteArray is a minor exception because it also includes the length in the type. However, the length is included in the serialization (as a 32-bit integer, per the serialization rules above), following the serialization of the inner type. The tags are as follows:

CLTypeSerialization Tag
Bool0
I321
I642
U83
U324
U645
U1286
U2567
U5128
Unit9
String10
Key11
URef12
Option13
List14
ByteArray15
Result16
Map17
Tuple118
Tuple219
Tuple320
Any21
PublicKey22

CLValue

A complete CLValue, including both the data and the type, can also be serialized (to store it in the global state). This is done by concatenating: the serialization of the length (as a 32-bit integer) of the serialized data (in bytes), the serialized data itself, and the serialization of the type.

Contracts

Contracts are a special value type because they contain the on-chain logic of the applications running on a Casper network. A contract contains the following data:

  • a wasm module
  • a collection of named keys
  • a protocol version

The wasm module must contain a function named call, which takes no arguments and returns no values. This is the main entry point into the contract. Moreover, the module may import any of the functions supported by the Casper runtime.

Note: though the call function signature has no arguments and no return value, within the call function body, the get_named_arg runtime function can be used to accept arguments (by ordinal), and the ret runtime function can be used to return a single CLValue to the caller.

The named keys are used to give human-readable names to keys in the global state, which are essential to the contract. For example, the hash key of another contract it frequently calls may be stored under a meaningful name. It is also used to store the URefs, which are known to the contract (see the section on Permissions for details).

Each contract specifies the Casper protocol version that was active when the contract was written to the global state.

WithdrawPurse

A purse used for unbonding, replaced in 1.5 by UnbondingPurse. WithdrawPurses prior to 1.5 were known as UnbondingPurses and now consist of historical data.

  • bonding_purse The bonding purse, serialized as a URef.

  • validator_public_key The public key of the validator, serialized as a PublicKey.

  • unbonder_public_key The public key of the unbonder, serialized as a PublicKey.

  • era_of_creation Era in which this unbonding request was created, as an EraId newtype, which serializes as a u64 value.

  • amount The unbonding amount, serialized as a U512 value.

Smart Contracts

Smart Contracts in General

A smart contract is a self-executing program that automates the actions required in a digital agreement. Once completed, the transactions are trackable and irreversible. Smart contracts permit trusted transactions and agreements among disparate, anonymous parties without the need for a central authority, legal system, or external enforcement mechanism.

Casper Smart Contracts

Casper smart contracts can be implemented in any programming language that compiles to Wasm, which can be installed and executed on-chain using Deploys. Most documentation examples and the Casper system contracts are written in Rust. You can find a guide to writing a simple, smart contract in Rust here.

Session Code

Session code is the simplest logic one can execute on a Casper network. It is essential because it is often used to trigger contract logic stored on-chain. Entry points in a contract provide access to the contract code installed in global state. Either session code or another smart contract may call these entry points. Understand when you would use session code over contract code here.

Further Reading

A Counter on the Testnet

This tutorial installs a simple counter contract on the Casper Testnet. The contract is straightforward and simply maintains a counter variable. If you want to learn to send deploys to a local Casper Network, you can follow a similar tutorial and work with NCTL. Once you are familiar with this process, the next step would be to write more practical smart contracts.

Here is how the tutorial is structured:

Prerequisites

  1. You have completed the Getting Started tutorial to set up your development environment, including tools like cmake (version 3.1.4+), cargo, and Rust.
  2. You have installed the Casper client to send deploys to the chain.
  3. You were able to set up and fund an account on the Casper Testnet. Make note of two critical pieces of information that you will need to complete this tutorial:
    • The location of your account’s secret_key.pem file
    • Your account hash identifier
  4. You selected a node whose RPC port will be receiving the deploys coming from your account.

Video Tutorial

If you prefer a video walkthrough of this guide, you can check out this video.

A Counter on an NCTL Network

This tutorial installs a simple counter contract on a local Casper network with NCTL. The contract is straightforward and simply maintains a counter variable. If you want to learn to send deploys to the Testnet, you can follow a similar tutorial. Once you are familiar with this process, the next step would be to write more practical smart contracts.

Here is how the tutorial is structured:

Prerequisites

  1. You have completed the Getting Started tutorial to set up your development environment, including tools like cmake (version 3.1.4+), cargo, and Rust.
  2. You have completed the NCTL tutorial, which introduces you to the CLI tool to set up and control local Casper networks for development.
  3. You have installed the Casper client to send deploys to the chain.

Deploys and the Deploy Lifecycle

Deploys

A Deploy is a data structure containing Wasm and the requester's signature(s). Additionally, the deploy header contains additional metadata about the deploy itself. A deploy’s structure is as follows:

Image showing the deploy data structure

  • Body: Containing payment code and session code (more details on these below)
  • Header: containing
    • The Public Key of the account in whose context the deploy will run
    • The timestamp of the deploy’s creation
    • A time-to-live, after which the deploy expires and cannot be included in a block
    • the blake2b256 hash of the body
  • Deploy hash: the blake2b hash of the Header
  • Approvals: the set of signatures which have signed the deploy hash; these are used in the account permissions model

The Deploy Lifecycle

A deploy goes through the following phases on Casper:

  1. Deploy Received
  2. Deploy Gossiped
  3. Block Proposed
  4. Block Gossiped
  5. Consensus Reached
  6. Deploy Executed

Deploy Received

A client sending the deploy will send it to one or more nodes via their JSON RPC servers. The node will ensure that a given deploy matches configuration settings outlined in the network's chainspec. Deploy configuration for the Casper Mainnet can be found here. Once accepted, the system returns the deploy hash to the client to indicate it has been enqueued for execution. The deploy could expire while waiting to be gossiped; whenever this happens, a DeployExpired event is emitted by the event stream servers of all nodes which have the expired deploy.

Deploy Gossiped

After a node accepts a new deploy, it will gossip to all other nodes. A validator node will put the deploy into the block proposer buffer. The validator leader will pick the deploy from the block proposer buffer to create a new proposed block for the chain. This mechanism is efficient and ensures all nodes in the network eventually hold the given deploy. Each node that accepts a gossiped deploy also emits a DeployAccepted event on its event stream server. The deploy may expire while waiting for a node to add it to the block. Whenever this happens, the node emits a DeployExpired event.

Block Proposed

The validator leader for this round will propose a block that includes as many deploys from the block proposer buffer as can fit in a block.

Block Gossiped

The proposed block propagates to all other nodes.

Consensus Reached

Once the other validators reach consensus that the proposed block is valid, all deploys in the block are executed, and this block becomes the final block added to the chain. Whenever reaching consensus, the event stream server emits a BlockAdded. FinalitySignature events emit shortly after that. Finality signatures for the new block arrive from the validators.

Deploy Executed

A deploy executes in distinct phases to accommodate flexibly paying for computation. The phases of a deploy are payment, session, and finalization. Payment code executes during the payment phase. If it is successful, the session code executes during the session phase. And, independently of session code execution, the finalization phase does some bookkeeping around the payment. Once the deploy is executed, a DeployProcessed event is emitted by the event stream server.

In the event of execution failure, the sender will be charged the minimum penalty payment - 2.5 CSPR on the Casper Mainnet. This prevents malicious spamming of faulty deploys.

Payment code

Payment code determines the payment amount for the computation requested and how much the sender is willing to pay. Payment code may include arbitrary logic, providing flexibility in paying for a deploy. For example, the simplest payment code could use the account's main purse. In contrast, an enterprise application may require a multi-signature scheme that accesses a corporate purse. To ensure the payment code will pay for its own computation, only accounts with a balance in their main purse greater than or equal to MAX_PAYMENT_COST may execute deploys. Based on the current conversion rate between gas and motes, we restrict the gas limit of the payment code execution so that the process spends no more than MAX_PAYMENT_COST motes (a constant of the system.) If the payment is absent or not enough, then payment execution is not successful. In this case, the effects of the payment code on global state are reverted, and the system covers the cost of the computation with motes taken from the offending account's main purse.

Session code

Session code provides the main logic for the deploy. It only executes if the payment code is successful. The gas limit for this computation is determined based on the amount of payment given (after subtracting the cost of the payment code itself).

Specifying payment code and session code

The user-defined logic of a deploy can be specified in a number of ways:

  • a Wasm module in binary format representing valid session code, including logic to be executed in the context of an account or to store Wasm in the form of a contract to be executed later. (Note that the named keys from the context of the account the deploy is running in.)
  • a 32-byte identifier representing the hash where a contract is already stored in the global state
  • a name corresponding to a named key in the account, where a contract is stored under the key

Payment and session code can be independently specified, so different methods of specifying them may be used (e.g. payment could be specified by a hash key, while the session is explicitly provided as a Wasm module).

Summary

The following diagram summarizes the deploy lifecycle.

Image showing the deploy lifecycle

Calling Smart Contracts with the Rust Client

Smart contracts exist as stored on-chain logic, allowing disparate users to call the included entry points. This tutorial covers different ways to call Casper contracts with the Casper command-line client and the put-deploy command. Each section below includes a short video demonstrating some example output.

The following examples use two contracts on Testnet:

Prerequisites

Calling Contracts by Contract Hash

After installing a contract in global state, you can use the contract's hash to call one of its entry points. The following usage of put-deploy allows you to call an entry point and receive a deploy hash. The hash is needed to verify that the deploy was processed successfully.

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name [CHAIN_NAME] \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-hash [HEX_STRING] \
--session-entry-point [ENTRY_POINT_FUNCTION]

The arguments used above are:

  • node-address - An IP address of a peer on the network. The default port for JSON-RPC servers on Mainnet and Testnet is 7777
  • chain-name - The chain name of the network where you wish to send the deploy. For Mainnet, use casper. For Testnet, use casper-test
  • secret-key - The file name containing the secret key of the account paying for the deploy
  • payment-amount - The payment for the deploy in motes
  • session-hash - Hex-encoded hash of the stored contract to be called as the session
  • session-entry-point - Name of the method that will be used when calling the session contract

Example - Calling the Counter contract by hash:

In this example, the --session-hash option identifies a stored contract with an entry-point called "counter-inc".

casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--chain-name casper-test \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount 100000000 \
--session-hash hash-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e \
--session-entry-point "counter-inc"

This put-deploy command is nearly identical to the command used to install the contract. Here, instead of session-path pointing to the Wasm binary, we have session-hash and session-entry-point identifying the on-chain contract and its associated entry point. No Wasm file is needed in this example since the contract is already on the blockchain, and the entry point doesn’t return a value. If an entry point returns a value, use code to interact with runtime return values.

tip

The payment amount varies based on each deploy and network chainspec.

The following sample response contains a deploy_hash, needed to verify the changes in global state, as described here.

Sample response
{
"id": 1197172763279676268,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"deploy_hash": "24b58fbc0cbbfa3be978e7b78b9b37fc1d17c887b1abed2b2e2e704f7ee5427c"
}
}

Video - Calling a contract by hash:

This video shows how to query a previously installed Counter contract by hash.

Calling Contracts with Session Arguments

When calling contract entry points, you may need to pass in information using session arguments. The put-deploy command allows you to do this with the --session-arg option:

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name [CHAIN_NAME] \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-hash [HEX_STRING] \
--session-entry-point [ENTRY_POINT_FUNCTION] \
--session-arg ["NAME:TYPE='VALUE'" OR "NAME:TYPE=null"]...

The arguments of interest are:

  • session-hash - Hex-encoded hash of the stored contract to be called as the session
  • session-entry-point - Name of the method that will be used when calling the session contract
  • session-arg - For simple CLTypes, a named and typed arg is passed to the Wasm code. To see an example for each type, run: 'casper-client put-deploy --show-arg-examples'

Example - Calling the Auction contract using session arguments:

This example demonstrates how to call the Auction contract's entry point delegate with three arguments:

  • The argument validator is the public key of the validator to whom the tokens will be delegated
  • The argument amount is the number of tokens to be delegated
  • The argument delegator is the public key of the account delegating tokens to a validator

To make the call, we use the contract hash, hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2, and the --session-hash option.

casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--chain-name casper-test \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount 2500000000 \
--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \
--session-entry-point "delegate" \
--session-arg "validator:public_key='0145fb72c75e1b459839555d70356a5e6172e706efa204d86c86050e2f7878960f'" \
--session-arg "amount:u512='500000000000'" \
--session-arg "delegator:public_key='0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf'"

Video - Calling a contract with session arguments:

This video shows how to call a modified Counter contract using session arguments.

Calling Contracts by Package Hash

You can also call an entry point in a contract that is part of a contract package (see contract upgrades). Call put-deploy using the stored package hash, the entry point you wish to access, the contract version number, and any runtime arguments. The call defaults to the highest enabled version if no version was specified.

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name [CHAIN_NAME] \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-package-hash [HEX_STRING] \
--session-entry-point [ENTRY_POINT_FUNCTION] \
--session-version [INTEGER]

The arguments of interest are:

  • session-package-hash - Hex-encoded hash of the stored package to be called as the session
  • session-entry-point - Name of the method that will be used when calling the session contract
  • session-version - Version of the called session contract. The latest will be used by default

Example 1 - Calling the Counter using the package hash and version:

In this example, we call the Counter contract by its package hash and version number. The entry point invoked is "counter-inc".

casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--chain-name casper-test \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount 100000000 \
--session-package-hash hash-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e \
--session-entry-point "counter-inc" \
--session-version 1

To find the contract package hash, look at the account's named keys associated with the contract. Here is an example:

{
"key": "hash-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e",
"name": "counter_package_name"
}

Example 2 - Calling the Auction using the package hash and version:

This example demonstrates how to call the Auction contract's delegate entry point by specifying the package hash using the --session-package-hash option. The call defaults to the highest enabled version since no version was specified with the --session-version option.

casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--chain-name casper-test \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount 2500000000 \
--session-package-hash hash-e375d42c29c0e4b2baefa63cf2d70af34439eda851e08129d8515515d63bd6a9 \
--session-entry-point "delegate" \
--session-arg "validator:public_key='0145fb72c75e1b459839555d70356a5e6172e706efa204d86c86050e2f7878960f'" \
--session-arg "amount:u512='500000000000'" \
--session-arg "delegator:public_key='0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf'"

Video - Calling a contract using the package hash:

The video shows how to query the previously installed Counter contract package.

Calling Contracts by Contract Name

We can also reference a contract using a key as the contract name. When you write the contract, use the put_key function to add the ContractHash under the contract's NamedKeys.

Having a key enables you to call a contract's entry-point in global state by using the put-deploy command as illustrated here:

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name [CHAIN_NAME] \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-name [NAMED_KEY_FOR_SMART_CONTRACT] \
--session-entry-point [ENTRY_POINT_FUNCTION]

The arguments of interest are:

  • session-name - Name of the stored contract (associated with the executing account) to be called as the session
  • session-entry-point - Name of the method that will be used when calling the session contract

Example 1 - Calling the Counter contract using a named key:

This example uses the Counter contract stored in global state under the "counter" named key. The code stores the ContractHash into a URef, which can be referenced once the contract is installed in global state. The full implementation is available on GitHub.

runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());

The following command invokes the entry point "counter_inc" and the contract stored under the "counter" named key.

casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--chain-name casper-test \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount 100000000 \
--session-name "counter" \
--session-entry-point "counter_inc"

The sample response will contain a deploy_hash, which you need to use as described here to verify the changes in global state.

Example 2 - Calling the Auction contract using a named key:

This example uses the system Auction contract stored in global state under the "auction" key and its delegate entry point.

casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--chain-name casper-test \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount 2500000000 \
--session-name "auction" \
--session-entry-point "delegate" \
--session-arg "validator:public_key='0145fb72c75e1b459839555d70356a5e6172e706efa204d86c86050e2f7878960f'" \
--session-arg "amount:u512='500000000000'" \
--session-arg "delegator:public_key='0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf'"

Video - Calling a contract using a named key:

This short video shows how to query the previously installed Counter contract using a named key, which is the name used to reference the contract.

Calling Contracts by Package Name

To call an entry point in a contract by referencing the contract package name, you can use the session-package-name, session-entry-point, and session-version arguments. This will enable you to access the entry point in global state by using the put-deploy command as illustrated here:

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name [CHAIN_NAME] \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-package-name [NAMED_KEY_FOR_PACKAGE] \
--session-entry-point [ENTRY_POINT_FUNCTION] \
--session-version [INTEGER]

The arguments of interest are:

  • session-package-name - Name of the stored package to be called as the session
  • session-entry-point - Name of the method that will be used when calling the session contract
  • session-version - Version of the called session contract. The latest will be used by default

Example 1 - Specifying the package name and version number:

This example calls the entry point "counter-inc" as part of the contract package name "counter_package_name", version 1, without any runtime arguments.

You should have previously created the contract by using new_contract, and provided the contract package name as the hash_name argument of new_contract.

This example code stores the "contract_package_name" into a NamedKey, which you can reference once you install the contract in global state.

    let (stored_contract_hash, contract_version) =
storage::new_contract(counter_entry_points,
Some(counter_named_keys),
Some("counter_package_name".to_string()),
Some("counter_access_uref".to_string())
);

Here is the command to call the contract using the package name:

casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--chain-name casper-test \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount 100000000 \
--session-package-name "counter_package_name" \
--session-entry-point "counter-inc" \
--session-version 1

Example 2 - Calling the package without specifying the version:

This example demonstrates how to call a contract that is part of the erc20_test_call package using runtime arguments. The call invokes the "check_balance_of" entry point and defaults to the highest enabled version since no version was specified.

    casper-client put-deploy \
--node-address http://3.143.158.19:7777 \
--chain-name integration-test \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--payment-amount 1000000000 \
--session-package-name "erc20_test_call" \
--session-entry-point "check_balance_of" \
--session-arg "token_contract:account_hash='account-hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180'" \
--session-arg "address:key='account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd'"

Video - Calling a contract using the package name:

This video demonstrates how to call versioned contracts by package name.

Calling a Contract using Wasm

Session code or contract code (compiled to Wasm) can act on a contract and change its state. The put-deploy command supports this mechanism as well:

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name [CHAIN_NAME] \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path [PATH]/[FILE_NAME].wasm

The argument of interest is:

  • session-path - The path to the compiled Wasm on your computer

Example - Session code acting on a contract:

The Counter Contract Tutorial shows how to change the state of a contract (counter-v1.wasm) using session code (counter-call.wasm).


casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--chain-name casper-test \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount 25000000000 \
--session-path [PATH_TO_YOUR_COMPILED_WASM]/counter-call.wasm

Video - Calling a contract using Wasm:

Calling Contracts that Return a Value

Visit the Interacting with Runtime Return Values tutorial to learn how to call a contract that returns a value using session code or contract code.

What's Next?

Delegating with the Casper Client

This document details a workflow where an account holder on a Casper network can delegate tokens to a validator.

Prerequisites

  1. You meet all prerequisites listed here, including having a valid node-address and the Casper command-line client
  2. You have previously installed a smart contract to a Casper network
  3. Acquiring a Validator's Public Key

Acquiring a Validator's Public Key

This workflow will take you through the additional prerequisite to acquire a validator's public key before sending the delegation request.

Any rewards earned are also redelegated by default to the validator from the initial delegation request. Therefore at the time of undelegation, you should consider undelegating the initial amount plus any additional rewards earned through the delegation process.

The active validator set constantly rotates; therefore, when delegating to a validator, remember that the validator you selected may have been rotated out of the set.

Sending the Delegation Request

There are two ways to delegate CSPR to a validator. The recommended and cheaper method is to call the delegate entry point from the system auction contract. The second method involves building the delegate.wasm from the casper-node repository and installing it on the network.

We recommend testing the following steps on the official Testnet before performing them in a live environment like the Casper Mainnet.

note

The minimum amount to delegate is 500 CSPR (500,000,000,000 motes).

Method 1: Delegating with the System Auction Contract

This method calls the existing delegate entry point from the system auction contract. Using this method, you do not need to build any contracts, reducing costs and complexity.

casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT_IN_MOTES> \
--session-hash <SESSION_HASH> \
--session-entry-point delegate \
--session-arg "validator:public_key='<HEX_ENCODED_VALIDATOR_PULIC_KEY>'" \
--session-arg "amount:u512='<AMOUNT_TO_DELEGATE>'" \
--session-arg "delegator:public_key='<HEX_ENCODED_DELEGATOR_PULIC_KEY>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version 1.5.1
  5. session-hash - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:
  • Testnet: hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2
  • Mainnet: hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea
  1. session-entry-point - Name of the entry point that will be used when calling the contract

The delegate entry point expects three arguments:

  1. validator: The hexadecimal public key of the validator receiving the delegated tokens
  2. amount: The number of tokens to be delegated
  3. delegator: The hexadecimal public key of the account delegating tokens to a validator. This key must match the secret key that signs the delegation

The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the Deploy Status section for more details.

note

Calling the delegate entry point on the auction contract has a fixed cost of 2.5 CSPR.

Example:

This example shows an account delegating 500 CSPR:

casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--chain-name casper-test \
--secret-key ~/KEYS/secret_key.pem \
--payment-amount 2500000000 \
--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \
--session-entry-point delegate \
--session-arg "validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'" \
--session-arg "amount:u512='500000000000'" \
--session-arg "delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'"

Next, confirm the delegation.

Method 2: Delegating with Compiled Wasm

Another way to send a delegation is to compile the delegate.wasm and send it to the network via a deploy. Here are the steps to compile the contract yourself.

Building the delegation Wasm

Obtain the delegate.wasm by cloning the casper-node repository.

git clone https://github.com/casper-network/casper-node

Prepare the Rust environment and then build the contracts using the Makefile provided in the repository.

cd casper-node
make setup-rs
make build-contracts-rs

Once you build the contracts, you can use the delegate.wasm to create a deploy that will initiate the delegation process. The Wasm can be found in this directory: target/wasm32-unknown-unknown/release/.

ls target/wasm32-unknown-unknown/release/delegate.wasm

Sending the delegation request

In this example, we use the Casper client to send a deploy containing the delegate.wasm to the network to initiate the delegation process.

casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT_IN_MOTES> \
--session-path <PATH_TO_WASM>/delegate.wasm \
--session-arg "validator:public_key='<HEX_ENCODED_VALIDATOR_PULIC_KEY>'" \
--session-arg "amount:u512='<AMOUNT_TO_DELEGATE>'" \
--session-arg "delegator:public_key='<HEX_ENCODED_DELEGATOR_PULIC_KEY>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version 1.5.1
  5. session-path - The path to where the delegate.wasm is located

The delegate entry point expects three arguments:

  1. validator: The hexadecimal public key of the validator receiving the delegated tokens
  2. amount: The number of tokens to be delegated
  3. delegator: The hexadecimal public key of the account delegating tokens to a validator. This key must match the secret key that signs the delegation

The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the Deploy Status section for more details.

Example:

This example command uses the Casper Testnet to delegate 500 CSPR, and the payment amount is 6 CSPR. The payment amount varies based on each deploy and network chainspec. However, notice that this method is more expensive than the previous one that calls the delegate entry point.

casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--chain-name casper-test \
--secret-key ~/KEYS/secret_key.pem \
--payment-amount 20000000000 \
--session-path ~/delegate.wasm \
--session-arg "validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'" \
--session-arg "amount:u512='500000000000'" \
--session-arg "delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'"

Next, confirm the delegation.

Confirming the Delegation

A Casper network maintains an auction where validators bid on slots to become part of the active validator set. Delegation rewards are only earned for a validator who has won the auction and is part of the active set. Thus to ensure the delegated tokens can earn rewards, you must first check the foloowing:

  1. Your delegation is part of the bid to the auction
  2. The validator is part of the active validator set

Once the deploy has been processed, you can query the auction for information to confirm our delegation. Use the Casper command-line client to create an RPC request with the following query:

casper-client get-auction-info \
--node-address http://<peer-ip-address>:7777

Request fields:

  • node-address - An IP address of a node on the network

The get-auction-info call will return all the bids currently in the auction contract and the list of active validators for 4 future eras from the present era.

Below is a sample of the bids structure:

"bids": [
{
"bid": {
"bonding_purse": "uref-a5ce7dbc5f7e02ef52048e64b2ff4693a472a1a56fe71e83b180cd33271b2ed9-007",
"delegation_rate": 1,
"delegators": [
{
"bonding_purse": "uref-ca9247ad56a4d5be70484303133e2d6db97f7d7385772155763749af98ace0b0-007",
"delegatee": "0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd",
"public_key": "010c7fef89bf1fc38363bd2ec20bbfb5e1152d6a9579c8847615c59c7e461ece89",
"staked_amount": "1"
},
{
"bonding_purse": "uref-38a2e9cad51b380e478c9a325578f4bbdaa0337b99b9ab9bf1dc2a114eb948b9-007",
"delegatee": "0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd",
"public_key": "016ebb38d613f2550e7c21ff9d99f6249b4ae5fb9e30938f6ece2d84a22a36b035",
"staked_amount": "478473232415318176495746923"
}
],
"inactive": false,
"staked_amount": "493754513995516852173468935"
},
"public_key": "0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd"
},

The delegation request has been processed successfully if your public key and associated amount appear in the bid data structure. However, this does not mean the associated validator is part of the validator set, so you must check the validator status recorded in the era_validators structure.

Checking Validator Status

The auction maintains a field called era_validators, which contains the validator information for 4 future eras from the current era. An entry for a specific era lists the PublicKeys of the active validators for that era, along with their stake in the network.

If a validator is part of the set, its public key will be in the era_validators field as part of the Auction data structure returned by casper-client get-auction-info.

In the response, check the "auction_state"."era_validators" structure, which should contain the public key of the selected validator for the era in which the validator will be active.

Below is an example of the era_validators structure:

"block_height":105,
"era_validators":[
{
"era_id":9,
"validator_weights":[
{
"public_key":"0102db4e11bccb3f9d823c82b9389625d383867d00d09b343043cdbe5ca56dd1fd",
"weight":"648151805935226166098427654"
},
{
"public_key":"01aa67009b37a23c7ad0ca632da5da239d5db46067d4b34125f61b04611f610baf",
"weight":"648151805938466925128109996"
},
{
"public_key":"01b7afa2beeddffd13458b763d7a00259f7dc0fa45498dfed05b4d7df4b7d65e2c",
"weight":"648151805935226166098427656"
},
{
"public_key":"01ca5463dac047cbd750d97ee42dd810cf1e081ece7d83ae4fc03b25a9ecad3b6a",
"weight":"648151805938466925128109998"
},
{
"public_key":"01f4a7644695aa129eba09fb3f11d0277b2bea1a3d5bc1933bcda93fdb4ad17e55",
"weight":"648151805938466925128110000"
}
]
},

In the above example, we see the public keys of the active validators in Era 9.

Note: Validators earn delegation rewards only when they are part of the active set. This information is time-sensitive; therefore, a validator selected today may not be part of the set tomorrow. Keep this in mind when creating a delegation request.

If your account is on the official Testnet or Mainnet, you can use the block explorer to look up your account balance and see that the tokens have been delegated:

  1. Testnet explorer
  2. Mainnet explorer

Execution Error Codes

This section covers smart contract execution error codes.

As mentioned in Writing Rust Contracts, smart contracts can exit with an error code defined by an ApiError. Descriptions of each variant are found here and include the following sub-types:

An ApiError of one of these sub-types maps to an exit code with an offset defined by the sub-type. For example, an ApiError::User(2) maps to an exit code of 65538 (i.e. 65536 + 2). You can find a mapping from contract exit codes to ApiError variants here.

Using the Casper CLI Client

This section explains how to interact with a Casper network using the Casper command-line client written in Rust.

TopicDescription
Transferring TokensTransferring tokens from one account to another using the Casper command-line client
Delegating tokensDelegating tokens to a validator on a Casper network
Undelegating Tokens with the Casper ClientUndelegating tokens from a validator on a Casper network
Sending Deploys to a NetworkSending Deploys to a Casper network using the Rust CLI Client
Installing Smart ContractsSteps to install a contract on a Casper network
Querying Global StateHow to query global state after contract installation
Calling Smart Contracts with the Rust ClientVarious ways to call a contract's entry-points
Execution Error CodesError codes for smart contract execution

Installing Smart Contracts

This document details the process of installing Casper smart contracts using the Casper command-line client and the put-deploy command.

Prerequisites

  • You have a compiled contract (.wasm file) to send to a Casper network
  • You have installed the Casper CLI client to interact with the network
  • You have a Casper Account with a public and secret key pair to initiate the deploy
  • You have enough CSPR tokens in your account's main purse to pay for deploys. If you plan to use the Casper Testnet, learn about the faucet to fund your testing account's main purse

Installing a Contract in Global State

To install a contract in global state, you need to send a deploy to the network with the contract Wasm. You can do so by using the put-deploy command.

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name [CHAIN_NAME] \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path [CONTRACT_PATH]/[CONTRACT_NAME].wasm

The arguments used above are:

  • node-address - An IP address of a peer on the network. The default port for JSON-RPC servers on Mainnet and Testnet is 7777
  • chain-name - The chain name to the network where you wish to send the deploy. For Mainnet, use casper. For Testnet, use casper-test
  • secret-key - The file name containing the secret key of the account paying for the deploy
  • payment-amount - The payment for the deploy in motes
  • session-path - The path to the contract Wasm, which should point to wherever you compiled the contract (.wasm file) on your computer

Once you call this command, it will return a deploy hash. You can use this hash to verify successful execution of the deploy.

Example - Install the contract:

Here we send a counter-v1.wasm to a local NCTL network.

casper-client put-deploy \
--node-address http://localhost:11101 \
--chain-name casper-net-1 \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount 5000000000000 \
--session-path ./counter/target/wasm32-unknown-unknown/release/counter-v1.wasm
tip

The payment amount varies based on each contract and network chainspec.

To verify the deploy, call get-deploy and provide the deploy hash you received from put-deploy.

casper-client get-deploy \
--node-address http://localhost:11101 [DEPLOY_HASH]

Video - Contract Installation Walkthrough

This video demonstrates the commands described above for installing a contract on-chain.

Querying Global State

Here we look at how to query global state to see details about a successfully installed contract.

Get the state root hash

The first step in querying the global state is obtaining the state root hash. The state root hash acts as an identifier for the current state of the network (global state). It is like a Git commit ID for commit history, and it provides a snapshot of the blockchain state at a specific point in time.

note

After sending deploys to the network, it's necessary to fetch the new state root hash in order to see the changes reflected in the global state. Without doing this, you would be querying past versions of the state.

To get the state root hash, use the get-state-root-hash command:

casper-client get-state-root-hash --node-address [NODE_SERVER_ADDRESS]

Query global state

Next, query the state of a Casper network at a given time, specified by the state-root-hash described above. You can dive into the data stored in global state using the optional query path argument -q.

casper-client query-global-state \
--node-address [NODE_SERVER_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [HASH_STRING] \
-q "[SESSION_NAME]/[SESSION_NAMED_KEY]"

The arguments used above are:

  • node-address - An IP address of a peer on the network. The default port for JSON-RPC servers on Mainnet and Testnet is 7777
  • state-root-hash - Hex-encoded hash of the state root
  • key - The identifier for the query. This must be one of the following: public key, account hash, contract package hash, transfer hash, or deploy hash
  • q - An optional query path argument that allows you to drill into the specifics of a query with respect to the key

Example - Query the account:

To find your account details, query global state using your account hash.

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash fa968344a2000282686303f1664c474465f9a028f32ec4f51791d9fa64c0bcd7 \
--key account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d

Here is how your account state would look. Notice that the sample response contains several named keys, including "counter", "counter_package_name", and "version". You can use these values to query the contract state further, as shown in the next example.

Sample account state
{
"id": -6831525034388467034,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[27614 hex chars]",
"stored_value": {
"Account": {
"account_hash": "account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_hash": "account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d",
"weight": 1
}
],
"main_purse": "uref-d92e420120199f90005802bf3036362f368ab69bebf17e7e53856d6ac82e117f-007",
"named_keys": [
{
"key": "hash-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e",
"name": "counter"
},
{
"key": "uref-41c3f4ae3c1ce2446f6fd880a96e698ae5abc715151e45e357d88bb739489c03-007",
"name": "counter_access_uref"
},
{
"key": "hash-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e",
"name": "counter_package_name"
},
{
"key": "uref-917762490591a1404cba59ed8dcf0bcfa7f644ef6c6be9bf5ea7b1641617cad0-007",
"name": "version"
}
]
}
}
}
}

tip

If you don't know your account hash, you can run this command:

casper-client account-address --public-key [PATH_TO_PUBLIC_KEY]

Example - Query the contract:

This example shows how to query global state given a contract hash. We use the contract hash from the sample response above.

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash fa968344a2000282686303f1664c474465f9a028f32ec4f51791d9fa64c0bcd7 \
--key hash-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e

Here is how the sample contract would look and would contain details such as the contract_package_hash, the contract entry_points, and the named_keys for the contract.

Sample contract state
{
"id": -4657473054587773855,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[21330 hex chars]",
"stored_value": {
"Contract": {
"contract_package_hash": "contract-package-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e",
"contract_wasm_hash": "contract-wasm-576b1718711d524a79ab2f05ce801006a3fd32eb48b9f7dac69a9fa966d634e3",
"entry_points": [
{
"access": "Public",
"args": [],
"entry_point_type": "Contract",
"name": "counter_get",
"ret": "I32"
},
{
"access": "Public",
"args": [],
"entry_point_type": "Contract",
"name": "counter_inc",
"ret": "Unit"
}
],
"named_keys": [
{
"key": "uref-d40613e50c7b405b02795e3fe3252554bef49b4b522e31a55f39b87c442f922a-007",
"name": "count"
}
],
"protocol_version": "1.4.5"
}
}
}
}


Example - Query a value using its key and the contract hash:

Next, you can query a named key associated with the contract using the -q option. This example comes from the Counter Contract Tutorial, where a "count" variable is incremented and stored under a named key.

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH] \
--key [CONTRACT_HASH] \
-q "count"
Sample stored value
{
"id": -2540117660598287261,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[56562 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "00000000",
"cl_type": "I32",
"parsed": 0
}
}
}
}

Example - Query a value using the account hash and named keys:

It is also possible to check the state of a specific contract variable in global state given the account hash under which the contract was installed. Here we query the named key "count", stored under another key identifying the contract and named "counter".

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash fa968344a2000282686303f1664c474465f9a028f32ec4f51791d9fa64c0bcd7 \
--key account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d \
-q "counter/count"

The response should be the same as in Example 3, above.

Example - Query contract package state:

You can query information about a contract package, such as the latest contract hash and contract version, given its contract package hash.

casper-client query-global-state \
--node-address http://localhost:11101 \
--key hash-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e \
--state-root-hash 763e737cf55a298d54bcdfb4ee55526538a1a086128914b9cc25ccbdebbbb966

Here is how the contract package details would look. The response would contain the contract_hash, which you would need to call a contract by hash in the next section. You would also see the access_key for the ContractPackage and the current contract_version.

Sample contract package state
{
"id": -6225901853092301031,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[20964 hex chars]",
"stored_value": {
"ContractPackage": {
"access_key": "uref-41c3f4ae3c1ce2446f6fd880a96e698ae5abc715151e45e357d88bb739489c03-007",
"disabled_versions": [],
"groups": [],
"versions": [
{
"contract_hash": "contract-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e",
"contract_version": 1,
"protocol_version_major": 1
}
]
}
}
}
}

Video - Querying Walkthrough

This video shows you what to expect when querying the network.

What's Next?

OpCode Costs Tables

The following tables outline the cost, in motes, for a given operation on Casper's Mainnet. If you are building for a private network or other instance of Casper, you will need to verify these costs in the associated chainspec.toml.

More information on chainspecs for private networks can be found here

note

All costs in this table are in motes, not CSPR, and the corresponding chainspec is here.

Storage Costs

AttributeDescriptionCost
gas_per_byteGas charged per byte stored in global state.630,000

OpCode Costs

AttributeDescriptionCost
bitBit operations multiplier.300
addArithmetic add operations multiplier.210
mulMul operations multiplier.240
divDiv operations multiplier.320
loadMemory load operation multiplier.2_500
storeMemory store operation multiplier.4,700
constConst store operation multiplier.110
localLocal operations multiplier.390
globalGlobal operations multiplier.390
integer_comparisonInteger operations multiplier.250
conversionConversion operations multiplier.420
unreachableUnreachable operation multiplier.270
nopNop operation multiplier.200
current_memoryGet the current memory operation multiplier.290
grow_memoryGrow memory cost per page (64 kB).240,000

Control Flow Operation Costs

AttributeDescriptionCost
blockCost for block opcode.440
loopCost for loop opcode.440
ifCost for if opcode.440
elseCost for else opcode.440
endCost for end opcode.440
brCost for br opcode.35_000
br_ifCost for br_if opcode.35,000
returnCost for return opcode.440
selectCost for select opcode.440
callCost for call opcode.68_000
call_indirectCost for call_indirect opcode.68,000
dropCost for drop opcode.440

Br_Table OpCode Costs

AttributeDescriptionCost
costFixed cost per br_table opcode.35,000
size_multiplierSize of target labels in the br_table opcode will be multiplied by size_multiplier.100

External Function Costs

The following costs are for low-level bindings for host-side ("external") functions. More information on the Casper external FFI can be found here.

Host-Side FunctionCostArguments
add5,800[0, 0, 0, 0]
add_associated_key9,000[0, 0, 0]
add_contract_version200[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
blake2b200[0, 0, 0, 0]
call_contract4,500[0, 0, 0, 0, 0, 420, 0]
call_versioned_contract4,500[0, 0, 0, 0, 0, 0, 0, 420, 0]
create_contract_package_at_hash200[0, 0]
create_contract_user_group200[0, 0, 0, 0, 0, 0, 0, 0]
create_purse2,500,000,000[0, 0]
disable_contract_version200[0, 0, 0, 0]
get_balance3,800[0, 0, 0]
get_blocktime330[0]
get_caller380[0]
get_key2,000[0, 440, 0, 0, 0]
get_main_purse1,300[0]
get_named_arg200[0, 0, 0, 0]
get_named_arg_size200[0, 0, 0]
get_phase710[0]
get_system_contract1,100[0, 0, 0]
has_key1,500[0, 840]
is_valid_uref760[0, 0]
load_named_keys42,000[0, 0]
new_uref17,000[0, 0, 590]
random_bytes200[0, 0]
print20,000[0, 4,600]
provision_contract_user_group_uref200[0, 0, 0, 0, 0]
put_key38,000[0, 1,100, 0, 0]
read_host_buffer3,500[0, 310, 0]
read_value6,000[0, 0, 0]
read_value_local5,500[0, 590, 0]
remove_associated_key4,200[0, 0]
remove_contract_user_group200[0, 0, 0, 0]
remove_contract_user_group_urefs200[0, 0, 0, 0, 0, 0]
remove_key61,000[0, 3,200]
ret23,000[0, 420,000]
revert500[0]
set_action_threshold74,000[0, 0]
transfer_from_purse_to_account2,500,000,000[0, 0, 0, 0, 0, 0, 0, 0, 0]
transfer_from_purse_to_purse82,000[0, 0, 0, 0, 0, 0, 0, 0]
transfer_to_account2,500,000,000[0, 0, 0, 0, 0, 0, 0]
update_associated_key4,200[0, 0, 0]
write14,000[0, 0, 0, 980]
write_local9,500[0, 1,800, 0, 520]

Protocol Operating Costs

AttributeDescriptionCost
wasmless_transfer_costDefault gas cost for a wasmless transfer.100,000,000

Auction System Contract Costs

These are the costs of calling auction system contract entrypoints.

EntrypointDescriptionCost
get_era_validatorsCost of calling the get_era_validators entrypoint.10,000
read_seigniorage_recipientsCost of calling the read_seigniorage_recipients entrypoint.10,000
add_bidCost of calling the add_bid entrypoint.2,500,000,000
withdraw_bidCost of calling the withdraw_bid entrypoint.2,500,000,000
delegateCost of calling the delegate entrypoint.2,500,000,000
undelegateCost of calling the undelegate entrypoint.2,500,000,000
run_auctionCost of calling the run_auction entrypoint.10,000
slashCost of calling the slash entrypoint.10,000
distributeCost of calling the distribute entrypoint.10,000
withdraw_delegator_rewardCost of calling the withdraw_delegator_reward entrypoint.10,000
withdraw_validator_rewardCost of calling the withdraw_validator_reward entrypoint.10,000
read_era_idCost of calling the read_era_id entrypoint.10,000
activate_bidCost of calling the activate_bid entrypoint.10,000
redelegateCost of calling the redelegate entrypoint.2,500,000,000

Mint System Contract Costs

These are the costs of calling mint system contract entrypoints.

EntrypointDescriptionCost
mintCost of calling the mint entrypoint.2,500,000,000
reduce_total_supplyCost of calling the reduce_total_supply entrypoint.10,000
createCost of calling the create entrypoint.2,500,000,000
balanceCost of calling the balance entrypoint.10,000
transferCost of calling the transfer entrypoint.10,000
read_base_round_rewardCost of calling the read_base_round_reward entrypoint.10,000
mint_into_existing_purseCost of calling the mint_into_existing_purse entrypoint.2,500,000,000

Handle_Payment System Contract Costs

These are the costs of calling entrypoints on the handle_payment system contract.

EntrypointDescriptionCost
get_payment_purseCost of calling the get_payment_purse entrypoint.10,000
set_refund_purseCost of calling the set_refund_purse entrypoint.10,000
get_refund_purseCost of calling the get_refund_purse entrypoint.10,000
finalize_paymentCost of calling the finalize_payment entrypoint.10,000

Standard_Payment System Contract Costs

These settings manage the costs of calling entrypoints on the standard_payment system contract.

EntrypointDescriptionCost
payCost of calling the pay entrypoint and sending an amount to a payment purse.10,000

Querying Global State

This page explains how to query global state after contract installation.

Prerequisites

Getting the State Root Hash

The first step in querying the global state is obtaining the state root hash. The state root hash acts as an identifier for the current state of the network (global state). It is like a Git commit ID for commit history, and it provides a snapshot of the blockchain state at a specific point in time.

note

After sending deploys to the network, it's necessary to fetch the new state root hash in order to see the changes reflected in the global state. Without doing this, you would be querying past versions of the state.

To get the state root hash, use the get-state-root-hash command:

casper-client get-state-root-hash --node-address [NODE_SERVER_ADDRESS]

Sending the Query

Next, query the state of a Casper network at a given time, specified by the state-root-hash described above. You can dive into the data stored in global state using the optional query path argument -q.

casper-client query-global-state \
--node-address [NODE_SERVER_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [HASH_STRING] \
-q "[SESSION_NAME]/[SESSION_NAMED_KEY]"

The arguments used above are:

  • node-address - An IP address of a peer on the network. The default port for JSON-RPC servers on Mainnet and Testnet is 7777
  • state-root-hash - Hex-encoded hash of the state root
  • key - The identifier for the query. This must be one of the following: public key, account hash, contract package hash, transfer hash, or deploy hash
  • q - An optional query path argument that allows you to drill into the specifics of a query with respect to the key

Query the account

To find your account details, query global state using your account hash.

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash fa968344a2000282686303f1664c474465f9a028f32ec4f51791d9fa64c0bcd7 \
--key account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d

Here is how your account state would look. Notice that the sample response contains several named keys, including "counter", "counter_package_name", and "version". You can use these values to query the contract state further, as shown in the next example.

Sample account state
{
"id": -6831525034388467034,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[27614 hex chars]",
"stored_value": {
"Account": {
"account_hash": "account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_hash": "account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d",
"weight": 1
}
],
"main_purse": "uref-d92e420120199f90005802bf3036362f368ab69bebf17e7e53856d6ac82e117f-007",
"named_keys": [
{
"key": "hash-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e",
"name": "counter"
},
{
"key": "uref-41c3f4ae3c1ce2446f6fd880a96e698ae5abc715151e45e357d88bb739489c03-007",
"name": "counter_access_uref"
},
{
"key": "hash-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e",
"name": "counter_package_name"
},
{
"key": "uref-917762490591a1404cba59ed8dcf0bcfa7f644ef6c6be9bf5ea7b1641617cad0-007",
"name": "version"
}
]
}
}
}
}

tip

If you don't know your account hash, you can run this command:

casper-client account-address --public-key [PATH_TO_PUBLIC_KEY]

Query the contract

This example shows how to query global state given a contract hash. We use the contract hash from the sample response above.

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash fa968344a2000282686303f1664c474465f9a028f32ec4f51791d9fa64c0bcd7 \
--key hash-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e

Here is how the sample contract would look and would contain details such as the contract_package_hash, the contract entry_points, and the named_keys for the contract.

Sample contract state
{
"id": -4657473054587773855,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[21330 hex chars]",
"stored_value": {
"Contract": {
"contract_package_hash": "contract-package-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e",
"contract_wasm_hash": "contract-wasm-576b1718711d524a79ab2f05ce801006a3fd32eb48b9f7dac69a9fa966d634e3",
"entry_points": [
{
"access": "Public",
"args": [],
"entry_point_type": "Contract",
"name": "counter_get",
"ret": "I32"
},
{
"access": "Public",
"args": [],
"entry_point_type": "Contract",
"name": "counter_inc",
"ret": "Unit"
}
],
"named_keys": [
{
"key": "uref-d40613e50c7b405b02795e3fe3252554bef49b4b522e31a55f39b87c442f922a-007",
"name": "count"
}
],
"protocol_version": "1.4.5"
}
}
}
}


Query a value using its key and the contract hash

Next, you can query a named key associated with the contract using the -q option. This example comes from the Counter Contract Tutorial, where a "count" variable is incremented and stored under a named key.

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH] \
--key [CONTRACT_HASH] \
-q "count"
Sample stored value
{
"id": -2540117660598287261,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[56562 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "00000000",
"cl_type": "I32",
"parsed": 0
}
}
}
}

Query a value using the account hash and named keys

It is also possible to check the state of a specific contract variable in global state given the account hash under which the contract was installed. Here we query the named key "count", stored under another key identifying the contract and named "counter".

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash fa968344a2000282686303f1664c474465f9a028f32ec4f51791d9fa64c0bcd7 \
--key account-hash-1d17e3fdad268f866a73558d1ae45e1eea3924c247871cb63f67ebf1a116e66d \
-q "counter/count"

The response should be the same as in Example 3, above.

Query contract package state

You can query information about a contract package, such as the latest contract hash and contract version, given its contract package hash.

casper-client query-global-state \
--node-address http://localhost:11101 \
--key hash-76a8c3daa6d6ac799ce9f46d82ac98efb271d2d64b517861ec89a06051ef019e \
--state-root-hash 763e737cf55a298d54bcdfb4ee55526538a1a086128914b9cc25ccbdebbbb966

Here is how the contract package details would look. The response would contain the contract_hash, which you would need to call a contract by hash in the next section. You would also see the access_key for the ContractPackage and the current contract_version.

Sample contract package state
{
"id": -6225901853092301031,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"block_header": null,
"merkle_proof": "[20964 hex chars]",
"stored_value": {
"ContractPackage": {
"access_key": "uref-41c3f4ae3c1ce2446f6fd880a96e698ae5abc715151e45e357d88bb739489c03-007",
"disabled_versions": [],
"groups": [],
"versions": [
{
"contract_hash": "contract-22228188b85b6ee4a4a41c7e98225c3918139e9a5eb4b865711f2e409d85e88e",
"contract_version": 1,
"protocol_version_major": 1
}
]
}
}
}
}

Video Walkthrough

This video shows you what to expect when querying the network.

What's Next?

Redelegating Tokens with the Casper Client

This document details a workflow where tokens staked with a validator can be redelegated to another validator with a single call while the unbonding process runs in the background. Otherwise, delegators would have to complete two steps by sending an unbonding request first and then delegate the tokens to the new validator.

Prerequisites

  1. You meet all prerequisites, including having a valid node-address and the Casper command-line client
  2. You have delegated tokens to a validator on a Casper network, and you have the validator's public key
  3. You have the public key of the new validator to whom you wish to redelegate tokens. See Acquiring a Validator's Public Key for more details

Method 1: Redelegating with the System Auction Contract

This method calls the existing redelegate entry point from the system auction contract. Using this method, you do not need to build contracts, reducing cost and complexity.

casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH_TO_DELEGATOR_SECRET_KEY> \
--chain-name <CHAIN_NAME> \
--payment-amount 2500000000 \
--session-hash <SESSION_HASH> \
--session-entry-point redelegate \
--session-arg "delegator:public_key='<DELEGATOR_PUBLIC_KEY_HEX>'" \
--session-arg "validator:public_key='<CURRENT_VALIDATOR_PUBLIC_KEY_HEX>'" \
--session-arg "amount:u512='<DELEGATION_AMOUNT>'" \
--session-arg "new_validator:public_key='<NEW_VALIDATOR_PUBLIC_KEY_HEX>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR
  5. session-hash - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:
  • Testnet: hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2
  • Mainnet: hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea
  1. session-entry-point - Name of the entrypoint that will be used when calling the contract

The redelegate entry point expects four arguments:

  1. delegator:public_key: The hexadecimal public key of the account submitting the redelegate request. This key must match the secret key that signs the deploy
  2. validator:public_key: The hexadecimal public key of the validator from whom the tokens will be undelegated
  3. amount: The amount to be redelegated to the new validator
  4. new_validator:public_key: The hexadecimal public key of the validator to whom the tokens will be delegated

The command will return a deploy hash, which is needed to verify the deploy's processing results.

note

Calling the redelegate entry point on the auction contract has a fixed cost of 2.5 CSPR and there is a minimum delegation amount of 500 CSPR that also applies to redelegations.

Example:

This example uses a private network running casper-node version 1.5. The payment amount specified is 2.5 CSPR. You must modify the payment and other values in the deploy based on the network's chainspec.toml.

casper-client put-deploy \
--node-address http://3.143.158.19:7777 \
--chain-name integration-test \
--secret-key ~/KEYS/integration/Test_secret_key.pem \
--payment-amount 2500000000 \
--session-hash hash-e22d38bcf3454a93face78a353feaccbf1d637d1ef9ef2e061a655728ff59bbe \
--session-entry-point redelegate \
--session-arg "validator:public_key='017fec504c642f2b321b8591f1c3008348c57a81acafceb5a392cf8416a5fb4a3c'" \
--session-arg "amount:u512='500000000000'" \
--session-arg "delegator:public_key='01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986'" \
--session-arg "new_validator:public_key='019e7b8bdec03ba83be4f5443d9f7f9111c77fec984ce9bb5bb7eb3da1e689c02d'"

Next, verify the redelegation.

Method 2: Redelegating with Compiled Wasm

Another way to send a redelegation is to compile the redelegate.wasm and send it to the network via a deploy. To compile the Wasm yourself, build the casper-node contracts that will include the redelegation Wasm.

Sending the redelegation request

We recommend testing the following steps on the official Testnet before performing them in a live environment like the Casper Mainnet.

This example uses the Casper client to send a deploy containing the redelegate.wasm to the network to initiate the redelegation process.

casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH_TO_DELEGATOR_SECRET_KEY> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT> \
--session-path <PATH_TO_WASM>/redelegate.wasm \
--session-arg "delegator:public_key='<DELEGATOR_PUBLIC_KEY_HEX>'" \
--session-arg "validator:public_key='<CURRENT_VALIDATOR_PUBLIC_KEY_HEX>'" \
--session-arg "amount:u512='<DELEGATION_AMOUNT>'" \
--session-arg "new_validator:public_key='<NEW_VALIDATOR_PUBLIC_KEY_HEX>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR
  5. session-path - The path to the redelegate.wasm on your computer

The redelegate.wasm expects four arguments:

  1. delegator:public_key: The hexadecimal public key of the account submitting the redelegate request. This key must match the secret key that signs the deploy
  2. validator:public_key: The hexadecimal public key of the validator from whom the tokens will be undelegated
  3. amount: The amount to be redelegated to the new validator
  4. new_validator:public_key: The hexadecimal public key of the validator to whom the tokens will be delegated

Save the returned deploy_hash from the output to query information about the redelegation Deploy.

note

Running the redelegate.wasm is a more expensive operation than calling the redelegate entrypoint from the system auction contract.

Example:

This example uses a private network running casper-node version 1.5. The payment amount specified is 8 CSPR. You must modify the payment and other values in the deploy based on the network's chainspec.toml.

casper-client put-deploy \
--node-address http://3.143.158.19:7777 \
--chain-name integration-test \
--secret-key ~/KEYS/integration/Test_secret_key.pem \
--payment-amount 8000000000 \
--session-path ~/redelegate.wasm \
--session-arg "validator:public_key='017fec504c642f2b321b8591f1c3008348c57a81acafceb5a392cf8416a5fb4a3c'" \
--session-arg "amount:u512='500000000000'" \
--session-arg "delegator:public_key='01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986'" \
--session-arg "new_validator:public_key='019e7b8bdec03ba83be4f5443d9f7f9111c77fec984ce9bb5bb7eb3da1e689c02d'"

Verifying the Redelegation

The redelegation process includes an unbonding delay before the tokens are redelegated to a new validator. In contrast, initial delegation occurs when a Casper network finalizes the associated Deploy.

Due to this delay, the new validator may become inactive before the redelegation completes. If this happens, the tokens will be returned to the delegator.

Once the redelegation Deploy has been processed, you can query the auction to confirm the redelegation. This process is the same as verifying a delegation request using the casper-client get-auction-info command.

Sending Deploys using the Casper Client

To install smart contracts on the blockchain, you can send your Wasm to the network via a Deploy. To do this, you will need to meet a few prerequisites:

  • You will need a client to interact with the network, such as the default Casper client
  • Ensure you have an Account and its associated keys This account will pay for the Deploy, and its secret key will sign the Deploy
  • Ensure this account has enough CSPR tokens to pay for the Deploy

Paying for Deploys

CSPR tokens are used to pay for deploys on the Casper Mainnet and Testnet. There are several ways to fund your account:

Monitoring the Event Stream for Deploys

If you want to follow the lifecycle of the Deploy, you can start monitoring a node's event stream. This section will focus only on DeployAccepted events, but there are other event types described here. You need the following information to proceed:

  • The IP address of a peer on the network
  • The port specified as the event_stream_server.address in the node's config.toml, which is by default 9999 on Mainnet and Testnet
  • The URL for DeployAccepted events, which is <HOST:PORT>/events/deploys

With the following command, you can start watching the event stream for DeployAccepted events. Note the event ID recorded when you send the Deploy in the next section.

curl -s http://65.21.235.219:9999/events/deploys

Sending a Deploy to the Network

You can call the Casper client's put-deploy command to put the compiled contract on the chain. In this example, the Deploy will execute in the account's context. See the advanced features section for key delegation.

casper-client put-deploy \
--node-address <HOST:PORT> \
--chain-name casper-test \
--secret-key <PATH> \
--payment-amount <PAYMENT-AMOUNT> \
--session-path <SESSION-PATH>
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777. You can find a list of trusted peers in network's configuration file, config.toml. Here is an example. You may send deploys to one of the trusted nodes or use them to query other online nodes.
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test. As you can see, this example uses the Testnet
  4. payment-amount - The payment for the Deploy in motes. This example uses 2.5 CSPR, but you need to modify this for your contract. See the note below
  5. session-path - The path to the contract Wasm, which should point to wherever you compiled the contract (.wasm file) on your computer

The command will return a deploy hash, which is needed to verify the deploy's execution results. Sending the deploy and receiving the deploy hash does not mean the deploy was processed successfully. Therefore, you must check the deploy execution using the deploy hash. See the deploy lifecycle for more details.

Note: Each Deploy gets a unique hash, which is part of the cryptographic security of blockchain technology. No two deploys will ever return the same hash.

Sample put-deploy result
{
"id": -6958186952964949950,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"deploy_hash": "34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496"
}
}

Verify the deploy details with the get-deploy command and the deploy_hash received above.

casper-client get-deploy \
--node-address <HOST:PORT> <DEPLOY-HASH>

If the Deploy succeeded, the get-deploy command would return a JSON object with the full deploy details.

Sample get-deploy result
{
"id": -3532286620275982221,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.5",
"deploy": {
"approvals": [
{
"signature": "015a7b0178e144fbf5ce52147c44a3e6bd6aae898ec6bb47c97b5802f3bcb6cd26331f7db18464cd1e51764c14ceb24b7ab9c4e3595505c32465fc0702e8d5510b",
"signer": "01e76e0279a08b96d9d68e6b86c618de24a0c324d7d0c1fa8c035f0bc2af1a396d"
}
],
"hash": "34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496",
"header": {
"account": "01e76e0279a08b96d9d68e6b86c618de24a0c324d7d0c1fa8c035f0bc2af1a396d",
"body_hash": "b1956600be3c11d7555ada11426ab1a8bdf36102f59838d6bf69cec321111a22",
"chain_name": "casper-test",
"dependencies": [],
"gas_price": 1,
"timestamp": "2022-03-24T12:05:57.579Z",
"ttl": "30m"
},
"payment": {
"ModuleBytes": {
"args": [
[
"amount",
{
"bytes": "05000c774203",
"cl_type": "U512",
"parsed": "14000000000"
}
]
],
"module_bytes": ""
}
},
"session": {
"ModuleBytes": {
"args": [],
"module_bytes": "[94478 hex chars]"
}
}
},
"execution_results": [
{
"block_hash": "098b618878a2413393925e1fbf6d3cf92f1208f4f8662a904e86b49b0c4ab9f0",
"result": {
"Success": {
"cost": "13327900740",
"effect": {
"operations": [],
"transforms": [
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",
"transform": "Identity"
},
{
"key": "balance-3a61ed9a3b472f35f4cf1e241d674fad8a5f9509c97a56d62bb03f7bcc4b8474",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "balance-3a61ed9a3b472f35f4cf1e241d674fad8a5f9509c97a56d62bb03f7bcc4b8474",
"transform": {
"WriteCLValue": {
"bytes": "0500279bd1ca",
"cl_type": "U512",
"parsed": "871100000000"
}
}
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": {
"AddUInt512": "14000000000"
}
},
{
"key": "uref-82a7b5713f2b9b3f9e1b4f2d1f312a5fec7c3a0bed6fa897501913951729dbbf-000",
"transform": {
"WriteCLValue": {
"bytes": "00000000",
"cl_type": "I32",
"parsed": 0
}
}
},
{
"key": "uref-ea022d75ff618533baf46040cc57692fb7f7840774c979c9dec0b5c3ddcec7e9-000",
"transform": {
"WriteCLValue": {
"bytes": "",
"cl_type": "Unit",
"parsed": null
}
}
},
{
"key": "hash-4d0e2bfb5d243ea567e9b37aa8229d2b8b01de838c4bd7ca570a178e012d6b82",
"transform": "WriteContractPackage"
},
{
"key": "hash-4d0e2bfb5d243ea567e9b37aa8229d2b8b01de838c4bd7ca570a178e012d6b82",
"transform": "Identity"
},
{
"key": "hash-3b69bafcc13b4541dddd7d5492e4754feee41c636990aeb6bf78d58fdd39fc43",
"transform": "WriteContractWasm"
},
{
"key": "hash-c39dd923df84c637e46e46a8a3326fcf85e43c60814878f44a08efd0074cb523",
"transform": "WriteContract"
},
{
"key": "hash-4d0e2bfb5d243ea567e9b37aa8229d2b8b01de838c4bd7ca570a178e012d6b82",
"transform": "WriteContractPackage"
},
{
"key": "account-hash-f407926760b91c2ce3af8bda7448841b3aa68c6e98053331d10819ef2d0a808e",
"transform": {
"AddKeys": [
{
"key": "hash-c39dd923df84c637e46e46a8a3326fcf85e43c60814878f44a08efd0074cb523",
"name": "counter"
}
]
}
},
{
"key": "deploy-34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496",
"transform": {
"WriteDeployInfo": {
"deploy_hash": "34550c8b86d5e38260882466e98427c62a27a96d85c13f49041a1579ebf84496",
"from": "account-hash-f407926760b91c2ce3af8bda7448841b3aa68c6e98053331d10819ef2d0a808e",
"gas": "13327900740",
"source": "uref-3a61ed9a3b472f35f4cf1e241d674fad8a5f9509c97a56d62bb03f7bcc4b8474-007",
"transfers": []
}
}
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "balance-0a24ef56971d46bfefbd5590afe20e5f3482299aba74e1a0fc33a55008cf9453",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": {
"WriteCLValue": {
"bytes": "00",
"cl_type": "U512",
"parsed": "0"
}
}
},
{
"key": "balance-0a24ef56971d46bfefbd5590afe20e5f3482299aba74e1a0fc33a55008cf9453",
"transform": {
"AddUInt512": "14000000000"
}
}
]
},
"transfers": []
}
}
}
]
}
}

We want to draw your attention to a few properties in the example output:

  • Execution cost 13327900740 motes, yet we paid 14000000000 motes. See the note about gas price
  • The contract returned no errors. If you see an "Out of gas error", you did not specify a high enough value in the --payment-amount arg
  • The time-to-live was 30 minutes

It is also possible to get a summary of the deploy's information by performing a query-global-state command using the Casper client and providing a state root hash or a block hash from a block at or after the one in which the deploy was executed.

casper-client get-state-root-hash --node-address <HOST:PORT>

casper-client query-global-state --node-address <HOST:PORT> \
--key deploy-<DEPLOY-HASH-HEX-STRING> \
--state-root-hash <STATE-ROOT-HASH-HEX-STRING>
casper-client query-global-state --node-address <HOST:PORT> \
--key deploy-<DEPLOY-HASH-HEX STRING>
--block-hash <BLOCK-HASH-HEX-STRING>

Run the help command for query-global-state to see its usage.

casper-client query-global-state --help

Time-to-live

Time-to-live is the parameter that determines how long a deploy will wait for execution. The acceptable maximum ttl is configurable by chain, with the Casper Mainnet maximum set to 18hours. If you are sending a deploy to a different network, you will need to check chainspec.toml for that network to determine the acceptable maximum. The minimum is theoretically zero, but this will result in an immediate expiration and an invalid deploy.

In the event of a network outage or other event that prevents execution within the ttl, the solution is to resend the deploy in question.

Should the deploy's ttl exceed the allowable limit, or if the deploy expires, the network's deploy acceptor will find the deploy invalid and return a warning.

Deploy Payments

Dependent upon the complexity and needs of the Deploy in question, several options exist to allow users to pay for smart contract execution.

The simplest way to pay for a Deploy on the Casper blockchain is to use the host side standard payment functionality. This can be done using an empty ModuleBytes as your payment code. However, you must specify the amount within a runtime argument. ModuleBytes can also serve as a custom payment contract if it is not empty, but any additional Wasm ran within will come at an additional cost on top of the payment. This includes invalid Wasm, which will still result in additional cost.

You may find the host side functionality of standard payment insufficient for your purposes. In this event, Casper provides the following options for custom payment code:

StoredContractByHash

StoredContractByName

StoredVersionContractByHash

StoredVersionContractByName

Using Arguments with Deploys

The session Wasm (or payment Wasm if you choose to not use the standard payment) of a Deploy often requires arguments to be passed to it when executed. These "runtime args" should be provided by using the --session-arg or --payment-arg options, once for each arg required. The Casper client provides some examples of how to do this:

casper-client put-deploy --show-arg-examples

Advanced Features

Casper networks support complex deploys using multiple signatures. Casper Accounts use a powerful permissions model that enables a multi-signature scheme for deploys.

The put-deploy command performs multiple actions under the hood, optimizing the typical use case. It creates a deploy, signs it, and sends the Deploy to the network without allowing multiple signatures. However, it is possible to call the following three commands and separate key management from account creation:

  • make-deploy - Creates a Deploy and outputs it to a file or stdout. As a file, the deploy can subsequently be signed by other parties using the sign-deploy subcommand and then sent to the network for execution using the send-deploy subcommand
  • sign-deploy - Reads a previously-saved Deploy from a file, cryptographically signs it, and outputs it to a file or stdout
  • send-deploy - Reads a previously-saved Deploy from a file and sends it to the network for execution

To sign a Deploy with multiple keys, create the Deploy with the make-deploy command. The generated deploy file can be sent to the other signers, who then sign it with their keys by calling the sign-deploy for each key. Signatures need to be gathered on the Deploy one after another until all required parties have signed the Deploy. Finally, the signed Deploy is sent to the network with the send-deploy command for processing.

For a step-by-step workflow, visit the Two-Party Multi-Signature Deploy guide. This workflow describes how a trivial two-party multi-signature scheme for signing and sending deploys can be enforced for an account on a Casper network.

A Note about Gas Price

A common question frequently arises: "How do I know what the payment amount (gas cost) should be?"

We recommend installing your contracts in a test environment, making sure the cost tables match those of the production Casper network to which you want to send the deploy. If you plan on sending a deploy to Mainnet, you can use the Testnet to estimate the payment amount needed for the deploy.

If your test configuration matches your production chainspec, you can check the deploy status and roughly see how much it would cost. You can estimate the costs in this way and then add a small buffer to be sure. Refer to the runtime economics section for more details about gas usage and fees.

Please be aware that sending a deploy always requires payment. This is true regardless of the validity of included Wasm.

If the deploy failure occurs after session execution begins, the penalty payment of 2.5 CSPR is included in the gas costs of the failed execution.

However, if the failure occurs prior to session execution, the penalty payment will not appear within the gas cost of the deploy. Instead, the system automatically deducts the 2.5 CSPR from the sending account's main purse.

Direct Token Transfer

This workflow describes how to use the Casper command-line client to transfer tokens between purses on a Casper network.

Prerequisites

This workflow assumes:

  1. You meet the general development prerequisites
  2. You are using the Casper command-line client
  3. You have a target public key
  4. You have a valid node address
  5. You must be able to sign a deploy for the source account using the source secret key

Direct Transfer Example

The following transfer command allows you to move CSPR from one account's purse to another as denominated in Motes. A Mote is a denomination of the cryptocurrency CSPR, where 1 CSPR = 1,000,000,000 Motes.

For transfers of at least 2.5 CSPR (2,500,000,000 Motes) from a single sender to a single recipient on a Casper network, the most efficient option is to use the direct transfer capability.

casper-client transfer \
--id <ID> \
--transfer-id <TRANSFER_ID> \
--node-address [NODE_SERVER_ADDRESS] \
--amount [AMOUNT_TO_TRANSFER] \
--secret-key [KEY_PATH]/secret_key.pem \
--chain-name [CHAIN_NAME] \
--target-account [TARGET_PUBLIC_KEY_HEX] \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES]

Request fields:

  • id - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned

  • transfer-id -<64-BIT INTEGER> The transfer-id is a memo field, providing additional information about the recipient, which is necessary when transferring tokens to some recipients. For example, if depositing tokens into an account's purse where off-chain management keeps track of individual sub-balances, it is necessary to provide a memo ID uniquely identifying the actual recipient. If this is not necessary for a given recipient, you may pass 0 or some u64 value that is meaningful to you

  • node-address - Hostname or IP and port of a node on a network bound to a JSON-RPC endpoint [default:http://localhost:7777]

  • amount -<512-BIT INTEGER> The number of motes to transfer (1 CSPR = 1,000,000,000 Motes)

  • secret-key - Path to secret key file

  • chain-name - Name of the chain, to avoid the deploy from being accidentally or maliciously included in a different chain

    • The chain-name for Testnet is casper-test
    • The chain-name for Mainnet is casper
  • target-account - Hex-encoded public key of the account that will receive the funds in its main purse

  • payment-amount - The payment for the transfer in motes. The payment amount varies based on each deploy and network chainspec. For Testnet node version 1.5.1, you can specify 10^8 motes

Important response fields:

  • "result"."deploy_hash" - The address of the deploy, needed to look up additional information about the transfer
note

Save the returned deploy_hash from the output to query information about the transfer deploy later.

Example Transfer:

casper-client transfer -v \
--id 3 \
--transfer-id 11102023 \
--node-address https://rpc.testnet.casperlabs.io/ \
--amount 5000000000 \
--secret-key ~/KEYS/secret_key.pem \
--chain-name casper-test \
--target-account 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986 \
--payment-amount 100000000
Explore the JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "account_put_deploy",
"params": {
"deploy": {
"hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",
"header": {
"account": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",
"timestamp": "2023-10-12T14:59:40.760Z",
"ttl": "30m",
"gas_price": 1,
"body_hash": "ea7e6a6cbdd4d761827cb627e162896bee3e771beda000550615c9b4fafa3a2d",
"dependencies": [],
"chain_name": "casper-test"
},
"payment": {
"ModuleBytes": {
"module_bytes": "",
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400e1f505",
"parsed": "100000000"
}
]
]
}
},
"session": {
"Transfer": {
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0500f2052a01",
"parsed": "5000000000"
}
],
[
"target",
{
"cl_type": "PublicKey",
"bytes": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",
"parsed": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986"
}
],
[
"id",
{
"cl_type": {
"Option": "U64"
},
"bytes": "014767a90000000000",
"parsed": 11102023
}
]
]
}
},
"approvals": [
{
"signer": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",
"signature": "01e53cb742ed13ff4f0584a3da0f22f5942a33e010965adf640c91204ae4bc7436f1e5534d338ffa117d193295214816445439781229d24a372085c316eac5e305"
}
]
}
},
"id": 3
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"id": 3,
"result": {
"api_version": "1.5.3",
"deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c"
}
}

Verifying the Deploy

A transfer on a Casper network is only executed after it has been included in a finalized block.

casper-client get-deploy
--node-address [NODE_SERVER_ADDRESS] [DEPLOY_HASH]

Important response fields:

  • "result"."execution_results"[0]."transfers[0]" - the address of the executed transfer that the source account initiated. We will use it to look up additional information about the transfer
  • "result"."execution_results"[0]."block_hash" - contains the block hash of the block that included the transfer. We will require the state_root_hash of this block to look up information about the accounts and their purse balances
note

Transfer addresses use a transfer- string prefix.

Example Query:

casper-client get-deploy
--node-address https://rpc.testnet.casperlabs.io
1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c
Explore the JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "info_get_deploy",
"params": {
"deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",
"finalized_approvals": false
},
"id": -3447643973713335073
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"result": {
"api_version": "1.5.3",
"deploy": {
"hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",
"header": {
"account": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",
"timestamp": "2023-10-12T14:59:40.760Z",
"ttl": "30m",
"gas_price": 1,
"body_hash": "ea7e6a6cbdd4d761827cb627e162896bee3e771beda000550615c9b4fafa3a2d",
"dependencies": [],
"chain_name": "casper-test"
},
"payment": {
"ModuleBytes": {
"module_bytes": "",
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400e1f505",
"parsed": "100000000"
}
]
]
}
},
"session": {
"Transfer": {
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0500f2052a01",
"parsed": "5000000000"
}
],
[
"target",
{
"cl_type": "PublicKey",
"bytes": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",
"parsed": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986"
}
],
[
"id",
{
"cl_type": {
"Option": "U64"
},
"bytes": "014767a90000000000",
"parsed": 11102023
}
]
]
}
},
"approvals": [
{
"signer": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",
"signature": "01e53cb742ed13ff4f0584a3da0f22f5942a33e010965adf640c91204ae4bc7436f1e5534d338ffa117d193295214816445439781229d24a372085c316eac5e305"
}
]
},
"execution_results": [
{
"block_hash": "aac51dad028ba8b3d6fec86a39252bbc4285d513fd57a8af4696ab5390ac5c2b",
"result": {
"Success": {
"effect": {
"operations": [],
"transforms": [
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"transform": "Identity"
},
{
"key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",
"transform": {
"WriteCLValue": {
"cl_type": "U512",
"bytes": "06621c3e660301",
"parsed": "1114111876194"
}
}
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": {
"AddUInt512": "100000000"
}
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"transform": "Identity"
},
{
"key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",
"transform": {
"WriteCLValue": {
"cl_type": "U512",
"bytes": "06621c3e660301",
"parsed": "1114111876194"
}
}
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": {
"AddUInt512": "100000000"
}
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",
"transform": "Identity"
},
{
"key": "balance-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c",
"transform": "Identity"
},
{
"key": "balance-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1",
"transform": {
"WriteCLValue": {
"cl_type": "U512",
"bytes": "06622a383c0201",
"parsed": "1109111876194"
}
}
},
{
"key": "balance-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c",
"transform": {
"AddUInt512": "5000000000"
}
},
{
"key": "transfer-0de7250864e67aa76626a844dcc931e615284a13a110df3f97cec9e3e97af405",
"transform": {
"WriteTransfer": {
"deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",
"from": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",
"to": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"source": "uref-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1-007",
"target": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-004",
"amount": "5000000000",
"gas": "0",
"id": 11102023
}
}
},
{
"key": "deploy-1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",
"transform": {
"WriteDeployInfo": {
"deploy_hash": "1f17a0bdeaaf71abd03492c854cdf97f746432751721ce555e95b9cefe641e3c",
"transfers": ["transfer-0de7250864e67aa76626a844dcc931e615284a13a110df3f97cec9e3e97af405"],
"from": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",
"source": "uref-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1-007",
"gas": "100000000"
}
}
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "balance-da632bfba17f4a7882581de2a37219be71628600ccd0df83f1d42465bd018537",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": {
"WriteCLValue": {
"cl_type": "U512",
"bytes": "00",
"parsed": "0"
}
}
},
{
"key": "balance-da632bfba17f4a7882581de2a37219be71628600ccd0df83f1d42465bd018537",
"transform": {
"AddUInt512": "100000000"
}
}
]
},
"transfers": ["transfer-0de7250864e67aa76626a844dcc931e615284a13a110df3f97cec9e3e97af405"],
"cost": "100000000"
}
}
}
]
},
"id": -3447643973713335073
}

Refer to the Section on querying deploys for more information.

Verifying the Transfer

In addition to verifying the deploy, you also need to verify the transfer details. The deploy may have been successful, but you also need to ensure the source and target accounts were updated correctly.

Transferring Tokens with the Casper CLI Client

The following topics describe using the Casper command-line client to transfer tokens between purses on a Casper network. Depending on the account configuration, a direct transfer or a multiple-signature (multi-sig) deploy transfer can be utilized.

Transferring tokens using a direct transfer

Tokens can be transferred directly when the signing key has enough weight to approve the transaction. This is the most common scenario, applicable by default for accounts with a single primary key. To use a direct transfer, see Transferring Tokens Using Direct Transfer.

Transferring tokens using a multi-sig deploy

Multi-sig deploy transfers are typically used when the account initiating the transfer has multiple associated keys that need to sign the deploy. To set up the account's associated keys, see the Two-Party Multi-Signature Deploys workflow. To use a multi-sig deploy transfer, see Transferring Tokens Using a Multi-sig Account.

Verifying a transfer using the command-line client

To verify the status of a transfer, see Verifying a Transfer.

Transferring Tokens using a Multi-Sig Deploy

This page presents a method of transferring tokens via a deploy file using multiple signatures. This method is recommended when implementing multi-signature transfers between purses on a Casper network.

The make-transfer command allows you to create a transfer and save the output to a file. You can then have the transfer signed by other parties using the sign-deploy command and send it to the network for execution using the send-deploy command.

Prerequisites

You must ensure the following prerequisites are met.

  1. Set up all the prerequisites listed here, including:
  2. Set up the source account for multi-signature deploys, as outlined in the Two-Party Multi-Signature Deploys workflow
  3. Get the path of the source account's secret key file
  4. Get the target account's public key in hex format

Token Transfer Workflow

The high-level flow to transfer tokens using the Casper CLI client and a deploy file is described in the following steps:

  1. The make-transfer command creates and signs a transfer, saving the output to a file
  2. The sign-deploy command adds additional signatures for a multi-signature transfer
  3. The send-deploy command sends the deploy containing the transfer to the network
Deployment flow

Creating the transfer

This section explains the make-transfer command using an example you can try on the Testnet. For this example, we are transferring 2,500,000,000 motes from the source account (with the secret_key.pem file) to a target account. To use this example on the Mainnet, the chain-name would be casper instead of casper-test. Note that we are saving the output of the make-transfer command in a transfer.deploy file.

casper-client make-transfer --amount 2500000000 \
--secret-key [PATH]/secret_key.pem \
--chain-name casper-test \
--target-account [PUBLIC_KEY_HEX] \
--transfer-id [ID] \
--payment-amount 100000000 \
--output transfer.deploy

The following table explains the parameters used in the make-transfer command.

ParameterDescription
amountThe number of motes you wish to transfer (1 CSPR = 1,000,000,000 motes)
secret-keyThe path of the secret key file for the source account
chain-nameThe name of the chain, to avoid the deploy from being accidentally or maliciously included in a different chain
  • For Testnet use casper-test
  • For Mainnet use casper
target-accountHex-encoded public key of the target account from which the main purse will be used
transfer-idA user-defined identifier permanently associated with the transfer
payment-amountThe payment for the transfer in motes. The payment amount varies based on the deploy and network chainspec. For Testnet node version 1.5.1, wasmless transfers cost 10^8 motes

In the output, you will see a section named approvals. This is where a signature from the source account is added to the deploy.

Example:

casper-client make-transfer --amount 2500000000 \
--secret-key ~/KEYS/multi-sig/keys/default_secret_key.pem \
--chain-name casper-test \
--target-account 0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf \
--transfer-id 1 \
--payment-amount 100000000 \
--output transfer.deploy
Sample output of the make-transfer command
{
"hash": "88c49fa9108485397a330f294914a6c2d614c581fbe0a31de1a954baad6d709b",
"header": {
"account": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",
"timestamp": "2023-10-12T19:14:22.080Z",
"ttl": "30m",
"gas_price": 1,
"body_hash": "1bb7436d4703816b5cbeef245dd83c0520f1c7173cdf609c664a29487cc5de1c",
"dependencies": [],
"chain_name": "casper-test"
},
"payment": {
"ModuleBytes": {
"module_bytes": "",
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400e1f505",
"parsed": "100000000"
}
]
]
}
},
"session": {
"Transfer": {
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400f90295",
"parsed": "2500000000"
}
],
[
"target",
{
"cl_type": "PublicKey",
"bytes": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",
"parsed": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf"
}
],
[
"id",
{
"cl_type": {
"Option": "U64"
},
"bytes": "010100000000000000",
"parsed": 1
}
]
]
}
},
"approvals": [
{
"signer": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",
"signature": "015e0db50b174f3627e0e27cb503f0836b30bd0e0f2c4b989366b0df57500a1cb2b0945408c938bc3c33c40dab59a9c6af6f4e01e474330cd27262bfc87680030e"
}
]
}

Signing the transfer

Once the deploy file is created, you can sign the deploy using other designated accounts. For this example, we are signing the deploy with a second secret key and saving the output in a transfer2.deploy file.

casper-client sign-deploy \
--input transfer.deploy \
--secret-key [PATH]/another_secret_key.pem \
--output transfer2.deploy
ParameterDescription
inputThe path of the deploy file, which needs to be signed
secret-keyThe path of the secret key file used to sign the deploy
outputThe path of the output file used to save the deploy with multiple signatures

Example:

casper-client sign-deploy \
--input transfer.deploy \
--secret-key ~/KEYS/multi-sig/keys/user_1_secret_key.pem \
--output transfer2.deploy

Towards the end of the following output, you can observe that there is an approvals section, which has two signatures, one from the account initiating the transfer and the second from the account used to sign the deploy.

Sample output saved in the transfer2.deploy file
{
"hash": "88c49fa9108485397a330f294914a6c2d614c581fbe0a31de1a954baad6d709b",
"header": {
"account": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",
"timestamp": "2023-10-12T19:14:22.080Z",
"ttl": "30m",
"gas_price": 1,
"body_hash": "1bb7436d4703816b5cbeef245dd83c0520f1c7173cdf609c664a29487cc5de1c",
"dependencies": [],
"chain_name": "casper-test"
},
"payment": {
"ModuleBytes": {
"module_bytes": "",
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400e1f505",
"parsed": "100000000"
}
]
]
}
},
"session": {
"Transfer": {
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400f90295",
"parsed": "2500000000"
}
],
[
"target",
{
"cl_type": "PublicKey",
"bytes": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf",
"parsed": "0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf"
}
],
[
"id",
{
"cl_type": {
"Option": "U64"
},
"bytes": "010100000000000000",
"parsed": 1
}
]
]
}
},
"approvals": [
{
"signer": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986",
"signature": "015e0db50b174f3627e0e27cb503f0836b30bd0e0f2c4b989366b0df57500a1cb2b0945408c938bc3c33c40dab59a9c6af6f4e01e474330cd27262bfc87680030e"
},
{
"signer": "01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51",
"signature": "017793ad52d27393b1aa8ff5bb9bdbcb48708910d6cdabd9a89b44690ca174edf8924aad340bf901ac343391cb4cba7cf4db07390372f28ecf471fd522e0b63803"
}
]
}

Sending the deploy

The next step is to send the deploy for processing on the network. As described in the Prerequisites section, you need to get an active node address from the corresponding network to complete this task. The following example uses the node https://rpc.testnet.casperlabs.io/ from the Testnet.

casper-client send-deploy \
--input transfer2.deploy \
--node-address https://rpc.testnet.casperlabs.io/
ParameterDescription
inputThe path of the deploy file, which is used as the input
node-addressThe Hostname or IP and port of the node

Make a note of the deploy_hash from the send-deploy command output to verify the status of the deploy.

Successful output of the send-deploy command
{
"jsonrpc": "2.0",
"id": -818883417884028030,
"result": {
"api_version": "1.5.3",
"deploy_hash": "88c49fa9108485397a330f294914a6c2d614c581fbe0a31de1a954baad6d709b"
}
}
note

If you encounter an account authorization error, you must set up the source account to allow multi-signature deploys using session code. The Two-Party Multi-Signature Deploys workflow is an example of how to accomplish this.

Example of an account authorization error
{
"code": -32008,
"message": "deploy parameter failure: account authorization invalid at prestate_hash: 5f0392de8ac3512a48a110acfc5bc10d4a6a07109b350ae14cbec0428656c8ac"
}

Verifying the transfer

To verify the transfer status, see Verifying a Transfer.

tip

You can also verify if the transfer was successful by checking your account balance using a block explorer.

Verifying a Transfer

Prerequisites

Before verifying a transfer, make sure you have:

  1. Initiated a Direct Transfer or Multi-sig Deploy Transfer
  2. The deploy_hash of the transfer you want to verify
  3. The public key of the source and target accounts

Query the State Root Hash

The state root hash is an identifier of the current network state. It gives a snapshot of the blockchain state at a moment in time. You can use the state root hash to query the network state after sending a deploy.

casper-client get-state-root-hash --node-address [NODE_SERVER_ADDRESS]

Example Query:

casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io
Sample output of the get-state-root-hash command
{
"jsonrpc": "2.0",
"id": 6458079936180872466,
"result": {
"api_version": "1.5.3",
"state_root_hash": "fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1"
}
}
note

After sending deploys to the network, you must get the new state root hash to see the changes reflected. Otherwise, you will be looking at events in the past.

Query the Transfer Details

A transfer is executed as part of a deploy. In a Casper network, deploys can contain multiple transfers. Execution of the deploy includes writing information about each individual transfer to global state. A unique hash known as the transfer-address identifies each transfer. The transfer-address consists of a formatted string with a transfer- prefix.

Image showing a transfer hash

First, use the get-deploy command and the deploy_hash to identify the corresponding transfer:

casper-client get-deploy \
--node-address [NODE_SERVER_ADDRESS] \
[DEPLOY_HASH]

Important response fields:

  • "result"."execution_results"."result"."Success"."transfers" - List of transfers contained in a successful deploy

After obtaining the transfer identifier, query the transfer details.

casper-client query-global-state \
--id [ID] \
--node-address [NODE_SERVER_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [TRANSFER_HASH]

Request fields:

  • id - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned
  • node-address - An IP address of a node on the network
  • state-root-hash - The hex-encoded hash of the state root
  • key - The base key for the query. This must be a properly formatted transfer address with a transfer- prefix, i.e., transfer-ab3e11fd612ccf9ddf5ddb3e5c0b3d3b5e5c0921fd1b45e8c657a63f01d6adcb

The -v option generates verbose output, printing the RPC request and response generated. Let's explore an example below.

Example Query:

casper-client query-global-state -v \
--id 3 \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1 \
--key transfer-ab3e11fd612ccf9ddf5ddb3e5c0b3d3b5e5c0921fd1b45e8c657a63f01d6adcb
Explore the JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "query_global_state",
"params": {
"state_identifier": {
"StateRootHash": "fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1"
},
"key": "transfer-ab3e11fd612ccf9ddf5ddb3e5c0b3d3b5e5c0921fd1b45e8c657a63f01d6adcb",
"path": []
},
"id": 3
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"result": {
"api_version": "1.5.3",
"block_header": null,
"stored_value": {
"Transfer": {
"deploy_hash": "4eedbb5cf4a571748cf7ae9c2f17777364a01f80f79f3633a0cec32b7e8cf2e3",
"from": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",
"to": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"source": "uref-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1-007",
"target": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-004",
"amount": "5000000000",
"gas": "0",
"id": 11102023
}
},
"merkle_proof": "[42526 hex chars]"
},
"id": 3
}

The query responds with more information about the transfer: its deploy hash, the account which executed the transfer, the source and target purses, and the target account. You can verify that the transfer processed successfully using this additional information.

Query the Account State

Next, query for information about the Source account, using the state-root-hash of the block containing the transfer:

casper-client query-global-state \
--id [ID] \
--node-address [NODE_SERVER_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [SOURCE_PUBLIC_KEY]

Request fields:

  • id - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned
  • node-address - An IP address of a node on the network
  • state-root-hash - Hex-encoded hash of the network state
  • key - The base key for the query. This must be a properly formatted public key, account hash, contract address hash, URef, transfer hash, or deploy-info hash

Important response fields:

  • "result"."stored_value"."Account"."main_purse" - the address of the main purse containing the sender's tokens. In this example, this purse is the source of the tokens transferred

Source Account Query:

casper-client query-global-state -v \
--id 4 \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1 \
--key 0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf
Explore the JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "query_global_state",
"params": {
"state_identifier": {
"StateRootHash": "fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1"
},
"key": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",
"path": []
},
"id": 4
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"result": {
"api_version": "1.5.3",
"block_header": null,
"stored_value": {
"Account": {
"account_hash": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",
"named_keys": [...],
"main_purse": "uref-11e6fc5354f61a004df98482376c45964b8b1557e8f2f13fb5f3adab5faa8be1-007",
"associated_keys": [
{
"account_hash": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",
"weight": 1
}
],
"action_thresholds": {
"deployment": 1,
"key_management": 1
}
}
},
"merkle_proof": "[31406 hex chars]"
},
"id": 4
}

Target Account Query:

Repeat the same step to query information about the Target account:

casper-client query-global-state -v \
--id 5 \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1 \
--key 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986
Explore the JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "query_global_state",
"params": {
"state_identifier": {
"StateRootHash": "fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1"
},
"key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"path": []
},
"id": 5
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"result": {
"api_version": "1.5.3",
"block_header": null,
"stored_value": {
"Account": {
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"named_keys": [...],
"main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",
"associated_keys": [...],
"action_thresholds": {
"deployment": 2,
"key_management": 3
}
}
},
"merkle_proof": "[32060 hex chars]"
},
"id": 5
}

Query the Purse Balance

All accounts on a Casper network have a purse associated with the Casper system mint, which is the main purse. The balance associated with a given purse is recorded in global state, and the value can be queried using the query-balance command and the purse identifier, which can be a public key or account hash, implying the main purse of the given account should be used. Alternatively, the purse's URef can be used. For full details, run the following help command:

casper-client query-balance --help

Verify the source purse balance using the query-balance command:

casper-client query-balance \
--id 6 \
--node-address [NODE_SERVER_ADDRESS] \
--state-root-hash [STATE_ROOT_HAHS] \
--purse-identifier [SOURCE_PUBLIC_KEY_HEX]

Request fields:

  • id - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned
  • node-address - An IP address of a node on the network
  • state-root-hash - Hex-encoded hash of the state root
  • purse-identifier - A public key or account hash, implying the main purse of the given account should be used. Alternatively, the purse's URef

Query Source Account Example:

casper-client query-balance -v --id 6 \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1 \
--purse-identifier account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655
Explore the sample JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "query_balance",
"params": {
"state_identifier": {
"StateRootHash": "fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1"
},
"purse_identifier": {
"main_purse_under_account_hash": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655"
}
},
"id": 6
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"result": {
"api_version": "1.5.3",
"balance": "1109111876194"
},
"id": 6
}

Similarly, query the balance of the target purse.

casper-client get-balance \
--id 7 \
--node-address [NODE_SERVER_ADDRESS] \
--state-root-hash [STATE_ROOT_HAHS] \
--purse-identifier [TARGET_PUBLIC_KEY_HEX]

Target Account Example:

casper-client query-balance -v --id 7 \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1 \
--purse-identifier account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7
Explore the sample JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "query_balance",
"params": {
"state_identifier": {
"StateRootHash": "fdb1474d441ec0fcbf2e088f1630dbf98d3bcf7f7a7fe298303797f35b8cb4e1"
},
"purse_identifier": {
"main_purse_under_account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7"
}
},
"id": 7
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"result": {
"api_version": "1.5.3",
"balance": "46200000000"
},
"id": 7
}

Undelegating Tokens with the Casper Client

This document details a workflow where tokens delegated to a validator on a Casper network can be undelegated.

Prerequisites

  1. You meet all prerequisites, including having a valid node-address and the Casper command-line client
  2. You have delegated tokens to a validator on a Casper network and you have the validator's public key

Sending the Undelegation Request

There are two ways to undelegate CSPR from a validator. The recommended and cheaper method is to call the undelegate entry point from the system auction contract. The second method involves building the undelegate.wasm from the casper-node repository and installing it on the network.

We recommend testing the following steps on the official Testnet before performing them in a live environment like the Casper Mainnet.

Method 1: Undelegating with the System Auction Contract

This method calls the existing undelegate entry point from the system auction contract. Using this method, you do not need to build any contracts, reducing costs and complexity.

casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT_IN_MOTES> \
--session-hash <SESSION_HASH> \
--session-entry-point undelegate \
--session-arg "validator:public_key='<HEX_ENCODED_VALIDATOR_PULIC_KEY>'" \
--session-arg "amount:u512='<AMOUNT_TO_UNDELEGATE>'" \
--session-arg "delegator:public_key='<HEX_ENCODED_DELEGATOR_PULIC_KEY>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version 1.5.1
  5. session-hash - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:
  • Testnet: hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2
  • Mainnet: hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea
  1. session-entry-point - Name of the entry point that will be used when calling the contract

The undelegate entry point expects three arguments:

  1. validator: The hexadecimal public key of the validator from whom the tokens will be undelegated
  2. amount: The number of tokens to be undelegated
  3. delegator: The hexadecimal public key of the account undelegating tokens from a validator. This key must match the secret key that signs the delegation

The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the Deploy Status section for more details.

note

Calling the undelegate entry point on the auction contract has a fixed cost of 2.5 CSPR. There is no minimum amount required for the undelegation call.

Example:

This example shows an account delegating 100 CSPR:

casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--chain-name casper-test \
--secret-key ~/KEYS/secret_key.pem \
--payment-amount 2500000000 \
--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \
--session-entry-point undelegate \
--session-arg "validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'" \
--session-arg "amount:u512='100000000000'" \
--session-arg "delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'"

Next, confirm the undelegation.

Method 2: Undelegating with Compiled Wasm

As part of this process, you need to build the casper-node contracts that produce the undelegation Wasm.

Next, use the Casper CLI client to send a deploy containing the undelegate.wasm to the network to initiate the undelegation process.

casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT_IN_MOTES> \
--session-path <PATH_TO_WASM>/undelegate.wasm \
--session-arg "validator:public_key='<HEX_ENCODED_VALIDATOR_PULIC_KEY>'" \
--session-arg "amount:u512='<AMOUNT_TO_UNDELEGATE>'" \
--session-arg "delegator:public_key='<HEX_ENCODED_DELEGATOR_PULIC_KEY>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version 1.5.1
  5. session-path - The path to where the delegate.wasm is located

The undelegate entry point expects three arguments:

  1. validator: The hexadecimal public key of the validator from whom the tokens will be undelegated
  2. amount: The number of tokens to be undelegated
  3. delegator: The hexadecimal public key of the account undelegating tokens from a validator. This key must match the secret key that signs the delegation

The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the Deploy Status section for more details.

Example:

This example command uses the Casper Testnet to undelegate 100 CSPR, and the payment amount is 6 CSPR. The payment amount varies based on each deploy and network chainspec. However, notice that this method is more expensive than the previous one that calls the undelegate entry point.

casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--chain-name casper-test \
--secret-key ~/KEYS/secret_key.pem \
--payment-amount 6000000000 \
--session-path ~/undelegate.wasm \
--session-arg "validator:public_key='01aa17f7b9889480b1bd34c3f94f263b229c7a9b01dd4dda19c2dd1d38d176c7a0'" \
--session-arg "amount:u512='100000000000'" \
--session-arg "delegator:public_key='01e3d3392c2e0b943abe709b25de5c353e5e1e9d95c7a76e3dd343d8aa1aa08d51'"

Next, confirm the undelegation.

Verifying the Undelegation

To verify that the undelegation succeeded, you can use the Casper command-line client to generate an RPC request to query the auction state. The subsequent RPC response will confirm that the undelegation request was successfully processed.

Here is how you can check the status of the auction to confirm that your bid was withdrawn:

casper-client get-auction-info \
--node-address http://<peer-ip-address>:7777

Request fields:

  • node-address - An IP address of a node on the network

If the public key and the amount are absent from the bids structure, we can safely conclude that we have indeed undelegated from the validator.

If your account is on the official Testnet or Mainnet, you can use the block explorer to look up your account balance and see that the tokens have been added to your balance:

  1. Testnet explorer
  2. Mainnet explorer

Important Note: After undelegating tokens from a validator, you must wait for the unbonding period to lapse before redelegating tokens to either the same validator or a different validator.

What is a dApp?

A decentralized application (dApp) is an application with some data on a blockchain or similar peer-to-peer network.

The degree that a dApp interacts with the blockchain can vary greatly depending on the needs of the application. Some dApps may use the blockchain simply to store data, with most of the logic taking place off-chain. Others may depend on logic stored on the blockchain, with only the bare minimum user interface stored outside of the blockchain itself.

How are Decentralized Applications Different?

A decentralized system consists of a group of interchangeable machines that can perform as a full system or distributed database. Additional machines strengthen the overall system by adding redundancy and computational power.

Any dApp will need access to a decentralized network, in one form or another. In a Casper network, this means connecting to a node. The decentralized aspect creates a situation where each node is fundamentally interchangeable for this purpose. If the connected node fails, the dApp can switch to a different node and continue operating without losing data or functionality.

Routine operations in a decentralized network may result in nodes coming on or offline. This node churn can result in downtime for a decentralized application if it relies on a single node. It is necessary to connect to multiple nodes simultaneously to ensure high uptime, especially if you are not operating your own node.

Interacting with a Decentralized Network

For a dApp to integrate with a Casper network, it must be able to send Deploys via the JSON-RPC. Business logic specific to the dApp can then be executed on chain via the Deploy. Sending a Deploy to a node will result in that node gossiping that Deploy to other nodes, assuming that the Deploy is valid and accepted. The Deploy will then be enqueued for execution.

A Deploy contains session code in the form of Wasm to be executed in the context of the sending account. Therefore, developers may use any programming language that can compile to Wasm when building a dApp for a Casper network. This session code may consist of Wasm to be executed once, or Wasm which will install contract code to be stored in global state. If the dApp requires periodic execution of the same Wasm, it is more efficient from both a gas and execution perspective to install the Wasm as a contract to be called later.

Sending a Deploy is the only means by which a dApp can change global state. As gas costs operate on a per-byte basis, smart contracts will incur less gas costs over time when compared against executing the same session code repeatedly. A dApp may send a Deploy simultaneously to each node it is connected to, but can only do so once per node, per Deploy.

All associated changes to global state occur after successful execution of the Deploy. In the case of a failed execution, the stack is unwound and any changes to global state as part of executing the Deploy are reverted. However, as there is a penalty payment that must be incurred, there is a change in global state through reducing the balance of the sending account. To send a Deploy, an account must hold a minimum balance greater than the network's penalty payment. This penalty payment can vary from network to network. On the public Casper Mainnet, the penalty payment is set to 2.5 CSPR.

Unlike other blockchain networks, a Casper network performs execution after consensus. This means observing the execution of the Deploy is sufficient proof of finality for most cases. For a stronger finality requirement, you can observe the finality signatures for the block that includes the given Deploy.

There is an inherent timing consideration when sending a Deploy, from the point where it is sent to when it is executed. The Deploy Lifecycle results in a delay longer than would be expected from a centralized application. The Deploy must be sent, accepted, gossiped, included in a finalized block and executed. This process varies from network to network. This delay should be taken into consideration when designing dApps for use with a Casper network, as the number of connected peers and the number of Deploys currently being sent may cause it to increase.

Overview of Casper dApps

The following topics are essential for developers building decentralized applications on a Casper network.

TopicDescription
Introducing dAppsIntroducing dApps on a Casper network
Prerequisites for Building dAppsRecommended setup for building dApps on Casper
SDK Client LibrariesClient-side libraries providing ways to interact with a Casper network
dApp Technology StackBuilding the front-end, backend, and on-chain logic of a dApp
Front-end Template with ReactUse the Casper JS SDK with React to build a dApp fron-tend
Signing DeploysDetails about the signatures required for deploys
Setting up a Local Network with NCTLLearn to set up a local test network
Testing Smart Contracts with NCTLTest deploys locally before sending them to a Casper network
Monitoring and Consuming EventsHow dApps can listen for emitted events and perform actions based on event data

Monitoring and Consuming Events

The Casper platform uses event streaming to signal state changes in smart contracts and nodes. Using Casper's client-side SDKs, dApps actively listening for emitted events can consume these events and perform actions based on event data.

Each Casper node streams events through the SSE (Server Sent Event) server via the port specified as the event_stream_server.address in the node's config.toml. This port is by default 9999 for nodes on Testnet and Mainnet.

Events are divided into three categories and streamed on their respective endpoints:

  • Deploy events - Associated with Deploys on a node. Currently, only a DeployAccepted event is emitted. The URL to consume deploy-related events on Mainnet and Testnet is http://<HOST>:9999/events/deploys/.
  • Finality Signature events - Emitted when a block has been finalized and cannot be altered. The URL to consume finality signature events on Mainnet and Testnet is http://<HOST>:9999/events/sigs/.
  • Main events - All other events fall under this type, including: BlockAdded, DeployProcessed, DeployExpired, Fault, Step, and Shutdown events. The URL to consume these events on Mainnet and Testnet is http://<HOST>:9999/events/main/.
note

An ApiVersion event is always emitted when a new client connects to a node's SSE server, informing the client of the node's software version.

Listening to the Event Stream

Applications can listen for such events for a specific account during a particular era, containing certain data. Then, they can parse the data and discard what they do not need. To consume the event stream, set up an event listener in your dApp using the following code:

const { EventStream, EventName } = require("casper-js-sdk");

const es = new EventStream("http://NODE_ADDRESS:9999/events/" + CHANNEL);
es.start();
es.subscribe(EventName.EVENT_NAME, eventHandler);

const eventHandler = (event) => {
console.log(event);
};

You can find node addresses of active online peers to replace NODE_ADDRESS, by navigating to cspr.live for Mainnet and testnet.cspr.live for Testnet.

Replace EVENT_NAME with one of the event types listed below.

Replace CHANNEL with one of the following event streams:

  • main for ApiVersion, BlockAdded, DeployExpired, DeployProcessed, Fault, or Step events.
  • deploys for DeployAccepted events.
  • sigs for FinalitySignature events.

Event Types

ApiVersion

The ApiVersion event is always the first event emitted when a new client connects to a node's SSE server. It specifies the protocol version of a node on the Casper platform. The following example contains the JSON representation of the ApiVersion event structure.

data:{"ApiVersion":"1.0.0"}

BlockAdded

A BlockAdded event is emitted when a new block is added to the blockchain and stored locally in the node.

Expand to view output
{
"BlockAdded": {
"block_hash": "62ddf902e9b6988b978413e2a9a2c6c95f8e1ddf452afd8e8a68f0ac22bf391a",
"block": {
"hash": "62ddf105e9b6988b378413e2a9a2c6c95f8e1ddf458afd8e8268f0ac72bfe91a",
"header": {
"parent_hash": "ed11ac2117edb9c5b26cf0cde318a807fd68e76206855a70429012ef16b557f5",
"state_root_hash": "3c1ad31757ae40f934de4825a818274e0c246d304c661daf656e22b65174ad66",
"body_hash": "eb2344f37193395bbc83587e498bc12ad5f0019055abcfa4c3b989d382a7969a",
"random_bit": true,
"accumulated_seed": "b8b671530f2221c8fdf201083f43c51e215e2f6ffcbe2d63238a2779eb177922",
"era_end": null,
"timestamp": "2023-01-01T09:55:25.312Z",
"era_id": 8426,
"height": 1566677,
"protocol_version": "1.4.13"
},
"body": {
"proposer": "010e5669b0f0545e2b32bc66363b9d3d4390fca56bf52305f1411b7fa12ca311c7",
"deploy_hashes": [],
"transfer_hashes": []
},
"proofs": []
}
}
}
  • block_hash - The cryptographic hash that identifies a block.
  • block - The JSON representation of the block.
  • proposer - The validator selected to propose the block.

DeployAccepted

DeployAccepted events are emitted when a node on the network receives a deploy.

Expand to view output
{
"DeployAccepted": {
"hash": "db84ba229ea37716230ac9874f66c0f12b9731d8d42f28060e481ef3d7263ead",
"header": {
"account": "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c",
"timestamp": "2023-01-01T20:22:45.383Z",
"ttl": "30m",
"gas_price": 1,
"body_hash": "8a377b07a01ac23905b2e416ff388508301feffbb9bdf275c59f87be1e9d0de5",
"dependencies": [],
"chain_name": "casper-test"
},
"payment": {
"ModuleBytes": {
"module_bytes": "",
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "040008af2f",
"parsed": "800000000"
}
]
]
}
},
"session": {
"StoredContractByHash": {
"hash": "1040f40d06f0355a80149befc4b5d1f203231231d66c4903688e178c36066539",
"entry_point": "test_entry_point",
"args": [
[
"cost",
{
"cl_type": "U512",
"bytes": "0500c817a804",
"parsed": "20000000000"
}
]
]
}
},
"approvals": [
{
"signer": "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c",
"signature": "01d81d4dc9504a356c23d3c161b87b39b1708cd282b59d3e44d9b999e787643ab495f168475bed8dc48d1056605e06c8ba74d96c69ae5b506c4312be8871c0c701"
}
]
}
}
  • hash - The blake2b hash of the Deploy.
  • account - The hexadecimal-encoded public key of the account submitting the Deploy.
  • body_hash - The blake2b hash of the Deploy body.
  • payment - Gas payment information.
  • session - The session logic defining the Deploy's functionality.
  • approvals - The signer's hexadecimal-encoded public key and signature.

For details on custom serializations, check the Serialization Standard. Also, the Types page defines the terms used in the event stream output.

DeployProcessed

A DeployProcessed event is emitted when a given Deploy has been executed.

Expand to view output
{
"DeployProcessed": {
"deploy_hash": "0f33be8f56ff23d7d503a9804675472e043830a6c17e6141dce717b4f0973c7d",
"account": "0201cbff12155b6ae1e99d571c01d56e9e1ba0def6719a6f06bc3e4a08f30a887444",
"timestamp": "2023-01-01T10:07:00.401Z",
"ttl": "30m",
"dependencies": [],
"block_hash": "509b754648168a73e6ab67e64d4a783cf580d6fc0c7c0ec560c6650f717841e0",
"execution_result": {
"Success": {
"effect": {
"operations": [],
"transforms": [
{
"key": "account-hash-a8261377ef9cf8e7411d6858801c71e28c9322e66355586549c75ab24cdd73f2",
"transform": "Identity"
}
]
},
"transfers": ["transfer-3389144d15238240f48f5966f2dc299b6b20eb19c13d834409b4d28fc50fa909"],
"cost": "100000000"
}
}
}
}
  • deploy_hash - The cryptographic hash of a Deploy.
  • account - The hexadecimal-encoded public key of the account submitting the Deploy.
  • timestamp - A timestamp type representing a concrete moment in time.
  • dependencies - A list of Deploy hashes.
  • block_hash - A cryptographic hash identifying a Block.
  • execution_result - The execution status of the Deploy, which is either Success or Failure.

DeployExpired

A DeployExpired event is emitted when the Deploy is no longer valid for processing or being added to a block due to its time to live (TTL) having expired.

Expand to view output
{
"DeployExpired": {
"deploy_hash": "7ecf22fc284526d6db16fbf455f489e0a9cbf782234131c010cf3078fb9be353"
}
}

Fault

The Fault event is emitted if there is a validator error.

Expand the below section to view the Fault event details:
{
"Fault": {
"era_id": 4591448806312642600,
"public_key": "013da85eb06279da42e28530e1116be04bfd2aa25ed8d63401ebff4d9153a609a9",
"timestamp": "2023-01-01T01:26:58.364Z"
}
}
  • era_id - A period of time during which the validator set does not change.
  • public_key - The hexadecimal-encoded public key of the validator that caused the fault.
  • timestamp - A timestamp representing the moment the validator faulted.

FinalitySignature

This event indicates validators have signed the final approvals and further alterations to the block will not be allowed. Refer to the consensus reached and block finality sections to learn more about finality signatures.

Expand to view output
{
"FinalitySignature": {
"block_hash": "eceed827e11f7969a7d3fe91d6fa4ce9749dd79d9f3ea26474fe2014db90e98d",
"era_id": 8419,
"signature": "0117087ef4b9a786e5a0ea8f198050e9de93dd94f87469b8124c346aeae5f36ad9adf80f670ee9c5887263267ed32cf932dce9b370353c596d59f91fbd57a1a205",
"public_key": "01c375b425a36de25dc325c9182861679db2f634abcacd9ae2ee27b84ba62ac1f7"
}
}
  • block_hash - A cryptographic hash identifying a Block.
  • era_id - A period of time during which the validator set does not change.
  • signature - Serialized bytes representing the validator's signature.
  • public_key - The hexadecimal-encoded public key of the validator.

Step

The Step event is emitted at the end of every era and contains the execution effects produced by running the auction contract's step function.

Expand to view output:
{
"Step": {
"era_id": 1,
"execution_effect": {
"operations": [],
"transforms": [
{
"key": "uref-53df18bf01396fbd1ef3a8757c7bdffc684c407d90f2cfeebff166db1d923613-000",
"transform": "Identity"
},
{
"key": "uref-f268de37fcea55f8fb1abeba8536a1cc041b2aed2691f1cf34aeaaf0ae379aa5-000",
"transform": "Identity"
},
{
"key": "bid-278e5af1ca6cddf5d5438999cb072b47f0d65e1484799f692c3c9c40304be30e",
"transform": "Identity"
},
{
"key": "bid-278e5af1ca6cddf5d5438999cb072b47f0d65e1484799f692c3c9c40304be30e",
"transform": {
"WriteBid": {
"validator_public_key": "0133eaae2821f090ac3ba0eadc0a897742094c0604df72b465c41d4b773298a7b9",
"bonding_purse": "uref-136552c255d4d737bf7e43d2be250f9f38691b9fe5d9e34446bff18d6d1cf984-007",
"staked_amount": "1000000000000005",
"delegation_rate": 5,
"vesting_schedule": {
"initial_release_timestamp_millis": 1664475057182,
"locked_amounts": null
},
"delegators": {
"012a241eaa9fa3bd6ccb0e0aaaf4658538f3540e04e2f58973614a168f2f2f813d": {
"delegator_public_key": "012a241eaa9fa3bd6ccb0e0aaaf4658538f3540e04e2f58973614a168f2f2f813d",
"staked_amount": "51312014671568117976319379",
"bonding_purse": "uref-c5ad00f9e6b2f2631ca647ad188187e63799a278a0a46ca25f6b4da64d556662-007",
"validator_public_key": "0133eaae2821f090ac3ba0eadc0a897742094c0604df72b465c41d4b773298a7b9",
"vesting_schedule": {
"initial_release_timestamp_millis": 1664475057182,
"locked_amounts": null
}
}
},
"inactive": false
}
}
}
]
}
}
}
  • era_id - A period of time during which the validator set does not change.
  • execution_effect - The journal of execution transforms from a single Deploy.
  • operations - Operations performed while executing a Deploy.
  • transform - The actual transformation performed while executing a Deploy.

Shutdown

The Shutdown event is emitted when the node is about to shut down, usually for an upgrade, causing a termination of the event stream.

Expand the below section to view the Shutdown event details:
"Shutdown"
  • Shutdown - The "Shutdown" text notifies the event listener that a shutdown will occur.

Reacting to Events

An application may parse each event needed for its use case and respond accordingly. The dApp may act on some events and not others, or it may act upon them all, depending on its use case. Each event type contains additional data that might help in deciding whether or not to take an action. For example, DeployAccepted events contain the account's public key that submitted the deploy, the contract address, and more. This information can help determine how to proceed or whether or not to react.

const eventHandler = (event) => {
if (event.body.DeployAccepted.header.account == "012481699f9231e36ecf002675cd7186b48e6a735d10ec1b30f587ca716937752c") {
// Perform an action
}
};

Unsubscribing from Events

In many cases, an application may need to unsubscribe after a certain time or may want to unsubscribe from some events but not others. The Casper SDKs provide this ability with the unsubscribe function:

es.unsubscribe(EventName.EVENT_NAME);
  • EVENT_NAME - One of the different event types emitted by a Casper node.

Stopping the Event Stream

A dApp may cease listening to all events using the stop function:

es.stop();

Replaying the Event Stream

This command will replay the event stream from an old event onward. Replace the NODE_ADDRESS, CHANNEL, and ID fields with the values of your scenario.

curl -sN http://NODE_ADDRESS:9999/events/CHANNEL?start_from=ID

Example:

curl -sN http://65.21.235.219:9999/events/main?start_from=29267508

Each URL can have a query string added to the form ?start_from=ID, where ID is an integer representing an old event ID. With this query, you can replay the event stream from that old event onward. If you specify an event ID already purged from the cache, the server will replay all the cached events.

note

The server keeps only a limited number of events cached to allow replaying the stream to clients using the ?start_from= query string. The cache size can be set differently on each node using the event_stream_buffer_length value in the config.toml. By default, it is only 5000. The intended use case is to allow a client consuming the event stream that loses its connection to reconnect and catch up with events that were emitted while it was disconnected.

Testing Smart Contracts with NCTL

NCTL effectively simulates a live Casper network. The process for sending a Deploy to an NCTL-based network is therefore similar to doing so on a live network.

Testing Deploys prior to sending them to a Casper network ensures that they operate as intended. When working in an environment that requires payment for execution, errors and inefficiencies quickly add up. To this end, Casper provides several layers of testing to identify and rectify any errors. After writing your smart contract and testing it using the provided framework, NCTL serves as the next step in the process. While testing is entirely optional, it should be considered a best practice to avoid paying for the execution of faulty code.

Getting Started with NCTL

Prior to testing a Deploy through NCTL, you should have the following steps accomplished:

  1. Completed writing a Deploy

  2. Tested the Deploy using the Casper testing framework

  3. Setup NCTL on your system

NCTL Verification Prior to Testing

Prior to attempting an NCTL test, you must verify that your local NCTL instance started correctly. Run the following command to view your current node status:

nctl-status

You should see five nodes RUNNING and five STOPPED. Further, verify that the node and user information propagated within the casper-node/utils/assets directory. Each node and user should have the associated Keys necessary to interact with the network. Run the following command to view first user details:

nctl-view-user-account user=1

Installing the Smart Contract

This document assumes that you setup your NCTL network using the standard settings in a directory called /casper/.

You will need the following information to use the put-deploy command:

  • The chain name, in this case casper-net-1. This will appear in our example put-deploy as --chain-name "casper-net-1"

  • The secret key of the account sending the Deploy. For this example, we are using node-1 as the sender. The secret key file can be found at casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem. In our example put-deploy, this will appear as --secret-key /casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem. If your Deploy is more complex and requires multiple accounts, NCTL also establishes multiple users for testing.

  • The payment amount in motes, which should be sufficient to avoid an 'Out of Gas' error. The payment amount will appear in our example put-deploy as --payment-amount 2500000000. NCTL tests are not an accurate representation of potential gas costs on a live network. Please see our note about gas prices.

  • The path to your Deploy that you wish to send to the NCTL network. This will appear in our example put-deploy as --session-path <PATH> and will require you to define the path to your specific Deploy Wasm.

  • The node address for a node on your NCTL network. In this example, we are using the node at http://localhost:11101. On the Casper Mainnet or Testnet, nodes will use port 7777. This will appear in our example put-deploy as --node-address http://<HOST>:7777.

The command to send your Deploy should look similar to the following code snippet:

note

Use of the $(get_path_to_client) command assumes that you are operating in an activated NCTL envrionment.

$(get_path_to_client) put-deploy \
--chain-name "casper-net-1" \
--secret-key /casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem \
--payment-amount 2500000000 \
--session-path <PATH> \
--node-address http://localhost:11101

The response will return something similar to the following information. Note the deploy_hash:

{
"id": 4824893960188648146,
"jsonrpc": "2.0",
"result": {
"api_version": "1.0.0",
"deploy_hash": "8e6309cc37bc58d8fedc1094ee1bd264a636d39fc0e05b5e1d72d98f7b6faf13"
}
}

Verifying Deploy Execution

The previous command sent the Deploy to the NCTL network, but we recommend verifying deploy execution before continuing. The deploy_hash received in the response allows you to query the Deploy's status.

To query the Deploy's status, you will pass both the deploy_hash and the same node-address from above using the following command. This will return either an error message in the event of failure or the Deploy details if it succeeds.

$(get_path_to_client) get-deploy 8e6309cc37bc58d8fedc1094ee1bd264a636d39fc0e05b5e1d72d98f7b6faf13 -n http://localhost:11101

Interacting with the Installed Contract

Once your NCTL network executes your Deploy, you can test the functionality of the installed contract. To do so, you will first need to identify any arguments to pass to the contract, starting with the ContractHash itself. This hash identifies the contract and allows you to target the included entry points. As we used the pre-established node-1 account to send the Deploy, we can retrieve the ContractHash from the node-1 account information. To do so, we will use the following command with a node address and the PublicKey of the node in question.

$(get_path_to_client) get-account-info \
--node-address http://localhost:11101 \
--public-key /casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/public_key.pem

This command will return information pertaining to the account, including the NamedKeys. The ContractHash of the contract to be tested will appear here. The process of calling the contract is similar to that of installing it, as they are both accomplished through sending a Deploy. In this instance, you will need the following information:

  • The node address, entered in this instance using --node-address http://localhost:11101

  • The chain name, entered in this instance using --chain-name "casper-net-1"

  • The payment amount for this Deploy in motes, which may need to be adjusted depending on cost and network chainspec. In this instance, we will use --payment-amount 500000000

  • The session path, defining the location of the Wasm bearing file for the Deploy. It appears in our example as --session-path <PATH> but you must define the path to your specific file.

  • Any session arguments specific to the contract that you are testing. Multiple instances of --session-arg may be used as necessary to provide values to the contract, including the ContractHash you acquired above. In the example below, you will see a demonstration of the ContractHash as a session argument as --session-arg "contract_key:key='hash-8c13aaeef50ae7f447ee21276965c31cfa45c4ea3abb03d35d078cdd6a40e4a'"

$(get_path_to_client) put-deploy \
--node-address http://localhost:11101 \
--chain-name "casper-net-1" \
--payment-amount 500000000 \
--session-path <PATH> \
--session-arg "contract_key:key='hash-8c13aaeef50ae7f447ee21276965c31cfa45c4ea3abb03d35d078cdd6a40e4a'"

Verifying Correct Contract Behavior

After calling your installed contract, you can verify that the contract behaved as expected by observing the associated change in global state. Depending on how your contract functions, this can have different meanings and results. If we use our donation contract from the basic smart contract tutorial, the NCTL process would have the following flow:

  1. Send a Deploy to install the "Donation" smart contract.

  2. Verify the execution of the Deploy.

  3. Interact with the installed contract using an additional Deploy that calls one or several of the entry points. For example, calling the donate entry point to donate an amount to the fundraising purse.

  4. Verify the associated change in global state. Namely, an increase in the balance of the fundraising purse.

Prerequisites

Before trying your hand at dApp development on a Casper network, there are a few things you should do first:

  1. Set up your development environment.

  2. Be sure you understand the language(s) you are developing in.

    Before beginning with one or more of the SDKs, ensure that you are familiar with the underlying language itself. There are many guides and tutorials available online to help you.

    The preferred stack for building on Casper is JavaScript using the Casper JS SDK, however there are many more SDKs available for a variety of different programming languages. Read about and examine the other available SDKs in the Introduction to SDKs.

  3. Familiarize yourself with the fundamentals of Casper networks.

    Casper networks are Proof-of-Stake smart contract blockchains written in Rust. Their architecture, from how they validates transactions to how they reach consensus, should be well understood before developing dApps that interact with them. Read up on Casper network design principles in the design section.

  4. Read the documentation or source code of your chosen SDK.

    Many of the Casper SDKs have documentation available to help you get a full grasp of their functions and methods. In some cases, documentation is written in the source files and rendered using a markup language. Check the repository of your preferred SDK(s) for links to documentation. There are also universal guides to teach you how to perform different functionalities using any of the available SDKs, see Client Library Usage.

Development Considerations

When developing a public dApp for a Casper network, it is important to keep security in mind and write your smart contract(s) and interface(s) with caution and care, especially if your dApp interacts with tokens of value.

To ensure the highest level of security, consider the following practices:

  1. Code review and auditing: Have your smart contracts and interfaces thoroughly reviewed and audited by experienced professionals. This will help identify any vulnerabilities, bugs, or potential exploits in your code.
  2. Implement best practices: Adhere to industry best practices in smart contract and dApp development. This includes following established design patterns, using secure coding techniques, and staying updated on the latest vulnerabilities and attack vectors.
  3. Testing and simulation: Conduct rigorous testing and simulation of your smart contracts and interfaces. This will help uncover any potential issues or weaknesses before deploying them on the mainnet.
  4. Plan for upgrades and bug fixes: Design your smart contracts to take advantage of Casper's support for smart contract upgradability. By doing so, you can ensure that your dApp remains secure and adaptable as the Casper ecosystem evolves, enabling seamless integration of future upgrades and bug fixes.
  5. Monitor and maintain: Regularly monitor your dApp's performance and security once it is deployed. This will help you quickly identify and address any potential threats or vulnerabilities.
  6. Educate users: Provide clear documentation and guidance to your dApp users, helping them understand how to use your application securely and effectively.

By taking these precautions and focusing on security throughout the development process, you can minimize risks and build a more robust and reliable dApp for the Casper Network.

SDK Client Library Usage

Installing the SDKs

Use npm or yarn to install the casper-js-sdk package:

npm install casper-js-sdk
yarn install casper-js-sdk

Creating Accounts

You may use the SDKs to interact with accounts on a Casper network. Accounts can use either an Ed25519 or Secp256k1 digital signature scheme. See the Accounts and Cryptographic Keys page for more details.

Creating new account keys

const { Keys } = require("casper-js-sdk");
const keypair = Keys.Ed25519.new();
const { publicKey, privateKey } = keypair;

Replace Ed25519 with Secp256K1 if you wish.

Exporting the public key and account hash

The keypair variable contains the private and public key pair for the account. You can use, read, or export the public key. You may also want access to the account hash, often used within smart contracts on a Casper network. The following methods show how to extract the public key and account hash.

// Create a hexadecimal representation of the public key and account hash.
const publicKeyHex = publicKey.toHex();
const accountHashHex = publicKey.toAccountHashStr();

Note that accountHashHex will be prefixed with the text "account-hash-".

Uploading the secret key from a file

To use a specific account, you should not include the private key in the source code; instead, upload the account's secret key from a local file. Update the path to the file in the example below.

const { Keys } = require("casper-js-sdk");
const keypair = Keys.Ed25519.loadKeyPairFromPrivateFile("./secret_key.pem");

Replace Ed25519 with Secp256K1 if you wish.


Transferring CSPR

Using the keypair created above, you can sign a deploy that transfers CSPR.

Replace the NODE_ADDRESS and corresponding RPC port with an active node on the network. You can find active online peers for Mainnet on cspr.live and for Testnet on testnet.cspr.live. The RPC port is usually 7777, but it depends on the network's configuration settings.

const { CasperClient, DeployUtil } = require("casper-js-sdk");

const casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");
const receipientPublicKeyHex = "01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c";

const amount = 2.5e9; // Minimum transfer: 2.5 CSPR
let deployParams = new DeployUtil.DeployParams(
keypair.publicKey,
"casper", // or "casper-test" for Testnet
);

const session = DeployUtil.ExecutableDeployItem.newTransferWithOptionalTransferId(amount, recipientPublicKeyHex);

const payment = DeployUtil.standardPayment(0.1e9); // Gas payment in motes: 0.1 CSPR
const deploy = DeployUtil.makeDeploy(deployParams, session, payment);
const signedDeploy = DeployUtil.signDeploy(deploy, keypair);

console.log(await casperClient.putDeploy(signedDeploy));

Once submitted, the above snippet will print the deploy hash in the console.


Installing Contracts

To install a contract on the network, you need to sign and send a deploy containing the compiled Wasm.

Replace the NODE_ADDRESS and corresponding RPC port with an active node on the network. You can find active online peers for Mainnet on cspr.live and for Testnet on testnet.cspr.live. The RPC port is usually 7777, but it depends on the network's configuration settings.

const { CasperClient, Contracts, RuntimeArgs, CLValueBuilder } = require("casper-js-sdk");
const fs = require("fs");

const casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");
const contract = new Contracts.Contract(casperClient);

const contractWasm = new Uint8Array(fs.readFileSync("/path/to/contract.wasm").buffer);

const runtimeArguments = RuntimeArgs.fromMap({
argument: CLValueBuilder.string("Hello world!"),
});

const deploy = contract.install(
contractWasm,
runtimeArguments,
"10000000000", // Gas payment (10 CSPR)
keypair.publicKey,
"casper", // or "casper-test" for Testnet
[keypair],
);

console.log(await casperClient.putDeploy(deploy));

Once submitted, the above snippet will print the deploy hash in the console.

Staking

Token staking is a fundamental aspect of the Casper Network, whereby users lock up tokens as collateral in exchange for the ability to participate in the blockchain's consensus mechanism and earn rewards. This delegated Proof-of-Stake consensus mechanism is crucial for the network's effective operation. With the aid of any of the Casper SDKs, you can delegate your tokens to validators and participate in staking on the network.

The delegation functionality is available as a smart contract, which can be found in the casper-node repository. To delegate tokens, first clone the repository:

git clone https://github.com/casper-network/casper-node.git
cd casper-node/

Then compile the delegate contract:

make setup-rs
make build-contract-rs/delegate

Now, assuming that you cloned casper-node from your project's root directory, cd back into it:

cd ../

Now in your dApp's backend (or standalone script), load the delegate.wasm file into memory and deploy it with the arguments "amount", "delegator", and "validator" included.

const { CasperClient, Contracts, RuntimeArgs, CLValueBuilder, CLPublicKey } = require("casper-js-sdk");
const fs = require("fs");

const casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");
const contract = new Contracts.Contract(casperClient);

const contractWasm = new Uint8Array(fs.readFileSync("./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm").buffer);

const runtimeArguments = RuntimeArgs.fromMap({
amount: CLValueBuilder.u512(500e9), // Minimum delegation amount: 500 CSPR
delegator: keypair.publicKey,
validator: CLPublicKey.fromHex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c"),
});

const deploy = contract.install(
contractWasm,
runtimeArguments,
"5000000000", // Gas payment (5 CSPR)
keypair.publicKey,
"casper", // or "casper-test" for testnet
[keypair],
);

(async () => {
console.log(await casperClient.putDeploy(deploy));
})();

Once submitted, the above snippet will print the deploy hash in the console.


Calling Contracts

Smart contracts on a Casper network are invoked by calling entry points. See below how to use Casper's SDKs to interact with these entry points and update the global state from a dApp:

const casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");
const contract = new Contracts.Contract(casperClient);
contract.setContractHash("hash-a3cac24aec9de1bbdb87083587b14d8aeffba5dfed27686512b7bb5dee60445d");
const runtimeArguments = RuntimeArgs.fromMap({
message: CLValueBuilder.string("Hello world!"),
});
const deploy = contract.callEntrypoint(
"update_msg",
runtimeArguments,
keypair.publicKey,
"casper", // or "casper-test" for Testnet
"1000000000", // 1 CSPR (10^9 Motes)
[keypair],
);
(async () => {
console.log(await casperClient.putDeploy(deploy));
})();

Once submitted, the above snippet will print the deploy hash in the console.


Staking

Token staking is a fundamental aspect of a Casper network, whereby users lock up tokens as collateral in exchange for the ability to participate in the blockchain's consensus mechanism and earn rewards. This delegated Proof-of-Stake consensus mechanism is crucial for the network's effective operation. With the aid of any of the Casper SDKs, you can delegate your tokens to validators and participate in staking on the network.

The delegation functionality is available as a smart contract, which can be found in the casper-node repository. To delegate tokens, first clone the repository:

git clone https://github.com/casper-network/casper-node.git
cd casper-node/

Then compile the delegate contract:

make setup-rs
make build-contract-rs/delegate

Now, navigate back to your project's root directory. In your dApp's backend (or standalone script), load the delegate.wasm file into memory and deploy it with the arguments "amount", "delegator", and "validator" included.

const { CasperClient, Contracts, RuntimeArgs, CLValueBuilder, CLPublicKey } = require("casper-js-sdk");
const fs = require("fs");

const casperClient = new CasperClient("http://NODE_ADDRESS:7777/rpc");
const contract = new Contracts.Contract(casperClient);

const contractWasm = new Uint8Array(fs.readFileSync("./casper-node/target/wasm32-unknown-unknown/release/delegate.wasm").buffer);

const runtimeArguments = RuntimeArgs.fromMap({
amount: CLValueBuilder.u512(500e9), // Minimum delegation amount: 500 CSPR
delegator: keypair.publicKey,
validator: CLPublicKey.fromHex("01e8c84f4fbb58d37991ef373c08043a45c44cd7f499453fa2bd3e141cc0113b3c"),
});

const deploy = contract.install(
contractWasm,
runtimeArguments,
"5000000000", // Gas payment (5 CSPR)
keypair.publicKey,
"casper", // or "casper-test" for testnet
[keypair],
);

(async () => {
console.log(await casperClient.putDeploy(deploy));
})();

Once submitted, the above snippet will print the deploy hash in the console.

.NET SDK

The C# .NET SDK allows developers to interact with a Casper network using C#.

Documentation

Visit https://make-software.github.io/casper-net-sdk/ to find the SDK documentation, examples, and tutorials.

Get started

This example shows how to retrieve an account's main purse balance from a testnet node. Make sure you have .NET 5 or higher before continuing.

Open a terminal window and create a new console app:

dotnet new console -o GetAccountBalance
cd GetAccountBalance

The Casper.Network.SDK for .NET is published on nuget.org as a NuGet package.

To add a reference to the SDK in your project, use the Package Manager in Visual Studio or the dotnet CLI tool.

Package Manager (Windows)

Install-Package Casper.Network.SDK

dotnet CLI Tool (Windows, Mac, and Linux)

dotnet add package Casper.Network.SDK

Now, replace the default code in Program.cs with this main program:

using System;
using System.Threading.Tasks;
using Casper.Network.SDK;
using Casper.Network.SDK.JsonRpc;
using Casper.Network.SDK.Types;

namespace Casper.NET.SDK.Examples
{
public class GetAccountBalance
{
public static async Task Main(string[] args)
{
string nodeAddress = "http://testnet-node.make.services:7777";

var hex = "0203914289b334f57366541099a52156b149436fdb0422b3c48fe4115d0578abf690";
var publicKey = PublicKey.FromHexString(hex);

try
{
var casperSdk = new NetCasperClient(nodeAddress);

// Get the balance using the account public key
//
var rpcResponse = await casperSdk.GetAccountBalance(publicKey);
Console.WriteLine("Public Key Balance: " + rpcResponse.Parse().BalanceValue);
}
catch (RpcClientException e)
{
Console.WriteLine("ERROR:\n" + e.RpcError.Message);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
}

Finally, run the example with:

dotnet run

The program will print the account's main purse balance retrieved from the testnet.

Visit https://make-software.github.io/casper-net-sdk/ to find other examples, tutorials, and complete documentation for this SDK.

Go SDK

Usage Examples

This section includes some examples of how to use Go SDK:

Get a Deploy from the Network

package main

import (
"context"
"fmt"
"net/http"

"github.com/make-software/casper-go-sdk/casper"
)

func main() {
handler := casper.NewRPCHandler("https://<Node Address and Port>/rpc", http.DefaultClient)
client := casper.NewRPCClient(handler)
deployHash := "62972eddc6fdc03b7ec53e52f7da7e24f01add9a74d68e3e21d924051c43f126"
deploy, err := client.GetDeploy(context.Background(), deployHash)
if err != nil {
return
}
fmt.Println(deploy.Deploy.Hash)
}

Handle the Deploy Processed Event

package main

import (
"context"
"log"

"github.com/make-software/casper-go-sdk/sse"
)

func main() {
client := sse.NewClient("https://<Node Address and Port>/events/main")
defer client.Stop()
client.RegisterHandler(
sse.DeployProcessedEventType,
func(ctx context.Context, rawEvent sse.RawEvent) error {
deploy, err := rawEvent.ParseAsDeployProcessedEvent()
if err != nil {
return err
}
log.Printf("Deploy hash: %s", deploy.DeployProcessed.DeployHash)
return nil
})
lastEventID := 1234
client.Start(context.TODO(), lastEventID)
}

Sending a Transfer

package main

import (
"context"
"encoding/hex"
"log"
"math/big"
"net/http"

"github.com/make-software/casper-go-sdk/casper"
"github.com/make-software/casper-go-sdk/types/clvalue"
)

func main() {
accountPublicKey, err := casper.NewPublicKey("012488699f9a31e36ecf002675cd7186b48e6a735d10ec1b308587ca719937752c")
if err != nil { return }
amount := big.NewInt(100000000)
session := casper.ExecutableDeployItem{
ModuleBytes: &casper.ModuleBytes{
ModuleBytes: hex.EncodeToString([]byte("<Contract WASM>")),
Args: (&casper.Args{}).
AddArgument("target", clvalue.NewCLByteArray(accountPublicKey.AccountHash().Bytes())).
AddArgument("amount", *clvalue.NewCLUInt512(amount)),
},
}

payment := casper.StandardPayment(amount)

deployHeader := casper.DefaultHeader()
deployHeader.Account = accountPublicKey
deployHeader.ChainName = "casper-test"

newDeploy, err := casper.MakeDeploy(deployHeader, payment, session)

handler := casper.NewRPCHandler("https://<Node Address>:7777/rpc", http.DefaultClient)
client := casper.NewRPCClient(handler)
result, err := client.PutDeploy(context.Background(), *newDeploy)

log.Println(result.DeployHash)
}

Python SDK

The Python SDK allows developers to interact with the Casper Node using Python 3.9+. This page covers various examples of using this SDK.

Installation

Before installing the library, you need to install dependencies from requirements.txt, which you can perform by running the following command:


pip install -r requirements.txt

Finally, to install the library, run:


pip install pycspr

Tests

You can find examples of testing this library with python scripts in the test directory. To run the tests, we recommend the pytest library:

    pytest ./tests

Usage Examples

In this section, we outline a couple of essential tasks you can accomplish with the Python SDK:

For further examples, take a look at the How-tos.

Sending a transfer

This example shows you how to define and transfer funds between purses on a Casper network. Replace the path_to_cp2_account_key in the code below with the receiver's account public key.

    import os
import pathlib
import random
import typing

import pycspr
from pycspr.client import NodeClient
from pycspr.client import NodeConnectionInfo
from pycspr.crypto import KeyAlgorithm
from pycspr.types import PrivateKey
from pycspr.types import Deploy
from pycspr.types import PublicKey

# path to cp1 secret key - defaults to NCTL user 1.
path_to_cp1_secret_key = pathlib.Path(os.getenv("NCTL")) / "assets" / "net-1" / "users" / "user-1" / "secret_key.pem"

# type of cp1 secret key - defaults to ED25519.
type_of_cp1_secret_key = KeyAlgorithm.ED25519.name,

# path to cp2 account key - defaults to NCTL user 2.
path_to_cp2_account_key = pathlib.Path(os.getenv("NCTL")) / "assets" / "net-1" / "users" / "user-2" / "public_key_hex"

# name of target chain - defaults to NCTL chain.
chain_name = "casper-net-1"

# host address of target node - defaults to NCTL node 1.
node_host = "localhost"

# Node API JSON-RPC port - defaults to 11101 @ NCTL node 1.
node_port_rpc = 11101

def _main(node_host, node_port_rpc, path_to_cp1_secret_key, type_of_cp1_secret_key,path_to_cp2_account_key, chain_name):
"""Main entry point.
:param args: Parsed command line arguments.
"""
# Set node client.
client = _get_client(node_host, node_port_rpc)

# Set counter-parties.
cp1, cp2 = _get_counter_parties(path_to_cp1_secret_key, type_of_cp1_secret_key,path_to_cp2_account_key)

# Set deploy.
deploy: Deploy = _get_deploy(chain_name, cp1, cp2)

# Approve deploy.
deploy.approve(cp1)

# Dispatch deploy to a node.
client.deploys.send(deploy)

#If deploy is successful send the indication
print(f"Deploy dispatched to node [{node_host}]: {deploy.hash.hex()}")


def _get_client(node_host, node_port_rpc) -> NodeClient:
"""Returns a pycspr client instance.
"""
return NodeClient(NodeConnectionInfo(
host=node_host,
port_rpc=node_port_rpc,
))


def _get_counter_parties(path_to_cp1_secret_key, type_of_cp1_secret_key,path_to_cp2_account_key) -> typing.Tuple[PrivateKey, PublicKey]:
"""Returns the 2 counter-parties participating in the transfer.
"""
cp1 = pycspr.parse_private_key(
path_to_cp1_secret_key,
type_of_cp1_secret_key,
)
cp2 = pycspr.parse_public_key(
path_to_cp2_account_key
)

return cp1, cp2


def _get_deploy(chain_name, cp1: PrivateKey, cp2: PublicKey) -> Deploy:
"""Returns transfer deploy to be dispatched to a node.
"""
# Set standard deploy parameters.
deploy_params = pycspr.create_deploy_parameters(
account = cp1,
chain_name = chain_name
)

# Set deploy.
deploy = pycspr.create_native_transfer(
params = deploy_params,
amount = int(2.5e9),
target = cp2.account_hash,
correlation_id = random.randint(1, 1e6)
)

return deploy


# Entry point.
if __name__ == '__main__':
_main(node_host, node_port_rpc, path_to_cp1_secret_key, type_of_cp1_secret_key, path_to_cp2_account_key, chain_name)

Staking

This example shows you how to define and stake funds with a validator.


import os
import pathlib

import pycspr
from pycspr.client import NodeClient
from pycspr.client import NodeConnectionInfo
from pycspr.crypto import KeyAlgorithm
from pycspr.types import Deploy
from pycspr.types import PrivateKey

# path to cp1 secret key - defaults to NCTL user 1.
path_to_validator_secret_key = pathlib.Path(os.getenv("NCTL")) / "assets" / "net-1" / "users" / "user-1" / "secret_key.pem"

# type of cp1 secret key - defaults to ED25519.
type_of_validator_secret_key = KeyAlgorithm.ED25519.name

# path to session code wasm binary - defaults to NCTL bin/eco/add_bid.wasm.
path_to_wasm = pathlib.Path(os.getenv("NCTL")) / "assets" / "net-1" / "bin" / "auction" / "add_bid.wasm"

# amount to stake, i.e. bond, into the network.
amount = int(2.5e9)

# amount to charge delegators for service provision.
delegation_rate = 2

# name of target chain - defaults to NCTL chain.
chain_name = "casper-net-1"

# host address of target node - defaults to NCTL node 1.
node_host = "localhost"

# Node API JSON-RPC port - defaults to 11101 @ NCTL node 1.
node_port_rpc = 11101

def _main(node_host, node_port_rpc, path_to_validator_secret_key, type_of_validator_secret_key, chain_name, amount, delegation_rate, path_to_wasm):
"""Main entry point.
:param args: Parsed command line arguments.
"""
# Set node client.
client: NodeClient = _get_client(node_host, node_port_rpc)

# Set validator key.
validator: PrivateKey = pycspr.parse_private_key(
path_to_validator_secret_key,
type_of_validator_secret_key,
)

# Set deploy.
deploy: Deploy = _get_deploy(validator, chain_name, amount, delegation_rate, path_to_wasm)

# Approve deploy.
deploy.approve(validator)

# Dispatch deploy to a node.
client.deploys.send(deploy)

print(f"Deploy dispatched to node [{node_host}]: {deploy.hash.hex()}")


def _get_client(node_host, node_port_rpc) -> NodeClient:
"""Returns a pycspr client instance.
"""
return NodeClient(NodeConnectionInfo(
host = node_host,
port_rpc = node_port_rpc,
))


def _get_deploy(validator: PrivateKey, chain_name, amount, delegation_rate, path_to_wasm) -> Deploy:
"""Returns delegation deploy to be dispatched to a node.
"""
# Set standard deploy parameters.
deploy_params = pycspr.create_deploy_parameters(
account = validator,
chain_name = chain_name
)

# Set deploy.
deploy = pycspr.create_validator_auction_bid(
params = deploy_params,
amount = amount,
delegation_rate = delegation_rate,
public_key = validator.as_public_key(),
path_to_wasm = path_to_wasm
)

return deploy


# Entry point.
if __name__ == '__main__':
_main(node_host, node_port_rpc, path_to_validator_secret_key, type_of_validator_secret_key, chain_name, amount, delegation_rate, path_to_wasm)

JavaScript/TypeScript SDK

This page contains details related to a few JavaScript (JS) clients and the Casper JS SDK.

Usage of JavaScript Clients

The Casper team has implemented specific JS clients to support interaction with the Casper contracts.

Repository & Client Packages

We provide repositories to create clients for Casper contracts and usage examples of such clients dedicated to interacting with smart contracts on Casper:

These packages give you an easy way to install and interact with the corresponding Casper contract.

Casper SDK for JavaScript

The TypeScript/JavaScript SDK allows developers to interact with a Casper network using TypeScript or JavaScript. This section covers different examples of using the Casper JS SDK.

Installation

To install this library using Node.js, run the following command:

npm install casper-js-sdk@next --save

Tests

You can find basic examples for how to use this library in the test directory. To run the tests, use this command:

npm run test

Usage Examples

In this section, we outline a couple of essential tasks you can accomplish with the JavaScript SDK:

  • Generating account keys
  • Sending a transfer

Generating Account Keys

This example shows you how to use the SDK to generate account keys to sign your deploy.

const fs = require("fs");
const path = require("path");
const { Keys } = require("casper-js-sdk");

const createAccountKeys = () => {
// Generating keys
const edKeyPair = Keys.Ed25519.new();
const { publicKey, privateKey } = edKeyPair;

// Create a hexadecimal representation of the public key
const accountAddress = publicKey.toHex();

// Get the account hash (Uint8Array) from the public key
const accountHash = publicKey.toAccountHash();

// Store keys as PEM files
const publicKeyInPem = edKeyPair.exportPublicKeyInPem();
const privateKeyInPem = edKeyPair.exportPrivateKeyInPem();

const folder = path.join("./", "casper_keys");

if (!fs.existsSync(folder)) {
const tempDir = fs.mkdirSync(folder);
}

fs.writeFileSync(folder + "/" + accountAddress + "_public.pem", publicKeyInPem);
fs.writeFileSync(folder + "/" + accountAddress + "_private.pem", privateKeyInPem);

return accountAddress;
};

const newAccountAddress = createAccountKeys();

After generating the keys with this code, you can add them to the Casper Wallet Chrome extension and use them to sign your transactions.

Sending a Transfer

This code block shows you how to define and send a transfer on a Casper network. Replace the sender-public-key and recipient-public-key in the code below.

The sendTransfer function below will return a transfer-hash which you can check on https://testnet.cspr.live/.

const fs = require("fs");
const path = require("path");
const axios = require("axios");
const casperClientSDK = require("casper-js-sdk");

const { Keys, CasperClient, CLPublicKey, DeployUtil } = require("casper-js-sdk");

const RPC_API = "http://159.65.203.12:7777/rpc";
const STATUS_API = "http://159.65.203.12:8888";

const sendTransfer = async ({ from, to, amount }) => {
const casperClient = new CasperClient(RPC_API);

const folder = path.join("./", "casper_keys");

// Read keys from the structure created in #Generating keys
const signKeyPair = Keys.Ed25519.parseKeyFiles(folder + "/" + from + "_public.pem", folder + "/" + from + "_private.pem");

// networkName can be taken from the status api
const response = await axios.get(STATUS_API + "/status");

let networkName = null;

if (response.status == 200) {
networkName = response.data.chainspec_name;
}

// For native-transfers the payment price is fixed
const paymentAmount = 100000000;

// transfer_id field in the request to tag the transaction and to correlate it to your back-end storage
const id = 187821;

// gasPrice for native transfers can be set to 1
const gasPrice = 1;

// Time that the deploy will remain valid for, in milliseconds
// The default value is 1800000 ms (30 minutes)
const ttl = 1800000;

let deployParams = new DeployUtil.DeployParams(signKeyPair.publicKey, networkName, gasPrice, ttl);

// We create a hex representation of the public key with an added prefix
const toPublicKey = CLPublicKey.fromHex(to);

const session = DeployUtil.ExecutableDeployItem.newTransfer(amount, toPublicKey, null, id);

const payment = DeployUtil.standardPayment(paymentAmount);
const deploy = DeployUtil.makeDeploy(deployParams, session, payment);
const signedDeploy = DeployUtil.signDeploy(deploy, signKeyPair);

// Here we are sending the signed deploy
return await casperClient.putDeploy(signedDeploy);
};

sendTransfer({
// Put here the public key of the sender's main purse. Note that it needs to have a balance greater than 2.5 CSPR
from: "<sender-public-key>",

// Put here the public key of the recipient's main purse. This account doesn't need to exist. If the key is correctly formatted, the network will create the account when the deploy is sent
to: "<recipient-public-key>",

// Minimal amount is 2.5 CSPR (1 CSPR = 1,000,000,000 motes)
amount: 25000000000,
});

Note: At any moment, you can serialize the deploy from this example to JSON to accomplish whatever you want (store it, send it, etc.).

Here is the code you can use to serialize the deploy:

const jsonFromDeploy = DeployUtil.deployToJson(signedDeploy);

Then, you can reconstruct the deploy object using this function:

const deployFromJson = DeployUtil.deployFromJson(jsonFromDeploy);

Setting up a Local Network with NCTL

NCTL stands for network/node control. NCTL is a CLI application you can use to set up and control multiple local Casper nodes during development. Many developers wish to spin up relatively small test networks to localize their testing before deploying to the blockchain. Adopting a standardized approach in the community is also helpful for troubleshooting and reporting issues.

Prerequisites

  1. You have completed the Getting Started section, which shows you how to install your development environment, including tools like CMake (version 3.1.4+), Cargo, and Rust.
  2. Make sure you have Python 3 installed if your operating system does not include Python.
  3. To run NCTL, you will also need the bash shell.

Video Tutorial

If you prefer a video walkthrough of this guide, you can check out this video.

Installing a Virtual Environment

We will show you how to run NCTL in a virtual environment. If you want to run NCTL at the system level, you can, but we recommend that you only do that if you are sure you know what you are doing.

First, you will need to install a set of tools required for running NCTL.

Step 1. The first tool you will need is pip, a package manager for Python. Pip comes with the Python 3 installation from python.org, but if you do not have it already, follow the steps below or the full installation instructions.

Instructions for MacOS:

$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python3 get-pip.py

Instructions for Linux:

$ sudo apt install python3-pip

Step 2. Install pkg-config, a program used to compile and link against one or more libraries.

Instructions for MacOS:

$ brew install pkg-config

Instructions for Linux:

$ sudo apt install pkg-config

Step 3. Install either libssl-dev (Linux) or openssl (MacOS), which are toolkits for the Transport Layer Security (TLS) and Secure Sockets Layer (SSL) protocols. They also serve as general-purpose cryptography libraries.

Instructions for MacOS:

$ brew install openssl

Instructions for Linux:

$ sudo apt install libssl-dev

Step 4. You will also need the gcc and g++ compilers, which usually come as part of developer command-line tools (versions 7.5.0 at the time of this writing).

Instructions for MacOS:

$ xcode-select --install
$ gcc --version
$ g++ --version

Instructions for Linux:

$ sudo apt install build-essential
$ gcc --version
$ g++ --version

Step 5. Create and activate a new virtual environment. Commands applicable to the virtual environment will be prefixed with (env). Run the following commands to set it up.

Instructions for MacOS and Linux:

$ python3 -m venv env
$ source env/bin/activate
(env) $

Step 6. Inside the virtual environment, upgrade pip to the latest version.

Instructions for MacOS and Linux:

(env) $ pip install --upgrade pip

Step 7. Install jq, a command-line JSON processor.

Instructions for MacOS and Linux:

(env) $ pip install jq

Step 8. Install supervisor, a cross-platform process manager.

Instructions for MacOS and Linux:

(env) $ pip install supervisor

Step 9. Install toml, a configuration file parser.

Instructions for MacOS and Linux:

(env) $ pip install toml

Setting up the Network

You are now ready to set up and run your local network of Casper nodes.

Step 10. Clone the casper-node-launcher software in your working directory, which we will call WORKING_DIRECTORY. Very Important!!! Choose a short path for your working directory; otherwise, the NCTL tool will report that the path is too long.

Instructions for MacOS and Linux:

(env) $ cd <WORKING_DIRECTORY>
(env) $ git clone https://github.com/casper-network/casper-node-launcher
note

Assuming you have set up a small local network, you can speed up the process of creating new blocks with NCTL by reducing the deploy_delay in your local config.toml before running nctl-assets-setup.

Step 11. Next, clone the casper-node software, also in your working directory.

Instructions for MacOS and Linux:

(env) $ git clone https://github.com/casper-network/casper-node

Step 12. Finally, clone the casper-client-rs software in your working directory.

Instructions for MacOS and Linux:

(env) $ git clone https://github.com/casper-ecosystem/casper-client-rs

Step 13. Activate the NCTL environment with the following command.

Instructions for MacOS and Linux:

(env) $ source casper-node/utils/nctl/activate

Step 14. Compile the NCTL binary scripts. The following command compiles both the casper-node and the casper-client in release mode.

Instructions for MacOS and Linux:

(env) $ nctl-compile
note

The compilation takes some time, so it might be a perfect moment to get some coffee.

Step 15. Set up all the assets required to run a local network, including binaries, chainspec, config, faucet, and keys. Also, spin up the network right after. The default network will have 10 nodes, with 5 active nodes and 5 inactive nodes.

Instructions for MacOS and Linux:

(env) $ nctl-assets-setup && nctl-start

Once a network is up and running, you can control each node within the network and add new nodes to the network.

Several other NCTL commands are available via aliases for execution from within a terminal session. All such commands are prefixed by nctl- and allow you to perform various tasks.

You should see the new directory utils/nctl/assets, with the following structure.

assets_setup

Here is the command line output you would expect.

nctl_output

Stopping the Network

Step 15. Although not necessary, you can stop and clean the NCTL setup with the following commands.

Instructions for MacOS and Linux:

(env) $ nctl-stop
(env) $ nctl-clean

Next Steps

  1. Explore the various NCTL commands.
  2. Explore the NCTL usage guide.

Signing Deploys

When creating a Deploy to be executed on a Casper network, the account owner, or more accurately, enough authorized signers must sign the deploy using their account's cryptographic key-pair. This key-pair is a combination of the account's secret and public keys. The signatures attached to the Deploy allow the network to verify that it should be executed.

When a signature is attached to a deploy, it is paired with the public key of the signer, and referred to as an Approval. Every valid deploy has at least one approval.

The signature creation process begins with the hashing of the payment and session of the deploy to create the BodyHash. The BodyHash becomes a component of the DeployHeader as outlined in the serialization standard. From there, the DeployHeader can be hashed to create the DeployHash. As outlined above, the DeployHash is then combined with the account's key-pair to create the deploy's signature.

As the DeployHash contains a hash of the deploy's body within, any variation to any aspect of the deploy or sending account's keys would render the DeployHash invalid.

Public Key Cryptography

Casper networks are compatible with both Ed25519 and Secp256k1 public key cryptography. When serialized, public keys and signatures are prefixed with a single byte, used as a tag to denote the applicable algorithm. Ed25519 public keys and signatures are prefixed with 1, whereas Secp256k1 are prefixed with 2.

Casper uses blake2b hashing within our serialization. However, these hashed values will be hashed once again when they are signed over. The type of hashing depends on the associated keypair algorithm as follows:

  • Ed25519 signs over a SHA-512 digest.

  • Secp256k1 signs over a SHA-256 digest.

Estimating Gas Costs with Speculative Execution

Version 1.5 of the Casper Node includes a new JSON RPC endpoint called speculative_exec. This endpoint allows developers to send a Deploy to a single node, which will execute the Deploy without committing the results to global state and, therefore, not incurring the associated costs. Observing the execution results of the Deploy gives a rough estimate of the potential cost for sending the Deploy without speculative execution.

In addition to the Deploy in question, speculative_exec also accepts a [block_identifier] for a specific block height or hash to speculate on. If you do not provide a block identifier, the Deploy will be executed on the most recent block.

Sending a Speculative Execution Deploy using the Rust CLI Casper Client

The Rust CLI Casper client includes a speculative-exec option that will flag a normal put-deploy for execution but not commitment to global state. The following command shows an example:


casper client put-deploy /
--node-address <HOST:PORT> /
--chain-name <CHAIN_NAME> /
--secret-key <PATH> /
--session-path <PATH> /
--payment-amount <PAYMENT_AMOUNT_IN_MOTES>
--speculative-exec <BLOCK HEIGHT OR HASH>

You should receive execution_results that show a cost.


{
"jsonrpc": "2.0",
"id": -4571113357017152230,
"result": {
"api_version": "1.0.0",
"block_hash": "6ca035b08de092e7f5e8fff771b880c5b4d7463a8f7a9b108888aaad958e5b0f",
"execution_result": {
"Success": {
"effect": {
<Deploy effects removed for conciseness.>
},
"transfers": [],
"cost": "87300473670"
}
}
}
}

note

Cost estimates acquired through speculative_exec may vary from the cost of sending the same Deploy to a Casper network. Speculative execution is a tool to help narrow down the potential cost of sending a Deploy, but many factors can cause the actual cost to vary.

dApp Technology Stack

There are 3 layers to building a decentralized application that interacts with a Casper network: Front-end, backend, and on-chain logic. This document outlines lists the requirements for each.

Front-End

The front-end, or client-side of a dApp consists of the interface that the user uses to interact with smart contracts on a Casper Network. This interface usually comes in the form of a website/webpage, mobile device application or computer program, but could also include APIs with endpoints that may be called or queried.

You will need to choose a Casper-compatible SDK for the language you are using to call and query smart contracts on a Casper network. Casper's SDKs have methods available for constructing Deploys and gathering global state data. While these interactions can be prepared on the front-end, they must be sent to the backend of your application before being sent off to a network, so as to fulfill CORS requirements.

Signing Transactions

The signing of transactions will, in many cases, need to be performed by the user on the front-end, for which you have a couple options:

  1. The Casper Wallet

    Use the Casper Wallet to sign deploys for a Casper network. Deploy objects are first converted to JSON, then sent to the Wallet to be signed, then must be sent to the backend and forwarded to a node.

    caution

    The Casper Signer has been deprecated and replaced with the Casper Wallet. We are in the process of updating this page. Meanwhile, visit the guide on Building with the Casper Wallet.

  2. Third-party signers

    Third-party signers may be used as well. A JSON representation of the unsigned transaction should be forwarded to the third-party signer and accept a callback containing the signed deploy object.

Querying Global State

To execute a query of global state, such as retrieving smart contract data or getting current chain information, the preparation may be done on the front-end, but the query to a node must ultimately originate from your application's backend. This preparatory stage comes only in the form of defining a contract hash and the path which you'd like to query data. Alternately, for chain information, you must define the endpoint you'd like to query.

Backend

The backend of a dApp consists of the server-side code that connects the blockchain to the front-end interface and deals with data-parsing and application-layer communication. A backend server is necessary for building dApps on Casper as Casper's nodes expect CORS headers from a specified origin on the HTTP requests they receive. Backend servers are helpful for other reasons too, such as queueing requests and analyzing the traffic moving between your dApp and the blockchain.

As the backend server of a dApp is the software communicating with Casper nodes (the blockchain), it needs to receive information such as which node and endpoint to connect to.

const client = new CasperClient("http://NODE_ADDRESS:7777/rpc");
tip

You can find online peers for Mainnet at cspr.live or testnet at testnet.cspr.live

There are two main types of blockchain interactions that will originate from the front-end: deploys and queries. In the case of a dApp, both of these will pass through the back-end.

Blockchain interaction for state queries is handled solely on the backend. On the front-end, a user simply chooses the path at which they want to query data. This path is sent to the backend where the server will perform the state query and send the result back to the front-end.

In the case of a user-signed transaction originating from the dApp's front-end, the backend will need to accept this transaction and forward it to a Casper network. This is often accomplished by opening a POST endpoint that accepts JSON formatted transactions and forwards them along.

Blockchain

The last stop for a deploy or query is the blockchain itself. Like the majority of smart contract blockchains, Casper networks maintain a forever-growing, immutable ledger that can be read and written to. When building a dApp for a Casper network, user interactions in the form of queries and deploys originate from the front-end, are forwarded to the backend, and are then sent to a Casper node for interaction with the blockchain. You can communicate with Casper nodes using JSON RPC calls, and have a variety of open transactional, informational, and Proof-of-Stake endpoints. By utilizing an SDK on the backend, you won't need to construct these JSON RPC calls yourself, they'll be done for you within the available methods.

More than likely, you will want your dApp to perform personalized functions, store custom data, and perhaps even store or transact upon tokens with monetary value. All of these behaviors can be implemented by writing custom smart contracts for your application. Smart contracts on a Casper network can perform any function that a classical computer can. Casper's smart contracts are executed as WebAssembly binaries, and can be written in any language that compiles to WebAssembly. Currently, most developers choose to write their smart contracts in Rust for its reliability and ease-of-use. Additionally, Casper's smart contract documentation is written for Rust.

To learn how to write smart contracts for your dApp, read the smart contract documentation.

Front-end Template with React

For building web applications, it is most common to use the Casper JS SDK with React. This is a popular solution among developers, but you may use any front-end library or framework, including none at all, to interact with a Casper network via the Casper JS SDK.

This guide will walk you through setting up and developing a React application with Vite that communicates with a Casper network. Experience with Vite is not required; however, if you have never built a React app, you should begin by reading the React documentation.

Get Started

Begin by opening a terminal and running:

node -v

To get your Node.js version.

To ensure compatibility, you should be running Node.js version 18 or above. Upgrade to version 18 using the Node Version Manager or another tool if you are running an earlier version.

Using npm, create a new Vite project by running:

npm install -g vite
npm create vite@latest

Name your project, select "React", then choose your preferred language. In this example, we will use JavaScript.

Head into your new project directory, replacing vite-project with your project name:

cd vite-project/

Run the following command to test the server:

npm install
vite dev

Quit the server by pressing q. Install the Casper JS SDK by running the following:

npm install casper-js-sdk

This guide will use axios to communicate with the backend; install it by running:

npm install axios

Casper Wallet Integration

The Casper Wallet extension content script injects the SDK into your website's global scope. Provider class and event types can be accessed with window.CasperWalletProvider and window.CasperWalletEventTypes. If the value of these variables is undefined the Casper Wallet is not installed.

Start with a helper for getting the provider instance:

touch src/casper-wallet.js

Fill the file with the following content:

// Timeout (in ms) for requests to the extension [DEFAULT: 30 min]
const REQUESTS_TIMEOUT_MS = 30 * 60 * 1000;

export const getProvider = () => {
let providerConstructor = window.CasperWalletProvider;
if (providerConstructor === undefined) {
alert("Casper Wallet extension is not installed!");
return;
}
let provider = providerConstructor({
timeout: REQUESTS_TIMEOUT_MS,
});
return provider;
};
tip

For complete integration details, refer to README of Casper Wallet SDK.

To ensure that a user's public key will be available to all necessary components, create a React state variable in src/App.jsx or another parent component that encapsulates the components that should have access to this public key:

import React from "react";
import Connect from "./Connect";
import "./App.css";

function App() {
const [publicKey, setPublicKey] = React.useState(null);
return (
<>
<Connect setPublicKey={setPublicKey} />
<div>
{publicKey !== null && (
<>
Wallet connected: {publicKey}
<br />
</>
)}
</div>
</>
);
}

export default App;

This is an example of src/App.jsx that imports and displays the Connect component that is described next. The setPublicKey function is passed to the Connect component as a prop so that it may set the public key and make it available to all of src/App.jsx. This way, when more components are added to src/App.jsx, they may utilize the publicKey variable.

To connect to the Casper Wallet within your React app, create the Connect component and import the getProvider helper.

touch src/Connect.jsx

Open the file and write:

import { getProvider } from "./casper-wallet";

const provider = getProvider();

const Connect = (props) => {
return (
<>
<button onClick={() => connectToWallet(props)}>Connect Wallet</button>
{/* Place for disconnect button */}
</>
);
};

export default Connect;

Notice that Connect accepts props, and forwards them to the connectToWallet function described below. This function is called when the button is clicked, allowing it to set the public key within src/App.jsx using props.setPublicKey().

Write the connectToWallet function under the Connect function component:

const connectToWallet = (props) => {
provider
.requestConnection()
.then((connected) => {
if (!connected) {
alert("Couldn't connect to wallet");
} else {
provider
.getActivePublicKey()
.then((publicKey) => {
props.setPublicKey(publicKey);
})
.catch((error) => {
alert(error.message);
});
}
})
.catch((error) => {
alert(error.message);
});
};

The connectToWallet() function calls provider.isConnected() to check if the Casper Wallet is already connected. If it is, it gets the public key of the selected account; if it's not, it opens up a connection request within the Wallet. provider.isConnected() will throw an error if the Wallet is not installed as an extension or if it is locked.

Disconnect the Casper Wallet

To request that the Casper Wallet disconnect from a website, add the following function call to src/Connect.jsx:

const disconnect = (props) => {
provider
.disconnectFromSite()
.then((disconnected) => {
if (disconnected) {
props.setPublicKey(null);
alert("Disconnected");
}
})
.catch((error) => {
alert(error.message);
});
};

Then connect it to a button:

const Connect = (props) => {
return (
<>
<button onClick={() => connectToWallet(props)}>Connect Wallet</button>
<button onClick={() => disconnect(props)}>Disconnect</button>
</>
);
};

Call a Smart Contract

For this example, we'll call a hypothetical "hello world" contract containing a single entrypoint "update_message". We'll call the "update_message" entrypoint with text entered by the user in an HTML input field.

When calling smart contracts from React, you'll need to implement the logic within a function accessible from a React component. You can obtain user-entered data from the DOM using elements like input, then grab the value within the smart-contract-calling function.

Create a new component:

touch src/UpdateMessage.jsx

Open the file and write:

import { useState } from "react";
import { Contracts, CasperClient, RuntimeArgs, CLValueBuilder, CLPublicKey, DeployUtil } from "casper-js-sdk";
import axios from "axios";
import { getProvider } from "./casper-wallet";

const provider = getProvider();

const UpdateMessage = (props) => {
const [message, setMessage] = useState("");

return (
<>
<input
id="message"
type="text"
value={message}
onChange={(e) => {
setMessage(e.target.value);
}}
/>
<button onClick={() => updateMessage(props, message)}>Update Message</button>
</>
);
};

export default UpdateMessage;

On the front-end you'll need to build the deploy and forward it to the Casper Wallet to be signed. In most cases, you will be calling smart contract entrypoints. This example deploy shows the calling of entrypoint "update_message" which will update the chain's global state to reflect the new data. You'll need the user's active public key to prepare the deploy, and you may retrieve this from the publicKey variable passed in as a prop from src/App.jsx. Write this function under your UpdateMessage component function.

const NODE_URL = "http://65.108.127.242:7777/rpc";
const NETWORK_NAME = "casper-test"; // "casper" for mainnet
const CONTRACT_HASH = "hash-75143aa708275b7dead20ac2cc06c1c3eccff4ffcf1eb9aebb8cce7c35cea041";

const updateMessage = (props, message) => {
const casperClient = new CasperClient(NODE_URL);
const contract = new Contracts.Contract(casperClient);
contract.setContractHash(CONTRACT_HASH);
const runtimeArguments = RuntimeArgs.fromMap({
message: CLValueBuilder.string(message),
});
const deploy = contract.callEntrypoint(
"update_message",
runtimeArguments,
CLPublicKey.fromHex(props.publicKey),
NETWORK_NAME,
"1000000000", // 1 CSPR (10^9 Motes)
);
const deployJSON = DeployUtil.deployToJson(deploy);
provider
.sign(JSON.stringify(deployJSON), props.publicKey)
.then((signedDeploy) => {
// Initiates sign request
axios
.post("/sendDeploy", signedDeploy, {
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
alert(response.data);
})
.catch((error) => {
console.error(error.message);
});
})
.catch((error) => {
console.error(error.message);
});
};

In this example, updateMessage builds a deploy and forwards it to the Casper Wallet to be signed by the user. Once it's been signed, signedDeploy is forwarded to the backend at the /sendDeploy endpoint using axios.post before being sent off to a Casper node. If an error occurs, or the user rejects the signature request, it will be logged to stderr. In this particular example, the result of this deployment will be presented to the user in the form of a JavaScript alert; however, you may do with the response data as you wish.

info

The backend endpoint /sendDeploy should handle signed deployment by simply passing it to a Casper node.

In Casper node v1.5.0, which sets up appropriate CORS headers, it will also be possible to send deployments directly from the browser, without relying on a backend server. This is useful for prototyping, however it is advised that you operate your own node.

Now that this component is created, render it to the user interface in src/App.jsx, passing along the publicKey as a prop:

import React from "react";
import Connect from "./Connect";
import UpdateMessage from "./UpdateMessage";
import "./App.css";

function App() {
const [publicKey, setPublicKey] = React.useState(null);
return (
<>
<Connect setPublicKey={setPublicKey} />
<div>
{publicKey !== null && (
<>
Wallet connected: {publicKey}
<br />
<UpdateMessage publicKey={publicKey} />
</>
)}
</div>
</>
);
}

Query a Smart Contract

Consider that the message written to the chain during the update_message entrypoint invocation is stored in the dictionary messages in the contract. Further consider that each account may write its own message and that the messages are stored under the account's account hash as the dictionary key. Querying this kind of data is essential in any dApp; here is how to communicate contract data to and from the front-end.

Create a new component:

touch src/Query.jsx

Open the file and write:

import axios from "axios";
import { CLPublicKey } from "casper-js-sdk";

const Query = (props) => {
return <button onClick={() => query(props)}>Query</button>;
};

const query = (props) => {
const accountHash = CLPublicKey.fromHex(props.publicKey).toAccountHashStr().substring(13);
axios
.get("/queryMessage?accountHash=" + accountHash)
.then((response) => {
alert(response.data);
})
.catch((error) => {
console.error(error.message);
});
};

export default Query;

All this component does is render an HTML button element that, when pressed, performs a GET request to the backend that includes the user's active account hash. The account hash is derived from the active public key, and is used to look up the message stored by the current user.

tip

The toAccountHashStr method produces a string that is prepended by the text "account-hash-". In this case, this text is not needed, so it is discarded by chaining on the substring(13) method.

info

This functionality relies on the /queryMessage endpoint, which should be implemented in your backend.

Now add this component to src/App.jsx, making available the publicKey state variable via a prop:

import React from "react";
import Connect from "./Connect";
import UpdateMessage from "./UpdateMessage";
import Query from "./Query";
import "./App.css";

function App() {
const [publicKey, setPublicKey] = React.useState(null);
return (
<>
<Connect setPublicKey={setPublicKey} />
<div>
{publicKey !== null && (
<>
Wallet connected: {publicKey}
<br />
<UpdateMessage publicKey={publicKey} />
<Query publicKey={publicKey} />
</>
)}
</div>
</>
);
}

Test Application

Test your application by running the following:

vite dev

Your application will start locally, and a URL will be shown where you can visit your application. Alternatively, press h, then o to open the app in a browser.

Build for Production

When you're ready to release your application, you'll want to compile it to pure JavaScript and serve it from a web server. Do so by running:

vite build

Once this is complete, you can preview your production build by running:

vite preview

URef Access Rights and Security Considerations

Understanding Access Rights

An Unforgeable Reference or URef is a key type used for storage on a Casper network. They can store any value other than Account and exist as a top-level entity. As such, no individual account may own a URef, they can only hold the necessary AccessRights to interact with a given URef.

AccessRights determine how an entity on a Casper network may interact with a URef. They appear as a single byte suffix after the concatenation of te URef's address. As an example, the following is an example of a URef with no associated access rights:

uref-974019c976b5f26412ce486158d2431967af35d91387dae8cbcd43c20fce6452-000

And this is the same URef with READ and ADD access rights.

uref-974019c976b5f26412ce486158d2431967af35d91387dae8cbcd43c20fce6452-005

The following table outlines all possible AccessRights settings:

Access RightsSerialization
NONE0
READ1
WRITE2
READ_WRITE3
ADD4
READ_ADD5
ADD_WRITE6
READ_ADD_WRITE7
danger

Any access rights granted alongside a passed URef are irrevocable.

AccessRights and Purses

A Purse is a unique type of URef representing a token balance. Each Account will have an associated URef that represents its main purse. Accounts and contracts may have additional purses.

For URefs that represent a purse, access rights determine the ability to read or change the associated balance of tokens. The following table outlines what each operation allows in the context of a purse:

Global StateAction Monetary Action
AddDeposit (i.e. transfer to)
WriteWithdraw (i.e. transfer from)
ReadBalance check

Security Considerations for dApp Developers

When developing a dApp that interacts with tokens in any way, it will be necessary to work with various URef AccessRights for associated purse URefs.

This tutorial outlines our recommendations when transferring tokens to a contract.

When passing a URef to another entity in any way, ensure that you are only passing the URef with the appropriate AccessRights. The following example code shows the syntax for creating a URef with any given access rights combination. In this example, only the new_uref should be passed to another entity.

// This example will create a version of the original URef with access rights stripped entirely.
let new_uref = uref.with_access_rights(AccessRights::NONE);
// This example will create a version of the original URef with only READ access rights.
let new_uref = uref.with_access_rights(AccessRights::READ);
// This example will create a version of the original URef with only WRITE access rights.
let new_uref = uref.with_access_rights(AccessRights::WRITE);
// This example will create a version of the original URef with both READ and WRITE access rights.
let new_uref = uref.with_access_rights(AccessRights::READ_WRITE);
// This example will create a version of the original URef with only ADD access rights.
let new_uref = uref.with_access_rights(AccessRights::ADD);
// This example will create a version of the original URef with both READ and ADD access rights.
let new_uref = uref.with_access_rights(AccessRights::READ_ADD);
// This example will create a version of the original URef with both ADD and WRITE access rights.
let new_uref = uref.with_access_rights(AccessRights::ADD_WRITE);
// This example will create a version of the original URef with full access rights.
let new_uref = uref.with_access_rights(AccessRights::READ_ADD_WRITE);

Essential Rust Crates

Several Rust crates are available on crates.io to support smart contract development with Rust. A crate is a compilation unit that can be compiled into a binary or a library. The corresponding documentation is published on docs.rs. The most important crates are listed below.

casper-types

Types shared by many Casper crates:

casper-contract

A library for developing Casper smart contracts:

casper-engine-test-support

The Casper test support library:

casper-node

The component for running a node on a Casper network:

casper-client

A client library for interacting with a Casper network:

casper-event-standard

A Rust library that provides a simple and standardized way for Casper contracts to emit events:

casper-hashing

A library providing hashing functionality including Merkle Proof utilities:

casper-wasm-utils

Command-line utilities and corresponding Rust API for producing pwasm-compatible executables:

cargo-casper

A command line tool for creating a Wasm smart contract and tests:

Other Libraries

The Open-Source Software page provides other community-curated tools and libraries.

Developers Overview

This section supports developers getting started with the Casper blockchain by writing dApps or smart contracts in Rust. Developers can install a local development environment with a runtime and a test framework. They can also create and test contracts with the libraries provided or use these libraries to build decentralized applications. Prior knowledge of Unix-based operating systems, like GNU/Linux, and programming knowledge with Rust, AssemblyScript, JavaScript, or Python are highly recommended.

TopicDescription
Development PrerequisitesSetup needed for various workflows
Essential Casper CratesAvailable Casper crates and the corresponding documentation
Writing On-Chain CodeWriting contracts in Rust and Wasm for a Casper network
Casper JSON-RPC APIEndpoints for developers wishing to interact directly with a Casper node's JSON-RPC API
Building dAppsUseful information for dApp developers
Interacting with the Blockchain Using CLIUsing a Rust command-line client to install and call contracts; transfer, delegate, and undelegate tokens.

The Ecosystem Open-Source Software may provide other helpful examples.

The motivation for the Casper Network roadmap is inspired by community feedback and recommendations. We look forward to building a decentralized future together.

Casper JSON-RPC Error Codes

The following document expands on custom error codes provided by casper-json-rpc crate.

Error Codes

CodeErrorDescription
-1NoSuchDeployThe requested Deploy was not found.
-2NoSuchBlockThe requested Block was not found.
-3FailedToParseQueryKeyParsing the Key from a query failed.
-4QueryFailedThe query failed to find a result.
-5QueryFailedToExecuteExecuting the query failed.
-6FailedToParseGetBalanceURefParsing the URef while getting a balance failed.
-7FailedToGetBalanceFailed to get the requested balance.
-8GetBalanceFailedToExecuteExecuting the query to retrieve the balance failed.
-9InvalidDeployThe given Deploy cannot be executed as it is invalid.
-10NoSuchAccountThe given account was not found.
-11FailedToGetDictionaryURefFailed to get the requested dictionary URef.
-12FailedToGetTrieFailed to get the requested dictionary trie.
-13NoSuchStateRootThe requested state root hash was not found.
-32600InvalidRequestThe JSON sent is not a valid Request object.
-32601MethodNotFoundThe method does not exist or is not available.
-32602InvalidParamsInvalid method parameter(s)
-32603InternalErrorInternal JSON-RPC error.
-32700ParseErrorInvalid JSON was received by the server.

Invalid Params

The casper-json-rpc no longer ignores invalid params fields. Params fields to be omitted should be an empty Array '[]', an empty Object '{}' or absent.

Failing to adhere to this will result in an InvalidParams error.

Guidance for JSON-RPC SDK Compliance

A compliant Casper JSON-RPC SDK implementation must support all the endpoints and relevant types within the specification. The specification allows everything ranging from a minimal viable implementation to a full implementation, and a given SDK should cite which level of implementation they claim to be compliant with. For example, an SDK claiming to be an informational SDK must have implemented all entry points and relevant types described in the informational JSON-RPC methods page.

A Casper JSON-RPC SDK claiming to be complete is expected to implement all endpoints and all types defined in the serialization standard.

Consistency

A Casper JSON-RPC SDK must be consistent in terminology, language, and functionality relative to the Casper platform's architecture and design. Use actual terms such as Account and Deploy, not similar terms such as wallet or transaction.

Care should be taken to maintain a universal language and not obscure the domain concepts of the Casper platform, which could confuse users of the SDK. The goal is to not make it difficult for users of an SDK to understand the documentation of the Casper platform. Further, they should be able to communicate effectively with technical support personnel who understand the terminology of the Casper platform and not the variant terminology of an SDK.

Advanced Functionality

SDK developers are allowed and encouraged to add convenience methods, supporting utilities, domain specific or macro support and extended functionality using the available endpoints and possible combinations.

However, it is critical that SDK developers avoid misleading or improperly characterizing the purpose and scope of the available endpoints. Custom functionality should improve on the basic building blocks of the Casper Platform, offering added convenience.

For example, some languages have strong idiomatic opinions and programmers using those languages are comfortable with or even expect SDKs in that language to follow those idioms. This is acceptable, as long as they do not obfuscate underlying terminology or semantics of the Casper platform.

Interacting with the Casper JSON-RPC API

Casper uses a custom JSON-RPC implementation known as casper-json-rpc that is compliant with the JSON-RPC 2.0 specification. If you are on this page, you are an advanced user wishing to interact directly with a Casper node's JSON-RPC API. You may use Postman or write code to interact with the Casper JSON-RPC API, which is fully compatible with the JSON-RPC 2.0 Specification.

Casper nodes provide the RPC schema on port 8888, followed by rpc-schema:

<HOST:8888>/rpc-schema

To see an example, navigate to a node's RPC schema using a browser.

The Casper client subcommand list-rpcs provides all currently supported RPCs. Here is an example of running the Casper client to list RPCs:

casper-client list-rpcs --node-address <HOST:PORT>

Table of Contents

PageDescription
Guidance for JSON-RPC SDK ComplianceRequirements for a compliant Casper SDK
Required JSON-RPC Methods for Minimal ComplianceMethods required for a minimally compliant Casper SDK
Transactional JSON-RPC MethodMethods allowing interaction with a Casper network
Informational JSON-RPC MethodsMethods returning information about the network from a Casper node
Proof-of-Stake JSON-RPC MethodsMethods pertaining to Proof-of-Stake functionality on a Casper network
TypesInformation on types used within JSON-RPC methods
CL TypesInformation related to CL Types

Informational JSON-RPC Methods

The following methods return information from a node on a Casper network. The response should be identical, regardless of the node queried, as the information in question is objective and common to all nodes within a network.


chain_get_block

This method returns the JSON representation of a Block from the network.

ParameterTypeDescription
block_identifierObjectThe Block hash or the Block height.
Example chain_get_block request

{
"id": 1,
"jsonrpc": "2.0",
"method": "chain_get_block",
"params": [
{
"Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"
}
]
}

chain_get_block_result

The result from chain_get_block depends on block availability from a given node. If chain_get_block returns an error message that the node does not have information on the given block, you may attempt to get the information from a different node.

ParameterTypeDescription
api_versionStringThe RPC API version.
blockObjectThe Block, if found. (Not required)
Example chain_get_block result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"block": {
"body": {
"deploy_hashes": [],
"proposer": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",
"transfer_hashes": [
"5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa"
]
},
"hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",
"header": {
"accumulated_seed": "ac979f51525cfd979b14aa7dc0737c5154eabe0db9280eceaa8dc8d2905b20d5",
"body_hash": "cd502c5393a3c8b66d6979ad7857507c9baf5a8ba16ba99c28378d3a970fff42",
"era_end": {
"era_report": {
"equivocators": [
"013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"
],
"inactive_validators": [
"018139770ea87d175f56a35466c34c7ecccb8d8a91b4ee37a25df60f5b8fc9b394"
],
"rewards": [
{
"amount": 1000,
"validator": "018a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c"
}
]
},
"next_era_validator_weights": [
{
"validator": "016e7a1cdd29b0b78fd13af4c5598feff4ef2a97166e3ca6f2e4fbfccd80505bf1",
"weight": "456"
},
{
"validator": "018a875fff1eb38451577acd5afee405456568dd7c89e090863a0557bc7af49f17",
"weight": "789"
},
{
"validator": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",
"weight": "123"
}
]
},
"era_id": 1,
"height": 10,
"parent_hash": "0707070707070707070707070707070707070707070707070707070707070707",
"protocol_version": "1.0.0",
"random_bit": true,
"state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",
"timestamp": "2020-11-17T00:39:24.072Z"
},
"proofs": [
{
"public_key": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",
"signature": "016291a7b2689e2edcc6e79030be50edd02f9bd7d809921ae2654012f808c7b9a0f125bc32d6aa610cbd012395a9832ccfaa9262023339f1db71ca073a13bb9707"
}
]
}
}
}

chain_get_block_transfers

This method returns all successful native transfers within a given Block from a network.

ParameterTypeDescription
block_identifierObjectThe Block hash.
Example chain_get_block_transfers request

{
"id": 1,
"jsonrpc": "2.0",
"method": "chain_get_block_transfers",
"params": [
{
"Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"
}
]
}

chain_get_block_transfers_result

ParameterTypeDescription
api_versionStringThe RPC API version.
block_hashObjectThe Block hash, if found.
transfersArrayThe Block's successful transfers, if found.
Example chain_get_block_transfers result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"block_hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",
"transfers": [
{
"amount": "0",
"deploy_hash": "0000000000000000000000000000000000000000000000000000000000000000",
"from": "account-hash-0000000000000000000000000000000000000000000000000000000000000000",
"gas": "0",
"id": null,
"source": "uref-0000000000000000000000000000000000000000000000000000000000000000-000",
"target": "uref-0000000000000000000000000000000000000000000000000000000000000000-000",
"to": null
}
]
}
}

chain_get_era_summary

This method returns the era summary at a given Block. If you do not specify a block_identifier, you will receive the era summary at the highest state root hash.

ParameterTypeDescription
block_identifierObjectThe Block hash. (Optional)
Example chain_get_era_summary request

{
"id": 1,
"jsonrpc":"2.0",
"method":"chain_get_era_summary",
"params": [
{
"Hash":"9bfa58709058935882a095ca6adf844b72a2ddf0f49b8575ef1ceda987452fb8"
}
]
}

chain_get_era_summary_result

ParameterTypeDescription
api_versionStringThe RPC API version.
era_summaryObjectThe era summary (if found).
Example chain_get_era_summary result

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"api_version": "1.0.0",
"era_summary": {
"block_hash": "9bfa58709058935882a095ca6adf844b72a2ddf0f49b8575ef1ceda987452fb8",
"era_id": 1,
"stored_value": {
"EraInfo": {
"seigniorage_allocations": [
{
"Delegator": {
"delegator_public_key": "01c08939bf1ecd1139448d435989a761c975466d30b96c2dd74e9d23c7b12bc9ff",
"validator_public_key": "01039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b",
"amount": "53472520551166781393617756"
}
},
{
"Validator": {
"validator_public_key": "01039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b",
"amount": "54552773491594393138943367"
}
},
{
"Delegator": {
"delegator_public_key": "01264689a5b4c57dac1088cd0aae8074de105f2269f6041e2c120e80df7a95e6b5",
"validator_public_key": "013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c18726",
"amount": "51312014670568117976319374"
}
},
{
"Validator": {
"validator_public_key": "013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c18726",
"amount": "56713279372733183026458256"
}
},
{
"Delegator": {
"delegator_public_key": "016f571eaf1d3a442e684ecdb31d00a51448dcbaa06d00b340983311f0ba3e76db",
"validator_public_key": "0186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f12",
"amount": "51852141140784624481333262"
}
},
{
"Validator": {
"validator_public_key": "0186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f12",
"amount": "56173152902516676521444368"
}
},
{
"Delegator": {
"delegator_public_key": "0161e7ed5c592f16b507b9dd196662b530f9bde6c5b2cfd957fe8d0700ecfbe20b",
"validator_public_key": "01d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b",
"amount": "52392267611001130986347150"
}
},
{
"Validator": {
"validator_public_key": "01d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b",
"amount": "55633026432300170016430480"
}
},
{
"Delegator": {
"delegator_public_key": "01b1339a1d114036d84d7b65c804669166d38456114657abbb0e53e67bf1667c60",
"validator_public_key": "01dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f",
"amount": "52932394080952975520954950"
}
},
{
"Validator": {
"validator_public_key": "01dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f",
"amount": "55092899961808199011606173"
}
}
]
}
},
"state_root_hash": "918abd1973171867e03c1e6e56fd7dd9da35c92461784f9a15c0df23e437d850",
"merkle_proof": "010000000e0000000000000000000000000000000000000000000000000000000000000000070a0000000101c08939bf1ecd1139448d435989a761c975466d30b96c2dd74e9d23c7b12bc9ff01039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b0b5c4316483512c2253f3b2c0001039c258651e04597d786142d9749922245cf44b6cc0c93c58bd6c1783ac3be9b0b87d59268bf17d8c6ff1f2d0101264689a5b4c57dac1088cd0aae8074de105f2269f6041e2c120e80df7a95e6b5013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c187260b8e45261378f096e3bd712a00013e193dec433a73a0b41b924243c62311689648a10b4468f9c609c75674c187260b90eee69bba24050981e92e01016f571eaf1d3a442e684ecdb31d00a51448dcbaa06d00b340983311f0ba3e76db0186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f120b0ef09fedb1f521341ee42a000186d12379939682ae9669b354f7a637ec106369074d567b969cc0e2127c904f120b10446dc1801f7ab820772e010161e7ed5c592f16b507b9dd196662b530f9bde6c5b2cfd957fe8d0700ecfbe20b01d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b0b8e9a19c8ebfaac847e562b0001d4cbef55ed9968171102aa136c9564286211ee46c5ab65b6fd68fab5b14d4c4b0b9099f3e6461aef67c0042e0101b1339a1d114036d84d7b65c804669166d38456114657abbb0e53e67bf1667c6001dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f0b46fad737700f37d5dec82b0001dbce10c8418c21daf16bc1052a486cdb557ba66b09a84605bc1f4b3df364960f0b9d1ed178841a631760922d01000000000e060000000001fb7043fe388fef916937aa899a0dda9b042168149e600fb068ecb16839d545d60101a0676758b903440b28c8f4a1d46404e9879fcfc0b90dad20962536de493aecc302013584bc9d5c00ac639fe14410b4cfa480b12eddd8f3dce08d7b76ae47977c1c680601664224aca1272e2a5632da4a56399dee6c585318ebbb7bb4040039792d3ad33c07013b48237cd26eb35ec3c864e1ae250ca656d00893de1dfc4c951e0d779adeda1d0a002c722cac61792676eb19d773fd3c41e37a63f54f78bdf7712ca96a5c5e5c4986"
}
}
}

chain_get_state_root_hash

This method returns a state root hash at a given Block. If you do not specify a block_identifier, you will receive the highest state root hash.

ParameterTypeDescription
block_identifierObjectThe Block hash. (Optional)
Example chain_get_state_root_hash request

{
"id": 1,
"jsonrpc": "2.0",
"method": "chain_get_state_root_hash",
"params": [
{
"Height": 10
}
]
}

chain_get_state_root_hash_result

ParameterTypeDescription
api_versionStringThe RPC API version.
state_root_hashStringHex-encoded hash of the state root.
Example chain_get_state_root_hash result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808"
}
}

info_get_chainspec

This method returns raw bytes for chainspec files.

Example info_get_chainspec request

{
"jsonrpc": "2.0",
"method": "info_get_chainspec",
"id": 5510244237763930243
}

info_get_chainspec_result

ParameterTypeDescription
api_versionStringThe RPC API version.
chainspec_bytesObjectThe raw bytes of the chainspec.toml, genesis accounts.toml, and global_state.toml files.
Example info_get_chainspec result

Please note that adding a --vv flag will return the full chainspec bytes.


{
"jsonrpc": "2.0",
"result": {
"api_version": "1.5.0",
"chainspec_bytes": {
"chainspec_bytes": "[22040 hex chars]",
"maybe_genesis_accounts_bytes": null,
"maybe_global_state_bytes": null
}
},
"id": 5510244237763930243
}

info_get_deploy

This method retrieves a Deploy from a network. It requires a deploy_hash to query the Deploy.

ParameterTypeDescription
deploy_hashStringThe Deploy hash.
finalized_approvalsBooleanDetermines whether to return the Deploy with the finalized approvals substituted. (Optional)
Example info_get_deploy request

{
"id": 1,
"jsonrpc": "2.0",
"method": "info_get_deploy",
"params": [
"5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa",
true
]
}

info_get_deploy_result

The response contains the Deploy and the results of executing the Deploy.

If the execution_results field is empty, it means that the network processed the Deploy, but has yet to execute it. If the network executed the Deploy, it will return the results of the execution. The execution results contain the Block hash which contains the Deploy.

ParameterTypeDescription
api_versionStringThe RPC API version.
deployObjectThe Deploy.
execution_resultsArrayAn array of execution results with Block hashes.
Example info_get_deploy result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"deploy": {
"approvals": [
{
"signature": "014c1a89f92e29dd74fc648f741137d9caf4edba97c5f9799ce0c9aa6b0c9b58db368c64098603dbecef645774c05dff057cb1f91f2cf390bbacce78aa6f084007",
"signer": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c"
}
],
"hash": "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa",
"header": {
"account": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",
"body_hash": "d53cf72d17278fd47d399013ca389c50d589352f1a12593c0b8e01872a641b50",
"chain_name": "casper-example",
"dependencies": [
"0101010101010101010101010101010101010101010101010101010101010101"
],
"gas_price": 1,
"timestamp": "2020-11-17T00:39:24.072Z",
"ttl": "1h"
},
"payment": {
"StoredContractByName": {
"args": [
[
"amount",
{
"bytes": "e8030000",
"cl_type": "I32",
"parsed": 1000
}
]
],
"entry_point": "example-entry-point",
"name": "casper-example"
}
},
"session": {
"Transfer": {
"args": [
[
"amount",
{
"bytes": "e8030000",
"cl_type": "I32",
"parsed": 1000
}
]
]
}
}
},
"execution_results": [
{
"block_hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",
"result": {
"Success": {
"cost": "123456",
"effect": {
"operations": [
{
"key": "account-hash-2c4a11c062a8a337bfc97e27fd66291caeb2c65865dcb5d3ef3759c4c97efecb",
"kind": "Write"
},
{
"key": "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1",
"kind": "Read"
}
],
"transforms": [
{
"key": "uref-2c4a11c062a8a337bfc97e27fd66291caeb2c65865dcb5d3ef3759c4c97efecb-007",
"transform": {
"AddUInt64": 8
}
},
{
"key": "deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1",
"transform": "Identity"
}
]
},
"transfers": [
"transfer-5959595959595959595959595959595959595959595959595959595959595959",
"transfer-8282828282828282828282828282828282828282828282828282828282828282"
]
}
}
}
]
}
}

query_balance

This method allows you to query for the balance of a purse using a PurseIdentifier and StateIdentifier.

ParameterTypeDescription
purse_identifierObjectThe identifier to obtain the purse corresponding to the balance query.
state_identifierObjectThe state identifier used for the query; if none is passed the tip of the chain will be used.
Example query_balance request
{
"id": 1,
"jsonrpc": "2.0",
"method": "query_balance",
"params": [
{
"name": "state_identifier",
"value": {
"BlockHash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"
}
},
{
"name": "purse_identifier",
"value": {
"main_purse_under_account_hash": "account-hash-0909090909090909090909090909090909090909090909090909090909090909"
}
}
]
}

query_balance_result

ParameterTypeDescription
api_versionStringThe RPC API version.
balanceObjectThe balance represented in motes.
Example query_balance result

{
"jsonrpc": "2.0",
"id": -6143675785141640608,
"result": {
"api_version": "1.0.0",
"balance": "1000000000000000000000000000000000"
}
}

query_global_state

This method allows for you to query for a value stored under certain keys in global state. You may query using either a Block hash or state root hash.

  • Note: Querying a purse's balance requires the use of query_balance, rather than any iteration of query_global_state.
ParameterTypeDescription
state_identifierObjectThe identifier used for the query.
keyStringcasper_types::Key as a formatted string.
pathArrayThe path components starting from the key as base.
Example query_global_state request

{
"id": 1,
"jsonrpc": "2.0",
"method": "query_global_state",
"params": [
"deploy-af684263911154d26fa05be9963171802801a0b6aff8f199b7391eacb8edc9e1",
[],
{
"BlockHash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"
}
]
}

query_global_state_result

ParameterTypeDescription
api_versionStringThe RPC API version.
block_headerObjectThe Block header if a Block hash was provided. (Not required)
stored_valueObjectThe stored value.
merkle_proofStringThe merkle proof.
Example query_global_state result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"block_header": {
"accumulated_seed": "ac979f51525cfd979b14aa7dc0737c5154eabe0db9280eceaa8dc8d2905b20d5",
"body_hash": "cd502c5393a3c8b66d6979ad7857507c9baf5a8ba16ba99c28378d3a970fff42",
"era_end": {
"era_report": {
"equivocators": [
"013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"
],
"inactive_validators": [
"018139770ea87d175f56a35466c34c7ecccb8d8a91b4ee37a25df60f5b8fc9b394"
],
"rewards": [
{
"amount": 1000,
"validator": "018a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c"
}
]
},
"next_era_validator_weights": [
{
"validator": "016e7a1cdd29b0b78fd13af4c5598feff4ef2a97166e3ca6f2e4fbfccd80505bf1",
"weight": "456"
},
{
"validator": "018a875fff1eb38451577acd5afee405456568dd7c89e090863a0557bc7af49f17",
"weight": "789"
},
{
"validator": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",
"weight": "123"
}
]
},
"era_id": 1,
"height": 10,
"parent_hash": "0707070707070707070707070707070707070707070707070707070707070707",
"protocol_version": "1.0.0",
"random_bit": true,
"state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",
"timestamp": "2020-11-17T00:39:24.072Z"
},
"merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3",
"stored_value": {
"Account": {
"account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",
"weight": 1
}
],
"main_purse": "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007",
"named_keys": []
}
}
}
}

state_get_account_info

This method returns a JSON representation of an Account from the network. The block_identifier must refer to a Block after the Account's creation, or the method will return an empty response.

ParameterTypeDescription
public_keyStringThe public key of the Account.
block_identifierObjectThe Block identifier.
Example state_get_account_info request

{
"id": 1,
"jsonrpc": "2.0",
"method": "state_get_account_info",
"params": [
{
"Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"
},
"013b6a27bcceb6a42d62a3a8d02a6f0d73653215771de243a63ac048a18b59da29"
]
}

state_get_account_info_result

ParameterTypeDescription
api_versionStringThe RPC API version.
accountObjectA JSON representation of the Account structure.
merkle_proofStringThe merkle proof.
Example state_get_account_info result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"account": {
"account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_hash": "account-hash-e94daaff79c2ab8d9c31d9c3058d7d0a0dd31204a5638dc1451fa67b2e3fb88c",
"weight": 1
}
],
"main_purse": "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007",
"named_keys": []
},
"api_version": "1.4.13",
"merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3"
}
}

state_get_dictionary_item

This method returns an item from a Dictionary. Every dictionary has a seed URef, findable by using a dictionary_identifier. The address of a stored value is the blake2b hash of the seed URef and the byte representation of the dictionary key.

You may query a stored value directly using the dictionary address.

ParameterTypeDescription
state_root_hashStringHash of the state root.
dictionary_identifierObjectThe Dictionary query identifier.
Example state_get_dictionary_item request

{
"id": 1,
"jsonrpc": "2.0",
"method": "state_get_dictionary_item",
"params": [
{
"URef": {
"dictionary_item_key": "a_unique_entry_identifier",
"seed_uref": "uref-09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db-007"
}
},
"0808080808080808080808080808080808080808080808080808080808080808"
]
}

### `state_get_dictionary_item_result`
ParameterTypeDescription
api_versionStringThe RPC API version.
dictionary_keyStringThe key under which the value is stored.
stored_valueObjectThe stored value.
merkle_proofStringThe merkle proof.
Example state_get_dictionary_item result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"dictionary_key": "dictionary-67518854aa916c97d4e53df8570c8217ccc259da2721b692102d76acd0ee8d1f",
"merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3",
"stored_value": {
"CLValue": {
"bytes": "0100000000000000",
"cl_type": "U64",
"parsed": 1
}
}
}
}


Node Informational JSON-RPC Methods

The following methods return information from a node on a Casper network. The responses return information specific to the queried node, and as such, will vary.


info_get_peers

This method returns a list of peers connected to the node.

Example info_get_peers request

{
"id": 1,
"jsonrpc": "2.0",
"method": "info_get_peers",
"params": []
}

info_get_peers_result

ParameterTypeDescription
api_versionStringThe RPC API version.
peersArrayThe node ID and network address of each connected peer.
Example info_get_peers result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"peers": [
{
"address": "127.0.0.1:54321",
"node_id": "tls:0101..0101"
}
]
}
}

info_get_status

This method returns the current status of a node.

Example info_get_status request

{
"id": 1,
"jsonrpc": "2.0",
"method": "info_get_status",
"params": []
}

info_get_status_result

ParameterTypeDescription
api_versionStringThe RPC API version.
available_block_rangeObjectThe available block range in storage.
block_syncObjectThe status of the block synchronizer builders.
build_versionStringThe compiled node version.
chainspec_nameStringThe chainspec name, used to identify the currently connected network.
last_added_block_infoObjectThe minimal info of the last Block from the linear chain.
last_progressStringTimestamp of the last recorded progress in the reactor.
next_upgradeObjectInformation about the next scheduled upgrade.
our_public_signing_keyStringOur public signing key.
peersArrayThe node ID and network address of each connected peer.
reactor_stateStringThe current state of the node reactor.
round_lengthIntegerThe next round length if this node is a validator. A round length is the amount of time it takes to reach consensus on proposing a Block.
starting_state_root_hashStringThe state root hash used at the start of the current session.
uptimeIntegerTime that passed since the node has started.
Example info_get_status result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"name": "info_get_status_result",
"value": {
"peers": [
{
"node_id": "tls:0101..0101",
"address": "127.0.0.1:54321"
}
],
"api_version": "1.4.8",
"build_version": "1.0.0-xxxxxxxxx@DEBUG",
"chainspec_name": "casper-example",
"starting_state_root_hash": null,
"last_added_block_info": {
"hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",
"timestamp": "2020-11-17T00:39:24.072Z",
"era_id": 1,
"height": 10,
"state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",
"creator": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c"
},
"our_public_signing_key": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",
"round_length": "1m 5s 536ms",
"next_upgrade": {
"activation_point": 42,
"protocol_version": "2.0.1"
},
"uptime": "13s",
"reactor_state": "Initialize",
"last_progress": "1970-01-01T00:00:00.000Z",
"available_block_range": {
"low": 0,
"high": 0
},
"block_sync": {
"historical": {
"block_hash": "16ddf28e2b3d2e17f4cef36f8b58827eca917af225d139b0c77df3b4a67dc55e",
"block_height": 40,
"acquisition_state": "have strict finality(40) for: block hash 16dd..c55e"
},
"forward": {
"block_hash": "59907b1e32a9158169c4d89d9ce5ac9164fc31240bfcfb0969227ece06d74983",
"block_height": 6701,
"acquisition_state": "have block body(6701) for: block hash 5990..4983"
}
}
}
}

Proof-of-Stake JSON-RPC Methods

The following methods pertain to the Proof-of-Stake functionality of a Casper network. They return information related to auctions, bids and validators. This information is necessary for users involved with node operations and validation.


state_get_auction_info

This method returns the bids and validators as of either a specific Block (by height or hash). If you do not provide a block_identifier, state_get_auction_info will return information from the most recent Block.

ParameterTypeDescription
block_identifierObjectThe Block identifier.
Example state_get_auction_info request

{
"id": 1,
"jsonrpc": "2.0",
"method": "state_get_auction_info",
"params": [
{
"Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"
}
]
}

state_get_auction_info_result

ParameterTypeDescription
api_versionStringThe RPC API version.
auction_stateObjectThe auction state.
Example state_get_auction_info result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"auction_state": {
"bids": [
{
"bid": {
"bonding_purse": "uref-fafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafa-007",
"delegation_rate": 0,
"delegators": [],
"inactive": false,
"staked_amount": "10"
},
"public_key": "01197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61"
}
],
"block_height": 10,
"era_validators": [
{
"era_id": 10,
"validator_weights": [
{
"public_key": "01197f6b23e16c8532c6abc838facd5ea789be0c76b2920334039bfa8b3d368d61",
"weight": "10"
}
]
}
],
"state_root_hash": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
}
}
}

info_get_validator_changes

This method returns status changes of active validators. Listed changes occurred during the EraId contained within the response itself. A validator may show more than one change in a single era.

Potential change types:

Change TypeDescription
AddedThe validator has been added to the set.
RemovedThe validator has been removed from the set.
BannedThe validator has been banned in the current era.
CannotProposeThe validator cannot propose a Block.
SeenAsFaultyThe validator has performed questionable activity.
Example info_get_validator_changes request

{
"id": 1,
"jsonrpc": "2.0",
"method": "info_get_validator_changes",
"params": []
}

info_get_validator_changes_result

If no changes occurred in the current era, info_get_validator_changes will return empty.

ParameterTypeDescription
api_versionStringThe RPC API version.
changesObjectThe validators' status changes.
Example info_get_validator_changes result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"changes": [
{
"public_key": "01d9bf2148748a85c89da5aad8ee0b0fc2d105fd39d41a4c796536354f0ae2900c",
"status_changes": [
{
"era_id": 1,
"validator_change": "Added"
}
]
}
]
}
}

chain_get_era_info_by_switch_block

This method returns an EraInfo from the network. Only the last Block in an era, known as a switch block, will contain an era_summary.

ParameterTypeDescription
block_identifierObjectThe Block identifier. If you do not supply a block_identifier, the returned information will be the most recent Block. (Optional)
Example chain_get_era_info_by_switch_block request

{
"id": 1,
"jsonrpc": "2.0",
"method": "chain_get_era_info_by_switch_block",
"params": [
{
"Hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb"
}
]
}

chain_get_era_info_by_switch_block_result

ParameterTypeDescription
api_versionStringThe RPC API version.
era_summaryObjectThe era summary (If found).
Example chain_get_era_info_by_switch_block

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"era_summary": {
"block_hash": "13c2d7a68ecdd4b74bf4393c88915c836c863fc4bf11d7f2bd930a1bbccacdcb",
"era_id": 42,
"merkle_proof": "01000000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625016ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a72536147614625000000003529cde5c621f857f75f3810611eb4af3f998caaa9d4a3413cf799f99c67db0307010000006ef2e0949ac76e55812421f755abe129b6244fe7168b77f47a7253614761462501010102000000006e06000000000074769d28aac597a36a03a932d4b43e4f10bf0403ee5c41dd035102553f5773631200b9e173e8f05361b681513c14e25e3138639eb03232581db7557c9e8dbbc83ce94500226a9a7fe4f2b7b88d5103a4fc7400f02bf89c860c9ccdd56951a2afe9be0e0267006d820fb5676eb2960e15722f7725f3f8f41030078f8b2e44bf0dc03f71b176d6e800dc5ae9805068c5be6da1a90b2528ee85db0609cc0fb4bd60bbd559f497a98b67f500e1e3e846592f4918234647fca39830b7e1e6ad6f5b7a99b39af823d82ba1873d000003000000010186ff500f287e9b53f823ae1582b1fa429dfede28015125fd233a31ca04d5012002015cc42669a55467a1fdf49750772bfc1aed59b9b085558eb81510e9b015a7c83b0301e3cf4a34b1db6bfa58808b686cb8fe21ebe0c1bcbcee522649d2b135fe510fe3",
"state_root_hash": "0808080808080808080808080808080808080808080808080808080808080808",
"stored_value": {
"EraInfo": {
"seigniorage_allocations": [
{
"Delegator": {
"amount": "1000",
"delegator_public_key": "01e1b46a25baa8a5c28beb3c9cfb79b572effa04076f00befa57eb70b016153f18",
"validator_public_key": "012a1732addc639ea43a89e25d3ad912e40232156dcaa4b9edfc709f43d2fb0876"
}
},
{
"Validator": {
"amount": "2000",
"validator_public_key": "012a1732addc639ea43a89e25d3ad912e40232156dcaa4b9edfc709f43d2fb0876"
}
}
]
}
}
}
}
}

Transactional JSON-RPC Methods


account_put_deploy

This is the only means by which users can send their compiled Wasm (as part of a Deploy) to a node on a Casper network. The request takes in the Deploy as a parameter, prior to sending it to a node on a network for execution.

ParameterTypeDescription
deployObjectA Deploy consists of an item containing a smart contract along with the requester's signature(s).

Note: You can find a list of trusted peers in the network's configuration file, config.toml. Here is an example config.toml. You may send deploys to one of the trusted nodes or use them to query other online nodes.

Example account_put_deploy request

{
"id": 1,
"jsonrpc": "2.0",
"method": "account_put_deploy",
"params": [
{
"approvals": [
{
"signer": "01f8b29f39c38600ecb3bbb082951e04ab63a4ad4f7c9048a5057e461a5a8d58a5",
"signature": "019d6ef5c62c80ad4e50df343fba6f0fced17dea4c65e7976f66335ffcfcde2a7f02e928c8507cef3c76c3151e0e9cc9c3f7838b9f7a99ac4be5522ca092841100"
}
],
"hash": "00a8677713222df88b6988926e0b14adeda6c663957f5075003395da4e5c6888",
"header": {
"account": "01f8b29f39c38600ecb3bbb082951e04ab63a4ad4f7c9048a5057e461a5a8d58a5",
"body_hash": "145ae09d6da5bc290051db8cb7132a41a30473d5900eaaf409d92b666325ca00",
"chain_name": "casper-net-1",
"dependencies": [
"0101010101010101010101010101010101010101010101010101010101010101"
],
"gas_price": 1,
"timestamp": "2023-09-26T14:07:10.024Z",
"ttl": "1h"
},
"payment": {
"StoredContractByName": {
"args": [
[
"amount",
{
"bytes": "0400f90295",
"cl_type": "U512"
}
]
],
"entry_point": "example-entry-point",
"name": "casper-example"
}
},
"session": {
"Transfer": {
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400f90295"
}
],
[
"target",
{
"cl_type": "URef",
"bytes": "09480c3248ef76b603d386f3f4f8a5f87f597d4eaffd475433f861af187ab5db07"
}
]
]
}
}
}
]
}

account_put_deploy_result

The result contains the deploy_hash, which is the primary identifier of a Deploy within a Casper network.

ParameterTypeDescription
api_versionStringThe RPC API version.
deploy_hashStringA hex-encoded hash of the Deploy as sent.
Example account_put_deploy result

{
"id": 1,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"deploy_hash": "5c9b3b099c1378aa8e4a5f07f59ff1fcdc69a83179427c7e67ae0377d94d93fa"
}
}

speculative_exec

The speculative_exec endpoint provides a method to execute a Deploy without committing its execution effects to global state. By default, speculative_exec is disabled on a node. Sending a request to a node with the endpoint disabled will result in an error message. If enabled, speculative_exec operates on a separate port from the primary JSON-RPC, using 7778.

speculative_exec executes a Deploy at a specified block. In the case of this endpoint, the execution effects are not committed to global state. As such, it can be used for observing the execution effects of a Deploy without paying for the execution of the Deploy.

ParameterTypeDescription
block_identifierObjectThe block hash or height on top of which to execute the deploy. If not supplied,the most recent block will be used.
deployObjectA Deploy consists of an item containing a smart contract along with the requester's signature(s).
Example speculative_exec request

{
"jsonrpc": "2.0",
"method": "speculative_exec",
"params": {
"block_identifier": null,
"deploy": {
"hash": "b6aa46333fb858deee7f259a5bca581251c6200a5d902aeb1244c3a7169b5971",
"header": {
"account": "01a2905e4680aa49e0b44100d9dfc861b9605bb35f9956b1e99eb43863363d80aa",
"timestamp": "2023-05-23T13:32:45.554Z",
"ttl": "30m",
"gas_price": 1,
"body_hash": "74db109805bb20de43ef89a5b084544a858908b236601519d5827cd9b7fbb925",
"dependencies": [],
"chain_name": "integration-test"
},
"payment": {
"ModuleBytes": {
"module_bytes": "",
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400e1f505",
"parsed": "100000000"
}
]
]
}
},
"session": {
"Transfer": {
"args": [
[
"amount",
{
"cl_type": "U512",
"bytes": "0400f90295",
"parsed": "2500000000"
}
],
[
"target",
{
"cl_type": "PublicKey",
"bytes": "01265ea737411b349ad3d0fc724c2c588acd2765c057e5c690cd5e3dade401782b",
"parsed": "01265ea737411b349ad3d0fc724c2c588acd2765c057e5c690cd5e3dade401782b"
}
],
[
"id",
{
"cl_type": {
"Option": "U64"
},
"bytes": "010000000000000000",
"parsed": 0
}
]
]
}
},
"approvals": [
{
"signer": "01a2905e4680aa49e0b44100d9dfc861b9605bb35f9956b1e99eb43863363d80aa",
"signature": "01c94d517d5bbc8d5c74e0e68b8cb308561ff979a1c91907b56d427cc90156c437726c0b736d17f7303f2db66e405c7e5c8175b8b863703938eff1659766dff808"
}
]
}
},
"id": 6889533540839698701
}

speculative_exec_result

The result contains the hash of the targeted block and the results of the execution.

ParameterTypeDescription
api_versionStringThe RPC API version.
block_hashObjectThe Block hash on top of which the deploy was executed.
execution_resultsObjectThe map of Block hash to execution result.
Example speculative_exec result

{
"jsonrpc": "2.0",
"id": -8801853076373554652,
"result": {
"api_version": "1.5.0",
"block_hash": "ff862326b08702a5089d64e32100537b7ff984cac4c0ba6d1c561f7c47125f76",
"execution_result": {
"Success": {
"effect": {
"operations": [],
"transforms": [
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",
"transform": "Identity"
},
{
"key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",
"transform": "Identity"
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "hash-0a300922655180354a9ee92b808c7b45b08e5b01d9da0bac9a9b3415bcebbf8d",
"transform": "Identity"
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",
"transform": "Identity"
},
{
"key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",
"transform": "Identity"
},
{
"key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",
"transform": {
"WriteCLValue": {
"cl_type": "U512",
"bytes": "05f0e630ed87",
"parsed": "583799990000"
}
}
},
{
"key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",
"transform": {
"AddUInt512": "100000000"
}
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",
"transform": "Identity"
},
{
"key": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",
"transform": "Identity"
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "hash-0a300922655180354a9ee92b808c7b45b08e5b01d9da0bac9a9b3415bcebbf8d",
"transform": "Identity"
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",
"transform": "Identity"
},
{
"key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",
"transform": "Identity"
},
{
"key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",
"transform": {
"WriteCLValue": {
"cl_type": "U512",
"bytes": "05f0e630ed87",
"parsed": "583799990000"
}
}
},
{
"key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",
"transform": {
"AddUInt512": "100000000"
}
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",
"transform": "Identity"
},
{
"key": "balance-92ec6dfbdf151e20b55c89e0a327959cf6e5b091c5f2b39201c1858e2943f3bd",
"transform": "Identity"
},
{
"key": "balance-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678",
"transform": {
"WriteCLValue": {
"cl_type": "U512",
"bytes": "05f0ed2d5887",
"parsed": "581299990000"
}
}
},
{
"key": "balance-92ec6dfbdf151e20b55c89e0a327959cf6e5b091c5f2b39201c1858e2943f3bd",
"transform": {
"AddUInt512": "2500000000"
}
},
{
"key": "transfer-97426c848475dae98446f2c2fd00ec7901cd8ddfe250171ff4ed25d78412a612",
"transform": {
"WriteTransfer": {
"deploy_hash": "d898910011b1f2f8797a442740e69cd5de41b9f796e658e962a24663e6199e5a",
"from": "account-hash-0a9b33af5108c5a6e1067b0ddec6853ce1745d591375d767ac5db680d21845e7",
"to": "account-hash-f466e7f5f9240fb577d1d4c650c4063752553406dff7aa24b4822ba2b72e5b65",
"source": "uref-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678-007",
"target": "uref-92ec6dfbdf151e20b55c89e0a327959cf6e5b091c5f2b39201c1858e2943f3bd-004",
"amount": "2500000000",
"gas": "0",
"id": 0
}
}
},
{
"key": "deploy-d898910011b1f2f8797a442740e69cd5de41b9f796e658e962a24663e6199e5a",
"transform": {
"WriteDeployInfo": {
"deploy_hash": "d898910011b1f2f8797a442740e69cd5de41b9f796e658e962a24663e6199e5a",
"transfers": [
"transfer-97426c848475dae98446f2c2fd00ec7901cd8ddfe250171ff4ed25d78412a612"
],
"from": "account-hash-0a9b33af5108c5a6e1067b0ddec6853ce1745d591375d767ac5db680d21845e7",
"source": "uref-7c25ef9382fcae902b922866434f7111a1b34534323e93ff5bf22f1a401c2678-007",
"gas": "100000000"
}
}
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "hash-0a300922655180354a9ee92b808c7b45b08e5b01d9da0bac9a9b3415bcebbf8d",
"transform": "Identity"
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",
"transform": "Identity"
},
{
"key": "hash-d2dfc9409965993f9e186db762b585274dcafe439fa1321cfca08017262c8e46",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "hash-59c6451dd58463708fa0b122e97114f07fa5f609229c9d67ac9426935416fbeb",
"transform": "Identity"
},
{
"key": "hash-f8df015ba26860a7ec8cab4ee99f079325b0bbb9ef0e7810b63d85df39da95fe",
"transform": "Identity"
},
{
"key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",
"transform": "Identity"
},
{
"key": "balance-ecc530e74cf2185936a334aa1e0f07539aa3b33c4b547e71fc4109151755652f",
"transform": "Identity"
},
{
"key": "balance-ea3c9bdcbe57f067a29609d397981b2d0fb39853a0a9f06e444b06404eadcb1a",
"transform": {
"WriteCLValue": {
"cl_type": "U512",
"bytes": "00",
"parsed": "0"
}
}
},
{
"key": "balance-ecc530e74cf2185936a334aa1e0f07539aa3b33c4b547e71fc4109151755652f",
"transform": {
"AddUInt512": "100000000"
}
}
]
},
"transfers": [
"transfer-97426c848475dae98446f2c2fd00ec7901cd8ddfe250171ff4ed25d78412a612"
],
"cost": "100000000"
}
}
}
}

Required Methods for Minimal Compliance

The methods included in this document represent the most basic, fundamental endpoints for a viable and compliant Casper SDK. They allow the user to retrieve the information necessary to interact with a Casper network, as well as the means to interact.

  • chain_get_block - This method returns the JSON representation of a Block from the network. The ongoing validity of the chain depends on block verification, which includes both a record of deploys and transfers.

  • info_get_deploy - This method allows retrieval of a Deploy from a Casper network. Without this method, users will be unable to verify any subsequent information relating to a sent Deploy.

  • account_put_deploy - This method allows users to send their compiled Wasm (as part of a Deploy) to a node on a Casper network. Deploys represent the only means by which a user can perform computation on the platform, without which their interaction with a Casper network will be entirely passive.

  • chain_get_state_root_hash - The state root hash is one of the several global state identifiers used to query the network state after sending deploys.

  • state_get_account_info - This method returns a JSON representation of an Account from the network. state_get_account_info is required to view associated account information, including any associated keys, named keys, action thresholds and the main purse.

  • query_balance - This method returns a purse's balance from a network. This is the only method to return a purse's balance in a human-readable format.

  • state_get_dictionary_item - This method returns an item from a Dictionary. Dictionaries represent a more efficient means of tracking large amounts of state.

  • query_global_state - This method allows for querying values stored under certain keys in global state. Aside from purse balances, this is the main means of recovering stored data from a Casper network.

note

The deprecated method state_get_balance should not be used.

In addition to these methods, a minimally compliant Casper SDK must account for the types associated with each method. Each method above links to the expanded information available within the larger JSON RPC method pages, which includes the necessary associated types.

Types

The following definitions expand on parameters seen elsewhere within the SDK standard and are provided for clarity and completeness.

Account

Structure representing a user's Account, stored in global state.

Required Parameters:

AccountHash

The AccountHash is a 32-byte hash derived from a supported PublicKey. Its role is to standardize keys that can vary in length.

ActionThresholds

Thresholds that have to be met when executing an action of a certain type.

Required Parameters:

  • deployment

  • key_management

ActivationPoint

The first era to which the associated protocol version applies.

Approval

A struct containing a signature and the public key of the signer.

Required Parameters:

AssociatedKey

A key granted limited permissions to an Account, for purposes such as multisig.

Required Parameters:

AuctionState

Data structure summarizing auction contract data.

Required Parameters:

AvailableBlockRange

  • low The inclusive lower bound of the range.

  • high The inclusive upper bound of the range.

Bid

An entry in the validator map.

Required Parameters:

  • bonding_purse The purse that was used for bonding.

  • delegation_rate The delegation rate.

  • delegators The validator's delegators, indexed by their public keys.

  • inactive true if validator has been "evicted".

  • staked_amount The amount of tokens staked by a validator (not including delegators).

  • validator_public_key Validator's public key.

Additional Parameters:

  • vesting_schedule Vesting schedule for a genesis validator. None if non-genesis validator.

BlockHash

A cryptographic hash identifying a Block.

BlockIdentifier

Identifier for possible ways to retrieve a Block.

  • Hash Identify and retrieve the Block with its hash.

  • Height Identify and retrieve the Block with its height.

BlockSynchronizerStatus

The status of the block synchronizer.

  • Historical The status of syncing a historical block, if any.

    • block_hash The block hash.

    • block_height The height of the block, if known.

    • acquisition_state The state of acquisition of the data associated with the block.

  • Forward The status of syncing a forward block, if any.

    • block_hash The block hash.

    • block_height The height of the block, if known.

    • acquisition_state The state of acquisition of the data associated with the block.

ChainspecRawBytes

The raw bytes of the chainspec.toml, genesis accounts.toml, and global_state.toml files.

  • chainspec_bytes Hex-encoded raw bytes of the current chainspec.toml file.

  • maybe_genesis_accounts_bytes Hex-encoded raw bytes of the current genesis accounts.toml file.

  • maybe_global_state_bytes Hex-encoded raw bytes of the current global_state.toml file.

Contract

A contract struct that can be serialized as a JSON object.

Required Parameters:

contract_package_hash

contract_wasm_hash

entry_points

named_keys

protocol_version

ContractHash

The hash address of the contract.

ContractPackage

Contract definition, metadata and security container.

Required Parameters:

ContractPackageHash

The hash address of the contract package.

ContractVersion

The version of the contract.

Required Parameters:

ContractWasmHash

The hash address of the contract Wasm.

Delegator

Represents a party delegating their stake to a validator (or "delegatee").

Required Parameters:

Additional Parameters:

Deploy

A Deploy; an item containing a smart contract along with the requester's signature(s).

Required properties:

DeployHash

Hex-encoded Deploy hash.

DeployHeader

The header portion of a Deploy.

Required Parameters:

DeployInfo

Information relating to the given Deploy.

Required Parameters:

  • deploy_hash The relevant Deploy.

  • from Account identifier of the creator of the Deploy.

  • gas Gas cost of executing the Deploy.

  • source Source purse used for payment of the Deploy.

  • transfers Transfers performed by the Deploy.

DictionaryIdentifier

Options for dictionary item lookups.

  • AccountNamedKey Lookup a dictionary item via an Account's named keys.

    Required Parameters:

    key The Account key as a formatted string whose named keys contain dictionary_name.

    dictionary_name The named key under which the dictionary seed URef is stored.

    dictionary_item_key The dictionary item key formatted as a string.

  • ContractNamedKey Lookup a dictionary item via a Contract's named keys.

    key The contract key as a formatted string whose named keys contains dictionary_name.

    dictionary_name The named key under which the dictionary seed URef is stored.

    dictionary_item_key The dictionary item key formatted as a string.

  • URef Lookup a dictionary item via its seed URef.

    seed_uref The dictionary's seed URef.

    dictionary_item_key The dictionary item key formatted as a string.

  • Dictionary Lookup a dictionary item via its unique key.

Digest

Hex-encoded hash digest.

DisabledVersions

Required Parameters:

  • contract_version

  • protocol_version_major

EntryPoint

Metadata describing a callable entry point and its return value, if any. All required parameters should be declared, whereas all non-required parameters should not be declared. Non-required parameters should not be confused with optional parameters.

Required Parameters:

EntryPointAccess

Enum describing the possible access control options for a contract entry point.

  • Public A public entry point is callable by any caller.

  • Groups Only callers from the authorized, listed groups may call this entry point. Note: If this list is empty then this entry point is not callable from outside the contract.

EntryPointType

Context of an entry point execution.

  • session Executes in the caller's context.

  • contract Executes in the callee's context.

EraID

Era ID newtype.

EraInfo

Auction metadata. Intended to be recorded at each era.

Required Parameters:

EraSummary

The summary of an era.

Required Parameters:

ExecutableDeployItem

Represents possible variants of an executable Deploy.

ModuleBytes

Executable specified as raw bytes that represent Wasm code and an instance of RuntimeArgs.

Required Parameters:

  • module_bytes Hex-encoded raw Wasm bytes. There are some special cases around passing module_bytes for payment code.

Additional Parameters:

  • args Runtime arguments.

StoredContractByHash

Stored contract referenced by its ContractHash, entry point and an instance of RuntimeArgs.

Required Parameters:

  • args Runtime arguments.

  • entry_point The name of an entry point.

  • hash A hex-encoded hash.

StoredContractByName

Stored contract referenced by a named key existing in the signer's Account context, entry point and an instance of RuntimeArgs.

Required Parameters:

  • args Runtime arguments.

  • entry_point The name of an entry point.

  • name A named key.

StoredVersionContractByHash

Stored versioned contract referenced by its ContractPackageHash, entry point and an instance of RuntimeArgs.

Required Parameters:

  • args Runtime arguments.

  • entry_point The name of an entry point.

  • hash A hex-encoded hash.

Additional Parameters:

  • version An optional version of the contract to call. It will default to the highest enabled version if no value is specified.

StoredVersionContractByName

Stored versioned contract referenced by a named key existing in the signer's Account context, entry point and an instance of RuntimeArgs.

Required Parameters:

  • args Runtime arguments.

  • entry_point The name of an entry point.

  • name A named key.

Additional Parameters:

  • version An optional version of the contract to call. It will default to the highest enabled version if no value is specified.

Transfer

A native transfer which does not contain or reference a Wasm code.

Required Parameters:

ExecutionEffect

The journal of execution transforms from a single Deploy.

Required Parameters:

ExecutionResult

The result of executing a single Deploy.

  • Failure The result of a failed execution`

    Required Parameters:

    effect

    transfers

    cost

    error_message The error message associated with executing the Deploy.

  • Success The result of a successful execution.

    Required Parameters:

    effect

    transfers

    cost

FinalizedApprovals

A boolean value that determines whether to return the deploy with the finalized approvals substituted. If false or omitted, returns the deploy with the approvals that were originally received by the node.

GlobalStateIdentifier

Identifier for possible ways to query global state.

Group

A (labelled) "user group". Each entry point of a versioned contract may be associated with one or more user groups which are allowed to call it.

Groups

Required Parameters:

JsonBid

An entry in a founding validator map representing a bid.

Required Parameters:

  • bonding_purse The purse that was used for bonding.

  • delegation_rate The delegation rate.

  • delegators The delegators.

  • inactive Is this an inactive validator.

  • staked_amount The amount of tokens staked by a validator (not including delegators).

JsonBids

A Json representation of a single bid.

Required Parameters:

JsonBlock

A JSON-friendly representation of Block.

Required Parameters:

  • body JSON-friendly Block body.

  • hash BlockHash.

  • header JSON-friendly Block header.

  • proofs JSON-friendly list of proofs for this Block.

JsonBlockBody

A JSON-friendly representation of Body.

Required Parameters:

JsonBlockHeader

JSON representation of a Block header.

Additional Parameters:

JsonDelegator

A delegator associated with the given validator.

Required Parameters:

JsonEraEnd

Required Parameters:

JsonEraReport

Equivocation and reward information to be included in the terminal Block.

Required Parameters:

JsonEraValidators

The validators for the given era.

Required Parameters:

JsonExecutionResult

The execution result of a single Deploy.

JsonProof

A JSON-friendly representation of a proof, i.e. a Block's finality signature.

Required Parameters:

JsonValidatorChanges

The changes in a validator's status.

Required Parameters:

JsonValidatorStatusChange

A single change to a validator's status in the given era.

Required Parameters:

JsonValidatorsWeights

A validator's weight.

Required Parameters:

Merkle_Proof

A merkle proof is a construction created using a merkle trie that allows verification of the associated hashes.

MinimalBlockInfo

Minimal info of a Block.

Required Parameters:

NamedArg

Named arguments to a contract.

NamedKey

A named key.

Required Parameters:

  • key The value of the entry: a casper Key type.

  • name The name of the entry.

NextUpgrade

Information about the next protocol upgrade.

Required Parameters:

NewValidator

The public key for the new validator in a redelegation using UnbondingPurse.

Operation

An operation performed while executing a Deploy.

Required Parameters:

  • key The formatted string of the Key.

  • kind

OpKind

The type of operation performed while executing a Deploy.

Parameter

Parameter to an entry point.

Required Parameters:

PeerEntry

Required Parameters:

  • address

  • node_id

PeersMap

Map of peer IDs to network addresses.

ProtocolVersion

Casper Platform protocol version.

PublicKey

Hex-encoded cryptographic public key, including the algorithm tag prefix.

PurseIdentifier

The identifier to obtain the purse corresponding to a balance query. Valid identifiers include:

  • main_purse_under_public_key The main purse under a provided PublicKey.

  • main_purse_under_account_hash The main purse under a provided AccountHash.

  • purse_uref A specific purse identified by the associated URef.

ReactorState

The state of the reactor, which will return one of the following:

  • Initialize Get all components and reactor state set up on start.

  • CatchUp Orient to the network and attempt to catch up to tip.

  • Upgrading Running commit upgrade and creating immediate switch block.

  • KeepUp Stay caught up with tip.

  • Validate Node is currently caught up and is an active validator.

  • ShutdownForUpgrade Node should be shut down for upgrade.

Reward

Required Parameters:

RuntimeArgs

Represents a collection of arguments passed to a smart contract.

SeigniorageAllocation

Information about a seigniorage allocation.

Signature

Hex-encoded cryptographic signature, including the algorithm tag prefix.

StoredValue

Representation of a value stored in global state. Account, Contract and ContractPackage have their own json_compatibility representation (see their docs for further info).

TimeDiff

Human-readable duration.

Timestamp

Timestamp formatted as per RFC 3339.

Transfer

Represents a transfer from one purse to another.

Required Parameters:

Additional Parameters:

  • id User-defined ID.

  • to Account to which funds are transferred.

TransferAddr

Hex-encoded transfer address.

Transform

The actual transformation performed while executing a Deploy.

  • WriteCLValue Write the given CLValue to global state.

  • WriteAccount Writes the given Account to global state.

  • WriteDeployInfo Writes the given DeployInfo to global state.

  • WriteEraInfo Writes the given EraInfo to global state.

  • WriteTransfer Writes the given Transfer to global state.

  • WriteBid Writes the given Bid to global state.

  • WriteWithdraw Writes the given Withdraw to global state.

  • AddInt32 Adds the given i32.

  • AddUInt64 Adds the given u64.

  • AddUInt128 Adds the given U128.

  • AddUInt256 Adds the given U256.

  • AddUInt512 Adds the given U512.

  • AddKeys Adds the given collection of named keys.

  • Failure A failed transformation, containing an error message.

TransformEntry

A transformation performed while executing a Deploy.

Required Parameters:

  • key The formatted string of the Key.

  • transforms The transformation.

U128

Decimal representation of a 128-bit integer.

U256

Decimal representation of a 256-bit integer.

U512

Decimal representation of a 512-bit integer.

UnbondingPurse

Unbonding purse.

Required Parameters:

URef

Hex-encoded, formatted URef.

ValidatorChange

A change to a validator's status between two eras.

  • Added

  • Removed

  • Banned

  • CannotPropose

  • SeenAsFaulty

ValidatorWeight

Required Parameters:

VestingSchedule

Vesting schedule for a genesis validator.

WithdrawPurse

Withdraw purse, previously known as unbonding purse prior to 1.5. Withdraw purses remain as historical data.

Required Parameters:

CLType

Casper types, i.e. types which can be stored and manipulated by smart contracts. Provides a description of the underlying data type of a CLValue.

    `Bool`
`I32`
`I64`
`U8`
`U32`
`U64`
`U128`
`U256`
`U512`
`Unit`
`String`
`Key`
`URef`
`PublicKey`
`Any`
  • Option Option of a CLType.

  • List Variable-length list of a single CLType (comparable to a Vec).

  • ByteArray Fixed-length list of a single CLType (comparable to a Rust array).

  • Result Result with Ok and Err variants of CLType's.

  • Map Map with keys of a single CLType and values of a single CLType.

  • Tuple1 1-ary tuple of a CLType.

  • Tuple2 2-ary tuple of CLTypes.

  • Tuple3 3-ary tuple of CLTypes.

CLValue

A Casper value, i.e. a value which can be stored and manipulated by smart contracts. It holds the underlying data as a type-erased, serialized Vec<u8> and also holds the CLType of the underlying data as a separate member. The parsed field, representing the original value, is a convenience only available when a CLValue is encoded to JSON, and can always be set to null if preferred.

Development Prerequisites

This page covers the necessary software for your Casper development environment. To develop comfortably, you should use Linux Ubuntu 20.04 or macOS. Developing on Windows is not advised.

caution

Casper does not officially support macOS. If you encounter any problems, reach out to the community on Telegram or Discord.

Preparing your Development Environment

Installing curl

sudo apt install curl

Installing essential Linux packages

sudo apt install build-essential

Installing packages required for Casper tools

sudo apt-get install pkg-config
sudo apt-get install openssl
sudo apt-get install libssl-dev

Installing cargo on Linux

sudo apt install cargo

Installing Rust

Install the Rust programming language if you don't already have it on your computer.

The official Rust guide recommends installing Rust by using curl:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

After your next login, the installation script automatically adds Rust to your system PATH. To start using Rust immediately, run the following command in your shell instead of restarting your terminal. The command will add Rust to your system PATH.

source $HOME/.cargo/env

Verify the installation:

rustup --version

Note: You can also use brew on MacOS or apt on Linux to install Rust.

Installing the Casper Crates

The best and fastest way to set up a Casper Rust project is to use cargo casper, which is the command line tool for creating a Wasm smart contract and tests for use on a Casper network. This tool will create a simple contract, a runtime environment, and a testing framework with a simple test. Cargo is a build system and package manager for Rust (much like pip if you are familiar with Python, or npm and yarn for those familiar with Javascript). It is also possible to use this configuration in your CI/CD pipeline.

cargo install cargo-casper

If you run into any issues with this command and you have not recently installed Rust from scratch, please make sure to update your Rust version with this command:

rustup update

Verify the installation:

cargo-casper --version
note

Familiarize yourself with the essential Casper crates described here.

Installing the Casper Client

The default Casper client is on crates.io. This client can transmit your deploys to a Casper network.

cargo install casper-client

Verify the installation:

casper-client --version

The Casper client can print out help information, which provides an up-to-date list of supported commands. To do so, use the following command:

casper-client --help

You can use help for each command to get the most up-to-date arguments and descriptions.

casper-client <command> --help

Accessing the Casper client source code

You can access the Casper client source code here. The lib directory contains the source for the client library, which may be called directly rather than through the CLI binary. The CLI app casper-client uses this library to implement its functionality.

If you wish to compile it, you will need to first install the nightly Rust toolchain with this command:

rustup toolchain install nightly

Then, compile the source code:

cargo build --release

You will find the casper-client executable in the target/release directory.

Installing CMake

If you plan to compile contracts from the source code, including those provided in the casper-node repository, install CMake with the commands below.

CMake is a popular build tool that we will use, and you may have it installed. If you do, make sure that you have the latest version. If you need to install or upgrade it, follow the steps below or on the CMake website. Once installed, check your version as shown below.

sudo apt-get -y install cmake

Check your version:

cmake --version

Sample output:

cmake version 3.20.0 (or above)

CMake suite maintained and supported by Kitware (kitware.com/cmake).

Installing an IDE

We advise using an integrated development environment such as Visual Studio Code (VSC) for development. There are many IDEs available for Rust development. The most popular IDEs for Rust are the following:

You can use any IDE you wish. Most of our documentation and examples use Visual Studio Code (VSC), a popular IDE with many extensions that might be helpful during development.

If you are using VSC, you might find the following extensions useful:

  • CodeLLDB – An important extension for debugging Rust code
  • rust-analyzer – The official Rust language extension
  • Better TOML – Support for formatting TOML files
  • crates – An extension to help manage crates
  • Error Lens – Enhances the programming experience by highlighting syntax errors

Setting up a Casper Account

The Account creation process consists of two steps:

  1. Creating an Account
  2. Funding the Account

The following video complements the instructions below, showing you the expected output.

Creating an account

The Casper blockchain uses an on-chain account-based model, uniquely identified by an AccountHash derived from a specific PublicKey.

By default, a transactional interaction with the blockchain takes the form of a Deploy cryptographically signed by the key-pair corresponding to the PublicKey used to create the account.

Users can create accounts using the Casper command-line client.

Alternatively, some Casper networks, such as the official Testnet and Mainnet, provide a browser-based block explorer that allows account creation as outlined here.

Use either method to generate an account and its corresponding cryptographic key-pair.

Generating the account hash

As a developer, you will often use an account hash, which is a 32-byte hash of the public key. This is because responses from the node contain AccountHashes instead of the direct hexadecimal-encoded public key. To view the account hash for a public key, use the account-address option of the Casper CLI client:

casper-client account-address --public-key <path-to-public_key.pem/public-key-hex>

Funding an Account

After generating the cryptographic key-pair for an Account, you must fund the account's main purse to create it on-chain.

On Testnet, you can fund an account by requesting test tokens according to this guide. You can request test tokens only once for each account.

On Mainnet, a pre-existing account must transfer CSPR tokens to the newly created account's main purse to finalize the setup. The source account needs to transfer CSPR tokens to the hexadecimal-encoded public key of the target account. This transfer will automatically create the target account if it does not exist. Currently, this is the only way to create an account on Mainnet.

Acquiring a Node Address from the Network

Clients can interact with a node on the blockchain via requests sent to that node's JSON-RPC endpoint, http://<node-ip-address>:7777 by default.

The node address is the IP of a peer node.

Both the official Testnet and Mainnet provide block explorers that list the IP addresses of nodes on their respective networks.

You can get the node-ip-address of a node on the network by visiting the following block explorers:

You will see a list of peers, and you can select the IP of any peer on the list.

Note: If the selected peer is unresponsive, pick a different peer and try again.

Getting Started with AssemblyScript

Casper Labs maintains the casper-contract to allow developers to create smart contracts using AssemblyScript. The package source is hosted in the main Casper Network repository.

Prerequisites

Installing AssemblyScript

Installation of AssemblyScript requires Node.js.

After installation of Node.js, the following command will install AssemblyScript:

npm i assemblyscript

Full instructions and details for installing AssemblyScript can be found here.

Development Environment Setup

Installing the Casper Package

The casper-contract package can be installed using the following command:

npm i casper-contract

The Assemblyscript contract API documentation can be found at https://www.npmjs.com/package/casper-contract.

Creating a Project

For each smart contract, it is necessary to create a project directory and initialize it.

The npm init process prompts for various details about the project. Answer as you see fit, but you may safely default everything except name, which needs to be specified. In this guide, we will refer to the contract name as your-contract-name.

mkdir project
cd project
npm init

Then install AssemblyScript and this package in the project directory.

npm install --save-dev assemblyscript@0.9.1
npm install --save casper-contract

Script Entries

Add script entries for AssemblyScript to your project's package.json. Note that your contract name is used for the name of the Wasm file. Replace your-contract-name with the name of your contract.

{
"name": "your-contract-name",
...
"scripts": {
"asbuild:optimized": "asc assembly/index.ts -b dist/your-contract-name.wasm --validate --optimize --use abort=",
"asbuild": "npm run asbuild:optimized",
...
},
...
}

In the project root, create an index.js file with the following contents. Replace your-contract-name with the name of your contract.

const fs = require("fs");

const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/dist/your-contract-name.wasm"));

const imports = {
env: {
abort(_msg, _file, line, column) {
console.error("abort called at index.ts:" + line + ":" + column);
},
},
};

Object.defineProperty(module, "exports", {
get: () => new WebAssembly.Instance(compiled, imports).exports,
});

Next, create a directory called assembly, and in that directory, create a file called tsconfig.json in the following way:

{
"extends": "../node_modules/assemblyscript/std/assembly.json",
"include": ["./**/*.ts"]
}

Sample Smart Contract

In the assembly directory, also create an index.ts file, where the code for the contract needs to go.

You can use the following sample snippet, which demonstrates a simple smart contract that immediately returns an error and writes a message to a block when executed on a Casper network.

//@ts-nocheck
import { Error, ErrorCode } from "casper-contract/error";

// simplest possible feedback loop
export function call(): void {
Error.fromErrorCode(ErrorCode.None).revert(); // ErrorCode: 1
}

If you prefer a more complicated first contract, you can look at example contracts on the Casper Ecosystem GitHub repository for inspiration.

Compile to Wasm

To compile the contract to Wasm, use npm to run the asbuild script from the project root:

npm run asbuild

If the build is successful, there will be a dist folder in the root folder and in it should be your-contract-name.wasm.

Best Practices for Casper Smart Contract Authors

At its core, the Casper platform is software, and best practices for general software development will apply. However, there are specific variables and situations that should be considered when developing for a Casper network. For example, a smart contract installed on global state cannot access file systems or open a connection to external resources.

Data Efficiency

When developing on Casper, a policy of efficient data usage will ensure the lowest possible cost for on-chain computation. To this end, minimizing the number of necessary Deploys will drastically decrease the overall cost.

When creating smart contracts, including an explicit initialization entry point allows the contract to self-initialize without a subsequent Deploy of session code. This entry point creates the internal structure of the contract and cannot be called after the initial deploy. Below is an example of a self-initalizing entry point that can be used within the call function.

Example Self-initialization Entry Point

// This entry point initializes the donation system, setting up the fundraising purse
// and creating a dictionary to track the account hashes and the number of donations
// made.
#[no_mangle]
pub extern "C" fn init() {
let fundraising_purse = system::create_purse();
runtime::put_key(FUNDRAISING_PURSE, fundraising_purse.into());
// Create a dictionary to track the mapping of account hashes to number of donations made.
storage::new_dictionary(LEDGER).unwrap_or_revert();
}

Bear in mind, the host node will not enforce this. The smart contract author must create the entry point and ensure it cannot be called after initial deployment.

Costs

Computations occurring on-chain come with associated gas costs. Efficient coding can help to minimize gas costs, through the reduction of overall Wasm sent to global state. Beginning with 1.5.0, even invalid Wasm will incur gas costs when sent to global state. As such, proper testing prior to sending a Deploy is critical.

Further, there is a set cost of 2.5 CSPR to create a new purse. If possible, the reuse of purses should be considered to reduce this cost. If reusing purses, proper access management must be maintained to prevent lapses in security. Ultimately, any choices made in regards to security and contract safeguards rely on the smart contract author.

Tips to reduce WASM size

Deploys have a maxim size specified in each network chainspec as max_deploy_size. For example, networks running node version 1.5.1, have the following maximum deploy size in bytes:

max_deploy_size = 1_048_576

Here are a few tips to reduce the size of Wasm included in a deploy:

  1. Build the smart contract in release mode. You will find an example here

    cargo build --release --target wasm32-unknown-unknown
  2. Run wasm-strip on the compiled code (see WABT). You will find an example here

    wasm-strip target/wasm32-unknown-unknown/release/contract.wasm
  3. Don't enable the std feature when linking to the casper-contract or casper-types crates using the #![no_std] attribute, which tells the program not to import the standard libraries. You will find an example here and further details here

    #![no_std]
  4. Build the contract with codegen-units set to 1 by adding codegen-units = 1 to the Cargo.toml under [profile.release]). You will find an example here

  5. Build the contract with link-time optimizations enabled by adding lto = true to the Cargo.toml under [profile.release]. You will find an example here

Inlining

As often as practicable, developers should inline functions by including the body of the function within their code rather than making call or call_indirect to the function. In the context of coding for Casper blockchain purposes, this reduces the overhead of executed Wasm and prevents unexpected errors due to exceeding resource tolerances.

Testing

Testing all Deploys prior to committing them to Mainnet can assist authors in detecting bugs and inefficiencies prior to incurring gas fees. Casper provides several methods of testing, including unit testing, testing using NCTL and sending Deploys to Testnet.

Information on these processes can be found at the following locations:

Additionally, the following two tutorials outline sending an example contract using both NCTL and Testnet:

Calling Contracts

Calling a contract on a Casper network requires the use of a deploy. When using the Casper Rust client, JavaScript SDK, or any other client, the intermediary client crafts the deploy for you, using the arguments you provide. This document outlines the various deploy variants through which you can execute Wasm or invoke the execution of on-chain Wasm.

Using Deploy Variants

ModuleBytes

ModuleBytes is a deploy variant that allows you to pass opaque Wasm bytes to a network. This variant is used to install a contract on the chain or execute Wasm.

However, you can also use ModuleBytes to deploy session code that calls a contract.

Further information on the structure of ModuleBytes can be found in here.

StoredContractByHash

StoredContractByHash is a deploy variant that invokes on-chain Wasm by specifying the contract hash and an entry point within the contract. When you don't need to send additional Wasm, you can use this deploy variant to invoke on-chain Wasm. It accepts any runtime arguments necessary for the entry point in question.

While there is no Wasm associated with this variant, it is still a deploy sent to a node that invokes an installed contract.

Further information on the structure of StoredContractByHash can be found here.

StoredContractByName

StoredContractByName is similar to StoredContractByHash, with the main difference being the reference used to invoke on-chain Wasm. Where StoredContractByHash requires the contract hash, StoredContractByName uses a string stored as a NamedKey in the caller's account.

This allows the caller to more easily reference a contract stored on-chain for later use but requires pre-planning to store the name within their account's NamedKeys.

StoredVersionedContractByHash

StoredVersionedContractByHash is a deploy variant that invokes on-chain Wasm based on the contract package hash rather than the contract hash directly. This variant allows the caller to specify a version within the contract package, but if a specific version is not supplied, it will use the most recent version of the contract within the package.

This makes StoredVersionedContractByHash more stable than StoredContractByHash, as any caller will be directed to the most recent version of the internal contract without needing to specify the hash of that specific contract. Callers that regularly interact with a contract that they know will be upgraded can use this variant to ensure they are always using the most up-to-date version.

DApp developers that use contracts developed by other parties can use StoredVersionedContractByHash to avoid interruptions from contract version changes.

Further information on the structure of StoredVersionedContractByHash can be found here.

StoredVersionedContractByName

StoredVersionedContractByName combines the functionality of StoredContractByName and StoredVersionedContractByHash. It allows a developer to store a reference string as a NamedKey within their account context that references a contract by its contract package hash.

Further information on the structure of StoredVersionedContractByName can be found here.

Transfer

Native Transfers are Wasmless transfers on a Casper network. This is how most transfers take place, albeit through a system like the Rust client that crafts the associated deploy and sends it to the network.

Further information on the structure of a native Transfer can be found here.

Using the Contract Hash vs. the Package Hash

This page describes the possibilities of using the contract hash vs. the contract package hash (package hash for short) when calling a contract or managing calls from other contracts. Contracts can allow, block, or track calls from other contracts. As noted in Upgrading and Maintaining Smart Contracts, the contract package contains various contract versions. The contract hash is a BLAKE2b hash of a contract, and the contract package hash is the BLAKE2b hash of a contract package.

package-representation

Depending on what a contract needs to accomplish, it may save and manage the contract hash, package hash, or both. This behavior depends on what the contract needs to do, so a given contract might:

  • Want to identify specific versions of contracts within the same package and thus use a contract hash
  • Not need specific contract versions and allow or block all versions in the same package, thus using the contract package hash
  • Need specific contract versions within the same package, and thus use both contract hash and contract package hash
  • Not need either hash for this use case

A given contract, i.e., CEP-18, which wants to allow or block or track calls from other contracts, should then decide:

  • Will the contract allow, block, or track contract callers loosely at the package level?
  • Will the contract allow, block, or track contract callers specifically at the contract level?

Or a more fine-grained variation would be:

  • Will the contract allow or block callers at the package level but track by both package and contract hash?
  • Will the contract allow other combinations of these basic concepts?

Each contract is responsible for documenting its choices and what it requires of its callers. It is essential to keep in mind the difference between the behavior of the Casper execution engine (the host), as exposed by the Casper External FFI, versus use cases and interactions between two or more ecosystem entities such as accounts and contracts.

The execution engine doesn't know how a contract such as CEP-18 is trying to manage its internal data or its exposed functionality. The contract is responsible for creating and managing a sub-ledger of resource management, access control, etc.

The Casper Call Stack

When identifying who called a contract or initiated a call chain, the execution engine offers the FFI method casper_load_call_stack, which provides a stack of one or more entries of this kind:

/// Represents the origin of a sub-call.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum CallStackElement {
/// Session
Session {
/// The account hash of the caller
account_hash: AccountHash,
},
/// Effectively an EntryPointType::Session - stored access to a session.
StoredSession {
/// The account hash of the caller
account_hash: AccountHash,
/// The contract package hash
contract_package_hash: ContractPackageHash,
/// The contract hash
contract_hash: ContractHash,
},
/// contract
StoredContract {
/// The contract package hash
contract_package_hash: ContractPackageHash,
/// The contract hash
contract_hash: ContractHash,
},
}

You can find the source code here.

After retrieving the required information, the contract must manage its internal logic and data storage, actions entirely opaque to the execution engine.

Learn more about Call Stacks and how Casper manages the calling of a contract.

Recommendations

Consider the following questions when designing the contract and choosing whether to use the contract hash or package hash.

  1. Will you allow only accounts to use the contract? If so, what kind of accounts are you considering?

    AnswerRecommendation
    Specific accountsUse the account hash to identify and track each account.
    Exactly one specific accountUse the account hash of a specific account to identify it.
    Any accountsThere is no need to track the accounts by account hash.
  2. Will you allow only contracts to use it? If so, what kind of contracts?

    AnswerRecommendation
    Specific contract versionsUse the contract hash to identify each contract version.
    Specific contract versions of specific packagesUse the contract hash and the package hash to identify each contract version.
    Any contract versions of specific packagesUse only the package hash to identify each contract package.
    Any contract version of any contractThere is no need to track by contract or package hash.
  3. Will you allow both accounts and contracts to use it? If so, will these accounts and contracts be:

    AnswerRecommendation
    Specific accounts and contract versionsUse the account hash to track each account and the contract hash to identify each contract version.
    Specific accounts and specific versions of specific packagesUse the account hash to identify each account and the contract hash and package hash to identify each contract version.
    Specific accounts and any versions of specific packagesUse the account hash to identify each account and the package hash to identify each contract package.
    Any accounts and contractsThere is no need to track by account hash or contract hash.

What's Next?

Contracts and Session Code

What is Session Code?

Session code is the simplest logic one can execute on a Casper network. It is essential because it is often used to trigger contract logic stored on the chain. Session code requires only one entry point, the call function, and it runs within the context of the account executing the session code. As a result, the session code runs with the account's permissions, such as having access to the account's main purse. For example, the session code could transfer tokens from the account's main purse.

The best use of session code is when the situation calls for stateless execution, and very little or no internal data needs to be tracked. Session code is required when interacting and accepting values returned across the Wasm boundary.

Comparing Session and Contract Code

The following table summarizes the key differences between session code and contract code on a Casper network.

Session CodeContract Code
Session code always executes in the context of the account that signed the deploy containing the session code.A smart contract, which is stored on-chain logic, executes within its own context.
Session code has only one entry point, call, which can be used to interact with the session code.A smart contract can have multiple entry points that can be invoked.
The call entry point initiates any action the session code takes.Any action undertaken by a contract must initiate through an outside call, usually via session code.
When a put_key call is made within the body of the session code, the key is added to the account's named keys.When a put_key call is made within the smart contract's context, the contract's record is modified to have a new named_key entry.
For more information on how to write session code, see Writing Session Code.For more information on writing contracts, see Writing a Basic Smart Contract in Rust.

The following image depicts the comparison presented in the table.

Comparing Session and Contract Code

What's Next?

Getting Started with Rust Casper Contracts

This guide covers additional prerequisites for writing your first Casper smart contract. You will also build a sample smart contract and run a few basic tests on it on your local machine.

Casper's blockchain is built upon the Rust programming language and compiles to WebAssembly. This guide will walk you through the steps to write your first contract, assuming you have already set up your development environment as described here.

Creating a Project

You can create a new sample project very easily with the cargo casper crate. For example, let's say that I want to create a project named my-project for this tutorial (you can choose a different name if you wish), then I can simply run the command:

cargo casper my-project

If you look inside the newly-created my-project folder, you will find two crates: contract and tests. This is a complete basic smart contract that saves a value, passed as an argument, on the blockchain. The tests crate provides a runtime environment of the Casper virtual machine, and a basic smart contract test.

Using the nightly toolchain

Navigate to the my-project folder and open the rust-toolchain file. You will notice that the file's contents specify a nightly version of Rust. Here is an example:

nightly-2022-08-03

Having the latest nightly toolchain to develop smart contracts in Rust would be best. Please refer to the Rust Documentation on Channels and the Rust Documentation on Toolchains for further information.

As shown in this example, we recommend setting up the rust-toolchain file in your project's top-level directory.

You can also install the nightly Rust toolchain with this command:

rustup toolchain install nightly

Available Casper Rust crates

To support smart contract development with Rust, the following crates are published:

  • casper-contract - a library supporting communication with the blockchain. This is the main library you will need to write smart contracts.
  • casper-engine-test-support - a virtual machine against which you can test your smart contracts.
  • casper-types - a library with types we use across the Rust ecosystem.

A crate is a compilation unit that can be compiled into a binary or a library.

note

For a comprehensive list of crates, visit the Essential Casper Crates page.

Available API documentation

Each of the Casper crates comes with API documentation and examples for each function, located at https://docs.rs. The latest contract API documentation can be found here.

Compiling to Wasm

The Casper blockchain uses WebAssembly (Wasm) in its runtime environment. Compilation targets for Wasm are available for Rust, giving developers access to all the Rust ecosystem tools when developing smart contracts.

  • Note: Wasm allows for the use of other languages, including but not limited to: C/C++, C#, Go, Julia, Lobster and ZIG.

To compile the smart contract into Wasm, go into the my-project folder, and run the following commands:

cd my-project
make prepare
make build-contract

You can find the compiled contract on this path: my-project/contract/target/wasm32-unknown-unknown/release/contract.wasm.

Linting

Casper contracts support Rust tooling such as clippy for linting contracts. Feel free to use them! You can also use the make check-lint command for linting your contract. Run this command inside the my-project folder:

make check-lint

Testing the Contract

In addition to creating the contract, the Casper crate also automatically created sample tests in the my-project/tests folder.

The Casper local environment provides a virtual machine against which you can run your contract for testing. When you run the test crate, it will automatically build the smart contract in release mode and then run a series of tests against it in the Casper runtime environment. The custom build script is named build.rs if you are interested in looking more into it.

note

Since the test script automatically builds the contract, during development you only need to run the command make test without the need for make build-contract.

A successful test run indicates that your smart contract environment is set up correctly.

make test

After the compilation finishes, the test should run and you should see output similar to this message in your terminal:

running 2 tests
test tests::should_error_on_missing_runtime_arg ... ok
test tests::should_store_hello_world ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s

As a brief example, open up my-project/contract/src/main.rs in your editor, modify the KEY_NAME value in the contract, and then rerun the make test command. You should observe that the smart contract recompiles and the test fails now.

Video Walkthrough

The following video tutorial complements this guide.

Rust Resources

These Rust resources are excellent and we highly recommend them:

  1. https://doc.rust-lang.org/book/foreword.html
  2. https://rustwasm.github.io/docs/book/
  3. https://doc.rust-lang.org/stable/rust-by-example

Writing a Basic Smart Contract in Rust

What is a Smart Contract?

A smart contract is a self-contained program installed on a blockchain. In the context of a Casper network, a smart contract consists of contract code installed on-chain using a Deploy. Casper smart contracts are programs that run on a Casper network. They interact with accounts and other contracts through entry points, allowing for various triggers, conditions, and logic.

Smart contracts exist as stored on-chain logic, allowing disparate users to call the included entry points. These contracts can, in turn, call one another to perform interconnected operations and create more complex programs. The decentralized nature of blockchain technology means that these smart contracts do not suffer from any single point of failure. Even if a Casper node leaves the network, other nodes will continue to allow the contract to operate as intended.

Key Features of Casper Contracts

On the Casper platform, developers may write smart contracts in any language that compiles to Wasm binaries. This tutorial focuses specifically on writing a smart contract in the Rust language. The Rust compiler compiles the contract code into Wasm. After that, the Wasm binary can be sent to a node on a Casper network using a Deploy. Nodes within the network then gossip deploys, include them within a block, and finalize them. After finalizing, the network executes the deploys within the block.

Further, the Casper platform allows for upgradable contracts. A ContractPackage is created through the new_contract or new_locked_contract methods. Through these methods, the Casper execution engine automatically creates the new contract package and assigns a ContractPackageHash. The new contract is added to this package with a ContractHash key. The execution engine stores the new contract within the contract package alongside any previously installed contract versions, if applicable.

The new_contract and new_locked_contract methods are a convenience that automatically creates the package associated with a new contract. Developers choosing not to use these methods must first create a contract package to function as a container for their new contract.

The contract contains required metadata, and it is primarily identified by its ContractHash. While the contract hash identifies a specific ContractVersion, the ContractPackageHash serves as an identifier for the most recent contract version in the contract package.

Creating the Directory Structure

To begin creating a smart contract, you need to set up the project structure, either manually or automatically, as shown below.

project-directory/

└── contract/
├── src/
└── main.rs
└── Cargo.toml

└── Makefile
└── rust-toolchain

└── tests/
├── src/
└── integration-tests.rs
└── Cargo.toml

The project structure would be different in a dApp with full-stack architecture.

Automatically using cargo casper

The cargo casper command can automatically set up the project structure. This is the recommended way of setting up a new Casper project.

cargo casper my-project

The cargo casper command will generate an example contract in the contract directory and an example tests crate with logic defined in the integration-tests.rs file. The Makefile includes commands to prepare and build the contract, and the rust-toolchain file specifies the target build version of Rust.

Semi-automatically using plain cargo

tip

If you are a beginner, creating the structure automatically with cargo casper is recommended and the command creates everything you need to start coding.

  1. Create a top-level project directory for the contract code and its corresponding tests.

  2. Inside the project directory, run the following command to create a new binary package called contract. Use a different name instead of contract if you wish.

    cargo new contract

    The command creates a contract folder with a /src/main.rs file and a Cargo.toml file:

    • main.rs - This file would contain the contract code.
    • Cargo.toml - This file would contain crate dependencies and other configurations.

    The following sections explain how to update these files using example code.

  3. Inside the project directory, run the command to auto-generate the folder structure for the tests. Use a different name instead of tests if you wish.

    cargo new tests

    The command creates a tests folder with a /src/main.rs file and a Cargo.toml file:

    • main.rs - This file would store the unit test code required to test the contract. You can rename the file to integration-tests.rs as shown in the example structure.
    • Cargo.toml - This is the file with test configurations.

    The Testing Smart Contracts guide explains how to update the tests using example code.

  4. Unlike cargo casper, cargo does not create a Makefile and rust-toolchain configuration file. Therefore, you must manually add these files to the project's root folder.

Example Makefile
prepare:
rustup target add wasm32-unknown-unknown

build-contract:
cd contract && cargo build --release --target wasm32-unknown-unknown
wasm-strip contract/target/wasm32-unknown-unknown/release/contract.wasm 2>/dev/null | true

test: build-contract
mkdir -p tests/wasm
cp contract/target/wasm32-unknown-unknown/release/contract.wasm tests/wasm
cd tests && cargo test

clippy:
cd contract && cargo clippy --all-targets -- -D warnings
cd tests && cargo clippy --all-targets -- -D warnings

check-lint: clippy
cd contract && cargo fmt -- --check
cd tests && cargo fmt -- --check

lint: clippy
cd contract && cargo fmt
cd tests && cargo fmt
Example rust-toolchain file
nightly-2022-08-03

Manually

tip

If you are a beginner, creating the structure automatically with cargo casper is recommended, and the command creates everything you need to start coding.

  1. Create a top-level project directory to store the contract code and corresponding tests.

  2. Create a folder for the contract code inside the project directory. This folder contains the logic that will be compiled into Wasm and executed on a Casper node. In this example, we named the folder contract. You can use a different folder name if you wish.

    • In the contract folder, add a source folder called src and a Cargo.toml file, which specifies the contract's dependencies.
    • Add a Rust file with the contract code in the src folder. In this example, we have the main.rs file.
  3. Navigating back to the project directory, create a folder for the tests, which help verify the contract's functionality. In this example, we named the folder tests.

    • In the tests folder, add a source folder called src and a Cargo.toml file, which specifies the required dependencies to run the tests.
    • In the src folder, add a Rust file with the tests that verify the contract's behavior. In this example, we have the integration-tests.rs file.
  4. Manually create Makefile and rust-toolchain as per Semi-automatic setup (4.)

Dependencies

The Cargo.toml file in the contract folder includes the dependencies and versions the contract requires. At a minimum, you need to import the latest versions of the casper-contract and casper-types crates. The following dependencies and version numbers are only examples and must be adjusted based on your requirements.

If you followed the automatic setup, the dependencies should be in the Cargo.toml file. For the semi-automatic setup and manual setup, however, you'll need to manually add the dependencies to the crate's Cargo.toml file:

[dependencies]
# A library for developing Casper network smart contracts.
casper-contract = "1.4.4"
# Types shared by many Casper crates for use on a Casper network.
casper-types = "1.5.0"
  • casper-contract = "1.4.4" - Provides the SDK for the execution engine (EE). The latest version of the crate is published here.
  • casper-types = "1.5.0" - Includes types shared by many Casper crates for use on a Casper network. This crate is necessary for the EE to understand and interpret the session code. The latest version of the crate is published here.

Writing a Basic Smart Contract

At this point, you either have the default example contract defined in contract/src/main.rs (automatic setup using cargo-casper), an empty contract/src/main.rs file (manual project setup), or a Rust "hello world" program defined in the contract/src/main.rs (semi-automatic setup).

This section covers the process of writing a smart contract in Rust, step by step. Therefore, you should clear the contents of the contract/main.rs file if there are any.

The example code comes from the counter contract. This simple contract allows callers to increment and retrieve an integer. Casper provides a contract API within the casper_contract crate.

info

Important syntax elements used frequently in Rust:

To be able to comfortably write code in Rust it is crucial to understand these topics before going further into the examples.

Updating the main.rs File

To begin writing contract code, add the following file attributes to support the Wasm execution environment. If you still have an auto-generated main.rs file, remove the auto-generated main function.

#![no_std]
#![no_main]
  • #![no_main] - This attribute tells the program not to use the standard main function as its entry point.
  • #![no_std] - This attribute tells the program not to import the standard libraries.

Defining required dependencies

Add the required imports and dependencies. The example code for the counter contract declares the following dependencies.

// This code imports necessary aspects of external crates that we will use in our contract code.
extern crate alloc;

// Importing Rust types.
use alloc::{
string::{String, ToString},
vec::Vec,
};
// Importing aspects of the Casper platform.
use casper_contract::{
contract_api::{runtime, storage},
unwrap_or_revert::UnwrapOrRevert,
};
// Importing specific Casper types.
use casper_types::{
api_error::ApiError,
contracts::{EntryPoint, EntryPointAccess, EntryPointType, EntryPoints, NamedKeys},
CLType, CLValue, URef,
};

Defining the global constants

After importing the necessary dependencies, you should define the constants used within the contract, including entry points and values. The following example outlines the necessary constants for the counter contract.

// Creating constants for values within the contract package.
const CONTRACT_PACKAGE_NAME: &str = "counter_package_name";
const CONTRACT_ACCESS_UREF: &str = "counter_access_uref";

// Creating constants for the various contract entry points.
const ENTRY_POINT_COUNTER_INC: &str = "counter_inc";
const ENTRY_POINT_COUNTER_GET: &str = "counter_get";

// Creating constants for values within the contract.
const CONTRACT_VERSION_KEY: &str = "version";
const CONTRACT_KEY: &str = "counter";
const COUNT_KEY: &str = "count";

Defining the contract entry points

Entry points provide access to contract code installed in global state. Either session code or another smart contract may call these entry points. A contract must have at least one entry point and may have more than one entry point. Entry points are defined by their name, and those names should be clear and self-describing. Each entry point is equivalent to a static main entry point in a traditional program.

Entry points are not functions or methods, and they have no arguments. They are static entry points into the contract's logic. Yet, the contract logic can access parameters by name, passed along with the Deploy. Note that another smart contract may access any of these entry points.

If an entry point has one or more mandatory parameters that will cause the logic to revert if they are not included, declare them within that entry point. Optional and non-critical parameters should be excluded.

When defining entry points, begin with a #[no_mangle] line to ensure the system does not change critical syntax within the method names. Each entry point should contain the contract code that drives the action you wish it to accomplish. Finally, include any storage or return values needed, as applicable.

The following entry point is an example from the counter contract. To see all the available entry points, review the contract in GitHub.

#[no_mangle]
pub extern "C" fn counter_inc() {
let uref: URef = runtime::get_key(COUNT_KEY)
.unwrap_or_revert_with(ApiError::MissingKey)
.into_uref()
.unwrap_or_revert_with(ApiError::UnexpectedKeyVariant);
storage::add(uref, 1); // Increment the count by 1.
}

Defining the call function

The call function starts the code execution and installs the contract on-chain. In some cases, it also initializes some constructs, such as a Dictionary for record-keeping or a purse. The following steps describe how to structure the call function. Review the call function in the counter contract.

  1. Define the runtime arguments.

At the time of contract installation, pass in parameters as runtime arguments. Use this pattern of variable definition to collect any sentinel values that dictate the behavior of the contract. If the entry point takes in arguments, you must declare those as part of the entry point's definition.

Look at the CEP-78 contract to see examples of entry points taking in arguments. The counter contract does not use variable parameters since it is too simple.

  1. Add the entry points into the call function.

The call function replaces a traditional main function and executes automatically when a caller interacts with the contract. Within the call function, we define entry points the caller can access using session code or another contract. When writing code that calls an entry point, there must be a one-to-one mapping of the entry point name. Otherwise, the execution engine will return an error that the entry point does not exist.

Each entry point should have these arguments:

  • name - The entry point's name, which should be the same as the initial definition.
  • arguments - A list of runtime arguments declared as part of the definition of the entry point.
  • return type - The CLType returned by the entry point. Use the type Unit for empty return types.
  • access level - Access permissions of the entry point.
  • entry point type - This can be contract or session code.

This step adds the individual entry points to a counter_entry_points object using the add_entry_point method. This object will later be passed to the new_contract method.

#[no_mangle]
pub extern "C" fn call() {
// Initialize the count to 0 locally
let count_start = storage::new_uref(0_i32);
// Create the entry points for this contract
let mut counter_entry_points = EntryPoints::new();

counter_entry_points.add_entry_point(EntryPoint::new(
ENTRY_POINT_COUNTER_GET,
Vec::new(),
CLType::I32,
EntryPointAccess::Public,
EntryPointType::Contract,
));

counter_entry_points.add_entry_point(EntryPoint::new(
ENTRY_POINT_COUNTER_INC,
Vec::new(),
CLType::Unit,
EntryPointAccess::Public,
EntryPointType::Contract,
));
}

In the following, we will add more content to this call function.

  1. Create the contract's named keys.

NamedKeys are a collection of String-Key pairs used to identify some network data quickly.

  • The String is the name given to identify the data
  • The Key is the data to be referenced

You can create named keys to store any record or value as needed, such as other accounts, smart contracts, URefs, transfers, deploy information, purse balances, etc. The list of possible Key variants can be found here.

For the counter, we store the integer that we increment into a named key.

    // In the named keys of the counter contract, add a key for the count.
let mut counter_named_keys = NamedKeys::new();
let key_name = String::from(COUNT_KEY);
counter_named_keys.insert(key_name, count_start.into());
  1. Create the contract.

Use the new_contract method to create the contract with its named keys and entry points. This method creates the contract object and saves the access URef and the contract package hash in the caller's context. The execution engine automatically creates a contract package and assigns it a contractPackageHash. Then, it adds the contract to the package with a contractHash.

    // Create a new contract package that can be upgraded.
let (stored_contract_hash, contract_version) = storage::new_contract(
counter_entry_points,
Some(counter_named_keys),
Some(CONTRACT_PACKAGE_NAME.to_string()),
Some(CONTRACT_ACCESS_UREF.to_string()),
);

Usually, these contracts are upgradeable with the ability to add new versions. You must have the access URef to the contract package to add a new contract version. This can be accomplished by passing the Some(CONTRACT_ACCESS_UREF.to_string()) argument to the new_contract method. To prevent any upgrades to a contract, use the new_locked_contract method described below.

  1. Create additional named keys.

Generally, the Contract_Hash and Contract_Version are saved as NamedKeys in the account's context for later use.

    // Store the contract version in the context's named keys.
let version_uref = storage::new_uref(contract_version);
runtime::put_key(CONTRACT_VERSION_KEY, version_uref.into());

// Create a named key for the contract hash.
runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());

The complete call function should look like this:

#[no_mangle]
pub extern "C" fn call() {
// Initialize the count to 0 locally
let count_start = storage::new_uref(0_i32);
// Create the entry points for this contract
let mut counter_entry_points = EntryPoints::new();

counter_entry_points.add_entry_point(EntryPoint::new(
ENTRY_POINT_COUNTER_GET,
Vec::new(),
CLType::I32,
EntryPointAccess::Public,
EntryPointType::Contract,
));

counter_entry_points.add_entry_point(EntryPoint::new(
ENTRY_POINT_COUNTER_INC,
Vec::new(),
CLType::Unit,
EntryPointAccess::Public,
EntryPointType::Contract,
));

// In the named keys of the counter contract, add a key for the count.
let mut counter_named_keys = NamedKeys::new();
let key_name = String::from(COUNT_KEY);
counter_named_keys.insert(key_name, count_start.into());

// Create a new contract package that can be upgraded.
let (stored_contract_hash, contract_version) = storage::new_contract(
counter_entry_points,
Some(counter_named_keys),
Some(CONTRACT_PACKAGE_NAME.to_string()),
Some(CONTRACT_ACCESS_UREF.to_string()),
);

/* To create a locked contract instead, use new_locked_contract and throw away the contract version returned
let (stored_contract_hash, _) =
storage::new_locked_contract(counter_entry_points, Some(counter_named_keys), None, None); */

// Store the contract version in the context's named keys.
let version_uref = storage::new_uref(contract_version);
runtime::put_key(CONTRACT_VERSION_KEY, version_uref.into());

// Create a named key for the contract hash.
runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());
}

Locked Contracts

Locked contracts cannot contain other contract versions in the same contract package; thus, they cannot be upgraded. In this scenario, the Casper execution engine will create a contract package, add a contract to that package and prevent any further upgrades to the contract. Use locked contracts when you need to ensure high security and will not require updates to the contract.

pub fn new_locked_contract(
entry_points: EntryPoints,
named_keys: Option<NamedKeys>,
hash_name: Option<String>,
uref_name: Option<String>,
) -> (ContractHash, ContractVersion) {
create_contract(entry_points, named_keys, hash_name, uref_name, true)
}
  • entry_points - The set of entry points defined inside the smart contract.
  • named_keys - Any named-key pairs for the contract.
  • hash_name - Contract hash value. Puts contractHash in the current context's named keys under hash_name.
  • uref_name - Access URef value. Puts access_uref in the current context's named keys under uref_name.

Note: The current context is the context of the person who initiated the call function, usually an account.

The counter contract in our example would be locked if we created it this way:

let (stored_contract_hash, _) =
storage::new_locked_contract(counter_entry_points, Some(counter_named_keys), None, None);

Compiling Contract Code

To compile the smart contract, run the following commands in the contract folder in your project's directory, where the Cargo.toml file and src folder are hosted.

rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown

For the counter example, in the project directory where the Makefile is, run the following commands:

make prepare
make build-contract

Executing Contract Code

Contract execution must be initiated through an outside call, usually via session code or another smart contract. Developers should also be familiar with the difference between contract code and session code, explained in the next section.

Video Walkthrough

The following brief video accompanies this guide.

What's Next?

Testing Smart Contracts

Introduction

As part of the Casper development environment, we provide a testing framework to test new contracts without running a full node. The framework creates an instance of the Casper execution engine, which can confirm successful deploys and monitor changes to global state using assertions. The Casper test crate must be included within the Rust workspace alongside the Wasm-producing crate to be validated.

note

The Casper test support crate is one of many options for testing contracts before sending them to a Casper network. If you prefer, you can create your own testing framework.

Defining Dependencies in Cargo.toml

This guide uses the project structure, and example contract outlined here for creating tests.

To begin, outline the required test dependencies in the /tests/Cargo.toml file. Specify the dependencies for your tests similarly and update the crate versions. Dependencies may vary with each project. For the counter tests, we have the following dependencies:

[dependencies]
casper-execution-engine = "2.0.1"
casper-engine-test-support = { version = "2.2.0", features = ["test-support"] }
casper-types = "1.5.0"
  • casper-execution-engine - This crate imports the execution engine functionality, enabling Wasm execution within the test framework. Each node contains an instance of an execution engine, and the testing framework simulates this behavior.
  • casper-engine-test-support - A helper crate that provides the interface to write tests and interact with an instance of the execution engine.
  • casper-types - Types shared by many Casper crates for use on a Casper network.

Writing the Tests

The tests for the contract usually reside in the tests directory. Tests for the counter contract reside in the tests/src/integration-tests.rs file. Notice that this file contains an empty main method to initialize the test program. Alternatively, we could use the #![no_main] annotation at the top of the file, as we did here.

fn main() {
panic!("Execute \"cargo test\" to test the contract, not \"cargo run\".");
}

The #[cfg(test)] attribute tells the Rust compiler to compile and run the tests only when invoking cargo test, not while debugging or releasing. All testing functions reside within the grouping mechanism mod tests.

#[cfg(test)]
mod tests {
// The entire test program resides here
}

Importing Builders and Constants

Import external test support, which includes a variety of default values and helper methods to be used throughout the test. Additionally, you will need to import any CLTypes used within the contract code to be tested.

    // Outlining aspects of the Casper test support crate to include.
use casper_engine_test_support::{
ExecuteRequestBuilder, InMemoryWasmTestBuilder, DEFAULT_ACCOUNT_ADDR,
DEFAULT_RUN_GENESIS_REQUEST,
};
// Custom Casper types that will be used within this test.
use casper_types::{runtime_args, ContractHash, RuntimeArgs};

Next, you need to define any global variables or constants for the test.

    const COUNTER_V1_WASM: &str = "counter-v1.wasm"; // The first version of the contract
const COUNTER_V2_WASM: &str = "counter-v2.wasm"; // The second version of the contract
const COUNTER_CALL_WASM: &str = "counter-call.wasm"; // Session code that calls the contract

const CONTRACT_KEY: &str = "counter"; // Named key referencing this contract
const COUNT_KEY: &str = "count"; // Named key referencing the value to increment/decrement
const CONTRACT_VERSION_KEY: &str = "version"; // Key maintaining the version of a contract package

const ENTRY_POINT_COUNTER_DECREMENT: &str = "counter_decrement"; // Entry point to decrement the count value
const ENTRY_POINT_COUNTER_INC: &str = "counter_inc"; // Entry point to increment the count value

Creating a Test Function

Each test function installs the contract and calls entry points to assert that the contract's behavior matches expectations. The test uses the InMemoryWasmTestBuilder to invoke an instance of the execution engine, effectively simulating the process of installing the contract on the chain.

As part of this process, we use the DEFAULT_RUN_GENESIS_REQUEST to install the system contracts necessary for the tests, including the Mint, Auction, and HandlePaymentcontracts, as well as establishing a default account and funding the associated purse.

    #[test]
/// Install version 1 of the counter contract and check its available entry points. ...
fn install_version1_and_check_entry_points() {
let mut builder = InMemoryWasmTestBuilder::default();
builder.run_genesis(&*DEFAULT_RUN_GENESIS_REQUEST).commit();

// See the repository for the full function.
}

Installing the Contract

Test functions use the ExecuteRequestBuilder to install a contract to be tested. In the counter tests, we use standard dependencies and the counter contract. Within the execution request, we specify the DEFAULT_ACCOUNT_ADDR established by our genesis builder as the account sending the Deploy.

After building the ExecuteRequestBuilder (in this example, contract_installation_request), we process the request through builder.exec and then add and process other requests as necessary.

    // Install the contract.
let contract_v1_installation_request = ExecuteRequestBuilder::standard(
*DEFAULT_ACCOUNT_ADDR,
COUNTER_V1_WASM,
runtime_args! {},
)
.build();

builder
.exec(contract_v1_installation_request)
.expect_success()
.commit();

Calling the Contract by Hash

To verify the installed contract, we need its contract hash. The test will then call its entry points using the contract_call_by_hash function. The following code retrieves the contract hash from the named keys of the DEFAULT_ACCOUNT_ADDR that sent the installation Deploy.

    // Check the contract hash.
let contract_v1_hash = builder
.get_expected_account(*DEFAULT_ACCOUNT_ADDR)
.named_keys()
.get(CONTRACT_KEY)
.expect("must have contract hash key as part of contract creation")
.into_hash()
.map(ContractHash::new)
.expect("must get contract hash");

Next, we test an entry point that should not exist in the first version of the contract.

    // Call the decrement entry point, which should not be in version 1 before the upgrade.
let contract_decrement_request = ExecuteRequestBuilder::contract_call_by_hash(
*DEFAULT_ACCOUNT_ADDR,
contract_v1_hash,
ENTRY_POINT_COUNTER_DECREMENT,
runtime_args! {},
)
.build();

// Try executing the decrement entry point and expect an error.
builder
.exec(contract_decrement_request)
.expect_failure()
.commit();

Calling the Contract using Session Code

In the counter example, we use the session code included in the counter-call.wasm file. For more details on what session code is and how it differs from contract code, see the next section.

The following session code uses the contract hash to identify the contract, the account for sending the deploy (DEFAULT_ACCOUNT_ADDR), the deploy to be sent (COUNTER_CALL_WASM), and the runtime arguments required. Once again, the ExecuteRequestBuilder simulates the execution of session code and calls the counter-inc entry point.

    // Use session code to increment the counter.
let session_code_request = ExecuteRequestBuilder::standard(
*DEFAULT_ACCOUNT_ADDR,
COUNTER_CALL_WASM,
runtime_args! {
CONTRACT_KEY => contract_v1_hash
},
)
.build();

builder.exec(session_code_request)
.expect_success()
.commit();

Evaluating and Comparing Results

After calling the contract, we should verify the results received to ensure the contract operated as intended. The builder method retrieves the required information and converts it to the value type required. Then, assert_eq!() compares the result against the expected value.

    // Verify the value of count is now 1.
let incremented_count = builder
.query(None, count_key, &[])
.expect("should be stored value.")
.as_cl_value()
.expect("should be cl value.")
.clone()
.into_t::<i32>()
.expect("should be i32.");

assert_eq!(incremented_count, 1);

For more test examples, visit the casper-node GitHub repository.

Testing Contracts that Call Contracts

If the code to be tested involves multiple contracts, they must be installed within the test. The exceptions are system contracts installed as part of the DEFAULT_RUN_GENESIS_REQUEST. The testing framework exists independently of any Casper network, so you will need access to the original contract installation code or the Wasm you wish to include.

Each contract installation will require an additional Wasm file installed through a Deploy using ExecuteRequestBuilder. Depending on your requirements as a smart contract author, you may need to use return values to interact with stacks of contracts. Interaction between contracts will require session code to initiate the process, as contracts will not execute actions autonomously.

The major difference between calling a contract from session code versus contract code is the ability to use non-standard dependencies for the ExecuteRequestBuilder. Where session code must designate a Wasm file within the standard dependencies, contract code can use one of the four available options for calling other contracts, namely:

  • contract_call_by_hash - Calling a contract by its ContractHash.
  • contract_call_by_name - Calling a contract referenced by a named key in the signer's Account context.
  • versioned_contract_call_by_hash - Calling a specific contract version using its ContractHash.
  • versioned_contract_call_by_name - Calling a specific version of a contract referenced by a named key in the signer's Account context.

The calling contract must also provide an entry point and any necessary runtime arguments in all cases.

Running the Tests

To run the tests, the counter example uses a Makefile.

make test

Under the hood, the Makefile generates a tests/wasm folder, copies the Wasm files to the folder, and runs the tests using cargo test.

test: build-contract
mkdir -p tests/wasm
cp contract-v1/target/wasm32-unknown-unknown/release/counter-v1.wasm tests/wasm
cp contract-v2/target/wasm32-unknown-unknown/release/counter-v2.wasm tests/wasm
cp counter-call/target/wasm32-unknown-unknown/release/counter-call.wasm tests/wasm
cd tests && cargo test

Video Walkthrough

The following brief video describes testing sample contract code.

Further Testing

Unit testing is only one way to test contracts before installing them on a Casper network. After unit testing a contract, you may perform local network testing using NCTL. This allows you to set up and control multiple local Casper nodes to perform testing in an other simulated network environment.

You may also wish to test your contracts on the Casper Testnet.

What's Next?

Testing Session Code

This section describes how to test session code using the Casper unit-testing framework. The writing session code section is a prerequisite for this tutorial, which uses the example code described here.

Specifying Dependencies in Cargo.toml

The Cargo.toml sample file in the tests directory contains the test framework dependencies. Specify the dependencies for your tests similarly and update the crate versions. Dependencies may vary with each project. These are the basic dependencies the testing framework requires:

[dev-dependencies]
casper-engine-test-support = { version = "2.2.0", features = ["test-support"] }
casper-execution-engine = "2.0.0"
casper-types = "1.5.0"
  • casper-execution-engine - This crate imports the execution engine functionality, enabling Wasm execution within the test framework. Each node contains an instance of an execution engine, and the testing framework simulates this behavior.
  • casper-engine-test-support - A helper crate that provides the interface to write tests and interact with an instance of the execution engine.
  • casper-types - Types shared by many Casper crates for use on a Casper network.

Writing the Tests

Tests for this example session code reside in the tests/src/integration-tests.rs file.

Notice that this file contains an empty main method to initialize the test program. Alternatively, we could use the #![no_main] annotation at the top of the file, as we did here.

fn main() {
panic!("Execute \"cargo test\" to test the contract, not \"cargo run\".");
}

The #[cfg(test)] attribute tells the Rust compiler to compile and run the tests only when invoking cargo test, not while debugging or releasing. All testing functions reside within the grouping mechanism mod tests.

#[cfg(test)]
mod tests {
// The entire test program resides here
}

Importing Required Packages

Next, import the packages required for the tests to run. The example tests use these packages:

    use casper_engine_test_support::{
ExecuteRequestBuilder, InMemoryWasmTestBuilder, DEFAULT_ACCOUNT_ADDR,
DEFAULT_RUN_GENESIS_REQUEST,
};
use casper_types::account::AccountHash;
use casper_types::{runtime_args, RuntimeArgs};

Defining The Constants

The names of the runtime arguments are defined as constants. Using the exact names as in the original contract class is mandatory to define these constants. These are dictated by the arguments specified by the session code. If your session code takes in different arguments, you should define them as constants at this point.

const ASSOCIATED_ACCOUNT_HASH: AccountHash = AccountHash::new([1u8; 32]); // hash of the associated account
const ASSOCIATED_ACCOUNT: &str = "deployment-account"; // the associated account argument
const CONTRACT_WASM: &str = "contract.wasm"; // file to pass to the instance of the EE

Creating a Test Function

In this step, we create a program to test the session code. The bodies of test functions typically perform some setup, run the code, then verify the results using assertions. Each test function is annotated with the #[test] attribute.

#[test]
fn <unit-test-name>{
// Test function implementation
}

This unit test is a good example of testing session code. At a high level, the test follows this process:

  1. Initialize an instance of the execution engine and the InMemoryWasmTestBuilder.
    let mut builder = InMemoryWasmTestBuilder::default();
  1. Execute the genesis process.
    builder.run_genesis(&*DEFAULT_RUN_GENESIS_REQUEST).commit();
  1. Execute the test-specific logic. In this example, retrieve information about the account running the session code and its associated keys. For full details, visit GitHub.

  2. Retrieve runtime arguments, which should be the same as defined in the contract.

  3. Create the execution request that sets up the session code to be processed. In this example, the CONTRACT_WASM is the session code.

    let execute_request =
ExecuteRequestBuilder::standard(*DEFAULT_ACCOUNT_ADDR, CONTRACT_WASM, runtime_args)
.build();
  1. Invoke the execution engine to process the session code.
    builder.exec(execute_request).expect_success().commit();
  1. Verify that the results match the expected output. This example checks the associated keys.
    assert!(associated_keys.contains_key(&ASSOCIATED_ACCOUNT_HASH));

Running the Test

This example uses a Makefile to run the tests.

make test

Under the hood, the Makefile generates a tests/wasm folder, copies the Wasm to the folder, and runs the tests with cargo test.

mkdir -p tests/wasm
cp contract/target/wasm32-unknown-unknown/release/contract.wasm tests/wasm
cd tests && cargo test

Other Examples

In the counter unit tests, we use session code to call the contract. The code loads the account that pays for the session code, the session code Wasm, and the runtime arguments. Then, the code invokes the execution engine to process the session code.

    // Use session code to increment the counter.
let session_code_request = ExecuteRequestBuilder::standard(
*DEFAULT_ACCOUNT_ADDR,
COUNTER_CALL_WASM,
runtime_args! {
CONTRACT_KEY => contract_v1_hash
},
)
.build();

builder.exec(session_code_request)
.expect_success()
.commit();

The verification step looks like this:


let incremented_count = builder
.query(None, count_key, &[])
.expect("should be stored value.")
.as_cl_value()
.expect("should be cl value.")
.clone()
.into_t::<i32>()
.expect("should be i32.");

assert_eq!(incremented_count, 1);

For many more examples, visit the casper-node GitHub repository.

Video Walkthrough

The following brief video describes testing the sample session code for configuring an account.

What's Next?

Upgrading and Maintaining Smart Contracts

Our smart contract packaging tools enable you to:

  • Upgrade your contracts and specify how the state of the contract is managed
  • Specify whether a contract is upgradable or immutable
  • Version your contracts and deprecate old versions
  • Set permissions around who can perform contract upgrades

The Contract Package

When you upgrade a contract, you add a new contract version in a contract package. The versioning process is additive rather than an in-place replacement of an existing contract. The original version of the contract is still there, and you can enable certain versions for specific clients. You can also disable a contract version if needed. If you find that you need to use a disabled contract version, you may also re-enable it.

package-representation

The contract package is like a container for different contract versions, with functionality that can differ slightly or significantly among versions. The contract package is created when you install the contract on the blockchain.

Videos and Tutorials

To learn more about versioning contracts, consult the following video, which builds upon the previous topics and videos in the Writing On-Chain Code documentation.

Or, for a different perspective, consult the Smart Contract Upgrade Tutorial.

Maintaining a Contract

The contract maintenance process is generally covered through the contract upgrade process.

Only major version changes in the Casper node software would require specific contract maintenance since a node version has a one-to-one mapping with the contract version. Otherwise, minor contract version changes can be addressed through the contract upgrade process. At the moment, we are not anticipating major contract changes in the Casper Mainnet. Therefore, the contract upgrade process can cater to any minor contract maintenance.

On instances like new node version releases, type upgrades, and bug fixes, we advise you to adhere to the same contract upgrade process.

Writing Session Code

This section explains how to write session code. To review the definition of session code and the differences between session code and contract code, see Comparing Session Code and Contract Code. Session code can be written in any programming language that compiles to Wasm. However, the examples in this topic use Rust.

Creating the Directory Structure

For writing session code, we use the same project structure used for writing contracts, described here.

Example 1: Writing Session Code

The following steps illustrate the process of writing session code using an example repository containing sample session code for configuring an account: https://github.com/casper-ecosystem/two-party-multi-sig/. The sample code adds an associated key to the account and updates the action thresholds. Remember that an Account on a Casper network can add associated accounts and set up a multi-signature scheme for deploys. To follow along, clone the repository.

git clone https://github.com/casper-ecosystem/two-party-multi-sig/
note

Before executing session code, ensure that you know exactly what the session code is doing. If you don't know what it is meant for, it could be doing something malicious.

Dependencies in Cargo.toml

The Cargo.toml file includes the dependencies and versions the session code requires. At a minimum, you need to import the latest versions of the casper-contract and casper-types crates. The following dependencies and version numbers are only examples and must be adjusted based on your requirements.

  • casper-contract = "1.4.4" - Provides the SDK for the execution engine (EE). The latest version of the crate is published here.
  • casper-types = "1.5.0" - Includes types shared by many Casper crates for use on a Casper network. This crate is necessary for the EE to understand and interpret the session code. The latest version of the crate is published here.

Updating the main.rs File

Open the contract/src/main.rs file that contains the sample session code. Notice these directives at the top of the file:

  • #![no_std] - Specifies not to import the standard library.
  • #![no_main] - Indicates the main function is not required since the session code has only one entry point as the call function.

Next, review the imported crates and other required libraries.

#![no_std]
#![no_main]

use casper_contract::contract_api::{account, runtime};
use casper_contract::unwrap_or_revert::UnwrapOrRevert;
use casper_types::account::{AccountHash, ActionType, Weight};

After the imported libraries, we usually find the constants.

const ASSOCIATED_ACCOUNT: &str = "deployment-account";

Next, we see the call function, the only entry point in this example session code. The #[no_mangle] flag ensures that the function name is retained as a string in the Wasm binary. For session code, this flag retains the call string and marks the entry point for the execution engine. Explore the call function details by opening the cloned project.

#[no_mangle]
pub extern "C" fn call() {
// Open the repository for details
}

When compiled, the call function could be used from another library. For example, a C library could link to the resulting Wasm.

Example 2: Calling a Contract with Session Code

Another example of session code is the counter-call/src/main.rs file, in the counter repository. This example shows how we commonly use session code to invoke logic stored within a smart contract. To follow along, clone the repository.

git clone https://github.com/casper-ecosystem/counter/

Observe how the project is set up and review the dependencies in the counter/counter-call/Cargo.toml file. Then, open the counter/counter-call/src/main.rs file containing the session code. Notice the directives at the top of the file, the required dependencies, and the declared constants.

The call function interacts with the contract's counter_inc and counter_get entry points. This is how the session's call entry point triggers the logic stored inside the counter contract.

    // Call the counter to get the current value.
let current_counter_value: u32 =
runtime::call_contract(contract_hash, COUNTER_GET, RuntimeArgs::new());

// Call the counter to increment the value.
let _: () = runtime::call_contract(contract_hash, COUNTER_INC, RuntimeArgs::new());

Example 3: Transfers using Session Code

In this example, we use session code to perform a transfer using the transfer_from_purse_to_purse system function. The entire session code is available in GitHub, but this is the call function:

#[no_mangle]
pub extern "C" fn call() {
let target_purse: URef = runtime::get_named_arg(ARG_TARGET_PURSE);
let amount: U512 = runtime::get_named_arg(ARG_AMOUNT);

let source_purse = account::get_main_purse();

system::transfer_from_purse_to_purse(source_purse, target_purse, amount, None)
.unwrap_or_revert();
}

Another system function is transfer_to_public_key. The full session code example is on GitHub.

#[no_mangle]
pub extern "C" fn call() {
let account_hash: PublicKey = runtime::get_named_arg(ARG_TARGET);
let transfer_amount: U512 = runtime::get_named_arg(ARG_AMOUNT);
system::transfer_to_public_key(account_hash, transfer_amount, None).unwrap_or_revert();
}

Other transfer functions are available here:

Compiling Session Code

Before running session code to interact with a contract or other entities on the network, you must compile it to Wasm. Run the following command in the directory hosting the Cargo.toml file and src folder.

cargo build --release --target wasm32-unknown-unknown

For the examples above, you may use the Makefiles provided:

make build-contract

Executing Session Code

Before running session code on a live Casper network, test it as described here. You can also set up a local network using NCTL for additional tests.

Session code can execute on a Casper network via a Deploy. All deploys can be broadly categorized as some unit of work that, when executed and committed, affects change to the network's global state.

The Casper command-line client and its put-deploy command provide one way to execute session code.

casper-client put-deploy \
--node-address <HOST:PORT> \
--chain-name <NETWORK-NAME> \
--secret-key <PATH> \
--payment-amount <PAYMENT-AMOUNT> \
--session-path <SESSION-PATH> \
--session-arg <"NAME:TYPE='VALUE'" OR "NAME:TYPE=null">
  • node-address - An IP address of a peer on the network. The default port for JSON-RPC servers on Mainnet and Testnet is 7777.
  • secret-key - The file name containing the secret key of the account paying for the deploy.
  • chain-name - The network where the deploy should be sent. For Mainnet, use casper. For Testnet, use casper-test.
  • payment-amount - Payment for the deploy in motes. The payment amount varies based on the deploy and network chainspec.
  • session-path - Path to the contract Wasm, pointing to the compiled contract.
  • session-arg - A named and typed argument passed to the Wasm code.

Use the --help option to view an updated list of supported arguments.

casper-client put-deploy --help

Video Walkthrough

The following brief video describes sample session code for configuring an account.

What's Next?

Disclaimer

By accepting this CasperLabs Tech Spec (this "Whitepaper"), each recipient hereof acknowledges and agrees that is not authorised to, and may not, forward or deliver this Whitepaper, electronically or otherwise, to any other person or reproduce this Whitepaper in any manner whatsoever. Any forwarding, distribution or reproduction of this Whitepaper in whole or in part is unauthorised. Failure to comply with this directive may result in a violation of applicable laws of any affected or involved jurisdiction.

Nothing in this Whitepaper constitutes an offer to sell, or a solicitation to purchase, the tokens native to the Casper blockchain ("CSPR”). In any event, were this Whitepaper to be deemed to be such an offer or solicitation, no such offer or solicitation is intended or conveyed by this Whitepaper in any jurisdiction where it is unlawful to do so, where such an offer or solicitation would require a license or registration, or where such an offer or solicitation is subject to restrictions. In particular, any CSPR to be issued have not been, and, as of the date of issuance of this Whitepaper, are not intended to be, registered under the securities or similar laws of any jurisdiction, whether or not such jurisdiction considers the CSPR to be a security or similar instrument, and specifically, have not been, and, as of the date of issuance of this Whitepaper are not intended to be, registered under the U.S. Securities Act of 1933, as amended, or the securities laws of any state of the United States of America or any other jurisdiction and may not be offered or sold in any jurisdiction where to do so would constitute a violation of the relevant laws of such jurisdiction.

This Whitepaper constitutes neither a prospectus according to Art. 652a of the Swiss Code of Obligations (the "CO”) or Art. 1156 CO nor a prospectus or basic information sheet according to the Swiss Financial Services Act (the "FinSA”) nor a listing prospectus nor a simplified prospectus according to Art. 5 of the Swiss Collective Investment Schemes Act (the "CISA”) nor any other prospectus according to CISA nor a prospectus under any other applicable laws.

The CSPR are not expected to be instruments in an offer and sale which are subject to the jurisdiction or oversight of the U.S. Securities Exchange Commission (the "SEC”). In any event, however, CSPR have not been approved or disapproved by, and are not expected to be approved or disapproved by, the SEC nor by the securities regulatory authority of any state of the United States of America or of any other jurisdiction, and neither the SEC nor any such securities regulatory authority has passed, or is expected to pass, upon the accuracy or adequacy of this Whitepaper.

The distribution of this Whitepaper and the purchase, holding, and/or disposal of CSPR may be restricted by law in certain jurisdictions. Persons reading this Whitepaper should inform themselves as to (i) the possible tax consequences, (ii) the legal and regulatory requirements, and (iii) any foreign exchange restrictions or exchange control requirements, which they might encounter under the laws of the countries of their citizenship, residence or domi-cile and which might be relevant to the purchase, holding or disposal of CSPR. No action has been taken to authorise the distribution of this Whitepaper in any jurisdiction in which such authorisation might be required.

No action has been or is intended to be taken by CasperLabs Networks AG and/or any of its affiliates in any jurisdiction that would or is intended to, permit a public sale or offering of any CSPR, or possession or distribution of this Whitepaper (in preliminary, proof or final form) or any other sale, offering or publicity material relating to the CSPR, in any country or jurisdiction where action for that purpose is required. Each recipient of this Whitepaper is reminded that it has received this Whitepaper on the basis that it is a person into whose possession this Whitepaper may be lawfully delivered in accordance with the laws of the jurisdiction in which it is located and/or bound and it may not nor is it authorised to deliver this document, electronically or otherwise, to any other person. If the recipient receives this document by e-mail, then its use of this e-mail is at its own risk and it is the recipient’s responsibility to take precautions to ensure that such e-mail is free from viruses and other items of a destructive nature.

Preliminary Nature of this Whitepaper

This Whitepaper is a draft and the information set out herein is of a preliminary nature. Consequently, neither CasperLabs Networks AG nor any of its affiliates assumes any responsibility that the information set out herein is final or correct and each of the foregoing disclaims, to the fullest extent permitted by applicable law, any and all liability whether arising in tort, contract or otherwise in respect of this Whitepaper. Neither this Whitepaper nor anything contained herein shall form the basis of or be relied on in connection with or act as an inducement to enter into any contract or commitment whatsoever. Recipients should note that the final structuring of CSPR and the Casper blockchain is subject to ongoing technical, legal, regulatory and tax considerations and each is, therefore, subject to material changes. In particular, neither the applicability nor the non-applicability of Swiss financial market regulations on the CSPR sale has not been confirmed by the Swiss Financial Market Supervisory Authority ("FINMA”). CasperLabs Networks AG and all its affiliates reserve the right to not assist in the completion of the software underlying CSPR and the CasperLabs blockchain, to not participate in the issuance or creation of CSPR or to change the structure of CSPR and/or the Casper blockchain for any reason, each at its sole discretion.

Forward-Looking Statements

This Whitepaper includes "forward-looking statements”, which are all statements other than statements of historical facts included in this Whitepaper. Words like "believe”, "anticipate”, "expect”, "project”, "estimate”, "predict”, "intend”, "target”, "assume”, "may”, "might”, "could”, "should”, "will” and similar expressions are intended to identify such forward-looking statements. Such forward-looking statements involve known and unknown risks, uncertainties and other factors, which may cause the actual functionality, performance or features of the Casper blockchain and/or CSPR to be materially different from any future functionality, performance or features expressed or implied by such forward-looking statements. Such forward-looking statements are based on numerous assumptions regarding the CasperLabs Networks AG’s and/or any of its affiliates’ present and future expectations regarding the development of the Casper blockchain and the associated software.

These forward-looking statements speak only as of the date of this Whitepaper. CasperLabs Networks AG and its affiliates expressly disclaim any obligation or undertaking to release any updates of or revisions to any forward-looking statement contained herein to reflect any change in CasperLabs Networks AG’s and/or any of its affiliates’ expectations with regard thereto or any change in events, conditions or circumstances on which any such statement is based.

Risk Factors

Furthermore, by accepting this Whitepaper, the recipient of hereof (the "Recipient”) acknowledges and agrees that it understands the inherent risks associated with blockchain and distributed ledger technology, tokens and cryptocurrencies in general and the CSPR in particular, including, but not limited to, those outlined hereinafter.

  • Risks associated with CasperLabs Networks AG’s experience: the Recipient is aware that CasperLabs Networks AG and its affiliates constitute a start-up group of companies. Inability of such companies to manage their affairs, including any failure to attract and retain appropriate personnel, could affect the completion and functionality of the Casper blockchain.

  • Risks associated with CSPR relative value: the Recipient understands and accepts that a purchaser of CSPR may experience financial losses relative to other assets, including fiat currency and/or any other cryptocurrency (including any cryptocurrency used to acquire CSPR). Potential purchasers and holders of CSPR are urged to carefully review this Whitepaper and assess and understand the risk factors relating to the CSPR and the Casper blockchain before acquiring CSPR (when and if CSPR become available).

  • Risks associated with (intellectual) property rights: the Recipient understands and accepts that, due to a lack of originality of the software and to the immaterial character of the CSPR, there may be no title of ownership in and to the intellectual property rights relating to CSPR.

  • Risks associated with blockchain: the Recipient understands and accepts that the smart contract, the underlying software application and software platform (i.e. the Casper blockchain) is still in an early development stage and unproven. The Recipient understands and accepts that there is no warranty that the process for creating the CSPR and/or the Casper blockchain will be uninterrupted or error-free and acknowledges that there is an inherent risk that the software could contain weaknesses, vulnerabilities or bugs causing, inter alia, the complete loss of CSPR. The Recipient understands and accepts that, after launch of the Casper blockchain, the smart contract and/or underlying protocols and/or the Casper blockchain and/or any other software involved may either delay and/or not execute a contribution due to the overall contribution volume, mining attacks and/or similar events.

  • Risk of weaknesses in the field of cryptography: the Recipient understands and accepts that cryptography is a technology that evolves relatively fast over time. At the same time, methods and tools to decrypt, access and/or manipulate data stored on a distributed ledger or blockchain are highly likely to progress in parallel and in addition, new technological developments such as quantum computers may pose as of now unpredictable risks to the CSPR and the Casper blockchain that could increase the risk of theft or loss of CSPR (if and when CSPR are created and/or issued).

  • Regulatory risks: the Recipient understands and accepts that it is possible that certain jurisdictions will apply existing regulations on, or introduce new regulations addressing, distributed ledger technology and/or blockchain technology based applications, which may be contrary to the current setup of the smart contract or the CasperLabs Networks AG project and which may, inter alia, result in substantial modifications of the smart contract and/or the CasperLabs Networks AG project, including its termination and the loss of the CSPR, if and when created and/or issued, or entitlements to receive CSPR, for the Recipient.

  • Risks associated with abandonment / lack of success: the Recipient understands and accepts that the creation of the CSPR and the development of the Casper blockchain as well as the CasperLabs Networks AG project may be abandoned for a number of reasons, including lack of interest from the public, lack of funding, lack of prospects (e.g. caused by competing projects) and legal, tax or regulatory considerations. The Recipient therefore understands that there is no assurance that, even if the CSPR/CasperLabs blockchain project is partially or fully developed and launched, the Recipient will receive any benefits through the CSPR held by it (if and when created and/or issued).

  • Risks associated with a loss of private key: the Recipient understands and accepts that CSPR, if and when created and/or issued, will only be accessed by using a wallet technically compatible with CSPR and with a combination of the Recipient’s account information (address) and private key, seed or password. The Recipient understands and accepts that if its private key or password gets lost or stolen, the CSPR associated with the Recipient’s account (address) will be unrecoverable and will be permanently lost.

  • Risks associated with wallets: the Recipient understands and accepts that CasperLabs Networks AG or any of its affiliates, employees, partners or advisors are in no way responsible for the wallet to which any CSPR are transferred. The Recipient understands and agrees that it is solely responsible for the access and security of its wallet, for any security breach of its wallet and/or with any loss of CSPR resulting from its wallet service provider, including any termination of the service by the wallet provider and/or bankruptcy of the wallet provider.

  • Risks associated with theft/hacks: the Recipient understands and accepts that the smart contract, the website, the underlying software application and software platform (i.e. the Casper blockchain), during its development and after its launch, may be exposed to attacks by hackers or other individuals that could result in an inability to launch the Casper blockchain or the theft or loss of CSPR. Any such event could also result in the loss of financial and other support of the CasperLabs Networks AG project impacting the ability to develop the CasperLabs Networks AG project and Casper blockchain.

  • Risks associated with mining attacks: the Recipient understands and accepts that, as with other cryptocurrencies and tokens, if and when launched, the Casper blockchain is susceptible to attacks relating to validators. Any successful attack presents a risk to the smart contract, expected proper execution and sequencing of transactions, and expected proper execution and sequencing of contract computations.

  • Risks associated with a lack of consensus: the Recipient understands and accepts that the network of validators will be ultimately in control of the genesis block and future blocks and that there is no warranty or assurance that the network of validators will perform their functions and reach proper consensus and allocate the CSPR to the Recipient as proposed by any terms. The Recipient further understands that a majority of the validators could agree at any point to make changes to the software and/or smart contracts and to run the new version of the software and/or smart contracts. Such a scenario could lead to the CSPR losing intrinsic value.

  • Risks associated with liquidity of CSPR: the Recipient understands and accepts that with regard to the CSPR, if and when created and/or issued, no market liquidity may be guaranteed and that the value of CSPR relative to other assets, including fiat currency and/or any other cryptocurrency (including any cryptocurrency used to acquire CSPR) over time may experience extreme volatility or depreciate in full (including to zero) resulting in loss that will be borne exclusively by the Recipient.

  • Risks associated with forking: the Recipient understands and accepts that hard and soft forks as well as similar events may, inter alia, lead to the creation of new or competing tokens to the CSPR, adversely affect the functionality, convertibility or transferability or result in a full or partial loss of units or reduction (including reduction to zero) of value of the Recipient’s CSPR (if and when created and/or issued).

Overview of Casper Economics

Casper's economic activity can be conceptualized as taking place on four distinct layers: consensus, runtime, ecosystem, and the macroeconomy. Each layer, consensus and up, provides a foundation for the activity taking place on the next layer. A trust-less platform requires that proper incentives be provided to participants operating each of these layers to ensure that they work together to unlock the platform's value.

We cannot yet provide formal game-theoretic results for our incentive mechanisms, but interested readers can follow our progress with the Economics of the Casper Blockchain paper, which will be periodically updated to summarize ongoing research.

This section of our online documentation is intended only to familiarize the user with our core economics features rather than describe their precise implementation and user interface. Some of the features may not be currently active.

Consensus

The consensus layer of our platform runs on the Highway flavor of CBC-Casper. The distinguishing characteristics of this protocol are its safety and liveness guarantees. Specifically, under the assumptions made in the Highway protocol paper, blocks in the canonical history cannot be reverted, and new blocks continue to be added to this history indefinitely. The assumptions, however, require that a large portion of validators remain online and honest; this assumed behavior must be incentivized for the platform to remain secure and live.

When discussing consensus, we default to considering it "one era at a time," unless expressly stated otherwise, in keeping with the Highway paper. Recall that each era is, effectively, a separate instance of the protocol.

Agents (consensus layer)

Validators are responsible for maintaining platform security by building an ever-growing chain of finalized blocks, backing this chain's security with their stakes. Their importance (often referred to as "weight") both to protocol operation and security is, in fact, equal to their stake, which includes both their own and delegated tokens.

Delegators are users who participate in the platform's security by delegating their tokens to validators, which adds to their weight and collecting a part of the rewards proportional to their delegations, net of a cut ("delegation rate") that is collected by the validator.

Incentives (consensus layer)

The auction determines the composition of the validator set for each era of the protocol. It is a "first-price" (winning bids become stakes) auction with a fixed number of spots chosen to balance security with performance (generally, the platform will run slower with more validators). Because rewards are proportional to the stake, we expect this competitive mechanism to provide a powerful impetus for staking as many tokens as possible.

Rewards (per era) are issued to validators who perform, at their nominal pace, in such a way as to make timely progress on block finalization. These rewards are shared with delegators proportionally to their contributions, net of a cut taken by the validator.

Evictions deactivate validators who fail to participate in an era, disabling their bid and suspending their participation until they signal readiness to resume participation by invoking a particular entry point in the auction contract.

Runtime

The runtime layer encompasses the deployment and execution of smart contracts, session code, and other activity that performs computation on the global state. This suggests potential markets for finite platform resources, such as markets for computing time and storage. Such markets could ensure that resources are allocated to their highest-value uses. Currently, however, we limit ourselves to metering computing time, measured as gas. Gas can be conceptualized as relative time use of different Wasm operations and host-side functions. Use of storage is also presently assigned a gas cost. We do not currently have a pricing mechanism for metered gas, although an outstanding Casper Enhancement Proposal (CEP #22) suggests the implementation of a first-price gas auction similar to Ethereum's. The initial Mainnet deploy selection mechanism is based on FIFO.

We expect to continue work on runtime resource markets, particularly gas futures (CEP #17).

Agents (consensus layer)

Validators again play a vital role in this layer since protocol operation includes construction and validation of new blocks, consisting of deploys that change the global state, which the validators also maintain.

Users execute session and contract code using the platform's computational resources

Incentives (consensus layer)

Transaction fees, or charges for gas use, ensure that the users compensate validators for performing their computations. Transaction fees are awarded to the block creator. Because we expect to launch with FIFO ordering of deploys, it can be assumed that one unit of gas will be priced at one mote until future changes to deploy orders are implemented.

Ecosystem

The ecosystem layer encompasses dApp design and operation. Casper Labs maintains multiple partnerships with prospective dApp developers, and we anticipate devoting significant resources to research the economics of prospective dApps.

Macroeconomy

Casper's macroeconomics refers to the activity in the cryptocurrency markets, where CSPR can be treated as one crypto-asset among many rather than a computational platform. Our token economics are different from those of "digital gold" tokens like Bitcoin, designed to be scarce. Our tokens are minted from a fixed starting basis, which is accounted for by tokens distributed to genesis validators, employees, community members and held for future distributions. The total supply of tokens grows at a fixed annual percentage rate from this basis.

The inflationary nature of our macroeconomics has two significant advantages over enforced scarcity. Inflation incentivizes token holders to stake or delegate their tokens, a behavior we explicitly support with our delegation feature. Additionally, because Casper is a general-purpose computing platform, it is essential to supply tokens to support actual economic activity on the platform and discourage hoarding tokens in expectation of speculative gain.

Glossary

These definitions are correct in the context of the Casper Labs. They may (and probably will) have slightly different semantics in other contexts, including other blockchain contexts.


A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


What is Casper?

What is Casper?

Casper is a new Turing-complete smart-contracting platform, backed by a Proof-of-Stake (PoS) consensus algorithm and WebAssembly (Wasm). The network is a permissionless, decentralized, public blockchain.

The network's consensus protocol is called Highway, and it has several benefits over classic Byzantine Fault Tolerant (BFT) consensus protocols. First, Highway allows networks to reach higher thresholds of finality, meaning that more blocks are finalized, and validators agree to add them to the blockchain. Second, the protocol achieves flexibility by expressing block finality in ways not possible in BFT models. This protocol is built on the correct-by-construction (CBC) Casper research.

Additionally, the Casper Network is optimized for enterprise and developer adoption. While leveraging blockchain technology, the network seeks to accelerate business operations via unique features like predictable network fees, upgradeable contracts, on-chain governance, privacy flexibility, and developer-friendly languages. Casper's core features and strengths enable developers and enterprises to reap the benefits of blockchain technology.

Casper also solves the scalability trilemma. Notably, the network is optimized for security, decentralization, and high throughput. All this is achieved while evolving to provide leading solutions for open-source projects and enterprises.

How does Casper work?

Casper relies on a group of validators to verify transactions and uphold the network. Unlike Proof-of-Work networks, which need to centralize validators for economies of scale, Casper allows for the geographical decentralization of validators. Casper validators verify transactions based on staked tokens and receive CSPR rewards for participating in the PoS consensus mechanism. CSPR is the native token on the Casper Network.

To understand the design further, read this article.

Disclaimer

Read the Legal Disclaimer regarding this CasperLabs Tech Spec (this "Whitepaper").

Bonding as a Validator

It is recommended that a bonding request be sent once the node has completed the synchronization process. In a Casper network, bonding takes place through the auction contract via the add_bid.wasm contract. The auction runs for a future era, every era. The chainspec.toml specifies the number of slots available, and the auction will take the top N slots and create the validator set for the future era.

In the Testnet, era durations are approximately two hours. The entire process takes approximately 3 eras. Therefore, the time for bid submission to inclusion in the validator set is a minimum of six hours. Bonding requests (bids) are transactions like any other. Because they are generic transactions, they are more resistant to censorship.

Method 1: Bonding with the System Auction Contract

This method submits a bid using the system auction contract. Call the existing add_bid entry point from the system auction contract. Using this method, you do not need to build any contracts, reducing costs and complexity.

sudo -u casper casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT_IN_MOTES> \
--session-hash <SESSION_HASH> \
--session-entry-point add_bid \
--session-arg="public_key:public_key='<PUBLIC_KEY_HEX>'" \
--session-arg="amount:u512='<BID_AMOUNT>'" \
--session-arg="delegation_rate:u8='<PERCENT_TO_KEEP_FROM_DELEGATORS>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version 1.5.1
  5. session-hash - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:
  • Testnet: hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2
  • Mainnet: hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea
  1. session-entry-point - Name of the entrypoint that will be used when calling the contract

The add_bid entry point expects three arguments:

  1. public key: The hexadecimal public key of the account's purse submitting the bid. This key must match the secret key that signs the bid
  2. amount: The bidding amount
  3. delegation_rate: Percentage of the rewards that the node operator retains for their services

The command will return a deploy hash, which is needed to verify the deploy's processing results.

note

Calling the add_bid entry point on the auction contract has a fixed cost of 2.5 CSPR.

Example:

This example command uses the Casper Testnet to bid 10,000 CSPR for a validating slot:

sudo -u casper casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--chain-name casper-test \
--secret-key /etc/casper/validator_keys/secret_key.pem \
--payment-amount 2500000000 \
--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \
--session-entry-point add_bid \
--session-arg "public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'" \
--session-arg "amount:U512='$[10000 * 1000000000]'" \
--session-arg="delegation_rate:u8='10'"

Next, check the status of the auction to see if you have won a validator slot.

Method 2: Bonding with Compiled Wasm

Another way to send a bonding transaction to the network is via a deploy containing the compiled add_bid.wasm. For details, refer to Building the Required Contracts.

The following deploy is a template for sending a bonding request:

sudo -u casper casper-client put-deploy \
--node-address http://<HOST:PORT> \
--secret-key /etc/casper/validator_keys/secret_key.pem \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT> \
--session-path $HOME/casper-node/target/wasm32-unknown-unknown/release/add_bid.wasm \
--session-arg="public_key:public_key='<PUBLIC_KEY_HEX>'" \
--session-arg="amount:u512='<BID-AMOUNT>'" \
--session-arg="delegation_rate:u8='<PERCENT_TO_KEEP_FROM_DELEGATORS>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes
  5. session-path - The path to the compiled Wasm on your computer

The add_bid.wasm expects three arguments:

  1. public_key: The hexadecimal public key of the account's purse submitting the bid. This key must match the secret key that signs the bid
  2. amount: The bidding amount
  3. delegation_rate: Percentage of the rewards that the node operator retains for their services

The command will return a deploy hash, which is needed to verify the deploy's processing results.

note

This method is more expensive than calling the add_bid entrypoint in the system auction contract, which has a fixed cost of 2.5 CSPR.

Example:

Here is an example request to bond using the add_bid.wasm. The payment amount specified is 3 CSPR. You must modify the payment and other values in the deploy based on the network's chainspec.toml.

sudo -u casper casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--secret-key /etc/casper/validator_keys/secret_key.pem \
--chain-name casper-test \
--payment-amount 3000000000 \
--session-path ~/casper-node/target/wasm32-unknown-unknown/release/add_bid.wasm \
--session-arg "public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'" \
--session-arg "amount:U512='$[10000 * 1000000000]'" \
--session-arg="delegation_rate:u8='10'"

Next, check the bid status to see if you have won a validator slot.

Checking the Bid Status

Since the bid was submitted using a deploy like any other, perform get-deploy using the casper-client, to see the execution status.

casper-client get-deploy --node-address http://<HOST:PORT> <DEPLOY_HASH>

If the bid wins the auction, the public key and associated bonded amount will appear in the auction contract as part of the validator set for a future era. To determine if the bid was accepted, query the auction contract:

casper-client get-auction-info --node-address http://<HOST:PORT>
Example auction info response
{
"jsonrpc": "2.0",
"result": {
"bids": [
{
"bid": {
"bonding_purse": "uref-488a0bbc3c3729f5696965da7a3aeee83805392944e36157909da273255fdb85-007",
"delegation_rate": 0,
"delegators": [],
"release_era": null,
"reward": "93328432442428418861229954179737",
"staked_amount": "10000000000000000"
},
"public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012"
},
{
"bid": {
"bonding_purse": "uref-14e128b099b0c3680100520226e6999b322989586cc22db0630db5ec1329f0a7-007",
"delegation_rate": 10,
"delegators": [],
"release_era": null,
"reward": "0",
"staked_amount": "9000000000000000"
},
"public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87"
},
{
"bid": {
"bonding_purse": "uref-6c0bf8cee1c0749dd9766376910867a84b2e826eaf6c118fcb0224c7d8d229dd-007",
"delegation_rate": 10,
"delegators": [],
"release_era": null,
"reward": "266185120443441810685787",
"staked_amount": "100000000"
},
"public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f"
},
{
"bid": {
"bonding_purse": "uref-3880b3daf95f962f57e6a4b1589564abf7deef58a1fb0753d1108316bba7b3d7-007",
"delegation_rate": 10,
"delegators": [],
"release_era": null,
"reward": "0",
"staked_amount": "9000000000000000"
},
"public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643"
},
{
"bid": {
"bonding_purse": "uref-5a777c9cd53456b49eecf25dcc13e12ddff4106175a69f8e24a7c9a4c135df0d-007",
"delegation_rate": 0,
"delegators": [],
"release_era": null,
"reward": "93328432442428418861229954179737",
"staked_amount": "10000000000000000"
},
"public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e"
}
],
"block_height": 318,
"era_validators": [
{
"era_id": 20,
"validator_weights": [
{
"public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",
"weight": "10000000000000000"
},
{
"public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",
"weight": "9000000000000000"
},
{
"public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",
"weight": "100000000"
},
{
"public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",
"weight": "9000000000000000"
},
{
"public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",
"weight": "10000000000000000"
}
]
},
{
"era_id": 21,
"validator_weights": [
{
"public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",
"weight": "10000000000000000"
},
{
"public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",
"weight": "9000000000000000"
},
{
"public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",
"weight": "100000000"
},
{
"public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",
"weight": "9000000000000000"
},
{
"public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",
"weight": "10000000000000000"
}
]
},
{
"era_id": 22,
"validator_weights": [
{
"public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",
"weight": "10000000000000000"
},
{
"public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",
"weight": "9000000000000000"
},
{
"public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",
"weight": "100000000"
},
{
"public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",
"weight": "9000000000000000"
},
{
"public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",
"weight": "10000000000000000"
}
]
},
{
"era_id": 23,
"validator_weights": [
{
"public_key": "013f774a58f4d40bd9b6cce7e306e53646913860ef2a111d00f0fe7794010c4012",
"weight": "10000000000000000"
},
{
"public_key": "01405133e73ef2946fe3a2d76a4c75d305a04ad6b969f3c4a8a0d27235eb260f87",
"weight": "9000000000000000"
},
{
"public_key": "01524a5f3567d7b5ea17ca518c9d0320fb4a75a28a5eab58d06c755c388f20a19f",
"weight": "100000000"
},
{
"public_key": "01a6901408eda702a653805f50060bfe00d5e962747ee7133df64bd7bab50b4643",
"weight": "9000000000000000"
},
{
"public_key": "01d62fc9b894218bfbe8eebcc4a28a1fc4cb3a5c6120bb0027207ba8214439929e",
"weight": "10000000000000000"
}
]
}
],
"state_root_hash": "c16ba80ea200d786008f8100ea79f9cfeb8d7d5ee8b133eda5a50dcf1c7131e8"
},
"id": -3624528661787095850
}

Note the era_id and the validator_weights in the response above. The current era is the one with the lowest ID in the era_validators array. For a given era_id, a set of validators is defined. If the public key associated with a bid appears in the validator_weights structure for an era, then the account is bonded in that era.

A Losing Bid

If a bid doesn't win a slot in the auction, it is too low. The resolution is to increase the bid amount. It is possible to submit additional bids, to increase the odds of winning a slot. It is also possible to encourage token holders to delegate stake to you for bonding.

Avoiding Ejection

To stay bonded and avoid ejection, each validator must keep their node running and in sync with the rest of the network. To recover from ejection, you will find more details here.

Withdrawing a Bid

Follow the steps in Unbonding to withdraw a bid.

Inactive vs. Faulty Validator Nodes

This page describes the differences between a validator node being considered inactive or faulty.

In the last block of each era N, the consensus algorithm checks whether there are any messages from your validator node in that era that have been received by most of the other validators. Only if there is no such message does your node get marked as inactive in that block.

Similarly, the consensus algorithm checks whether any two messages from your validator node contradict each other. If that is the case, it gets marked as faulty in that block. Usually, that means:

  • If you got marked as inactive, your node probably crashed or was offline for the duration of one whole era, i.e., at least from when the era began until the era's last block was proposed.
  • If you got marked as faulty, you were probably running two nodes with the same validator key, or you restarted a node during the era and deleted its unit file.

The auction contract is run when the block gets executed, as always at the end of the era. But if you were faulty or inactive, you are now evicted and don't participate in the auction anymore. You also don't receive any rewards for era N. The auction determines the validator set for the era after the next (because auction_delay is set to 1 on mainnet), i.e., for era N + 2. That means you will still be a validator (with a weight proportional to your stake) in the next era, N + 1, but after that, you will not be a validator anymore, and your slot will be given to the next highest bidder.

And even in the next era, N + 1:

  • If you are inactive, you won't be assigned leader slots or be allowed to propose any blocks. Your node will only vote on other proposers' blocks if it returns online and can still receive rewards. But, even if it comes back online in era N + 1, it will get evicted for being offline in era N.
  • If you are faulty, all your messages will be ignored. You won't be able to propose blocks or vote for them and won't receive block rewards.

In both cases, you remain evicted until you reactivate your bid, as described here.

Becoming a Validator

After setting up a node, the operator can submit a bid to win a validating slot and bond to the network. This section also covers unbonding from the network, recovering from eviction, and the differences between inactive and faulty nodes.

TitleDescription
Bonding as a ValidatorA guide about the bonding process and submitting a bid
Unbonding as a ValidatorThe process to withdraw a bid and unbonding
Recovering from Validator EvictionSteps a validator needs to take if it is evicted from the validator set
Inactive vs. Faulty NodesThe differences between inactive and faulty nodes

Recovering from Validator Eviction

This topic discusses the steps a validator needs to take if it is evicted from the validator set:

  1. Detecting the eviction
  2. Correcting any underlying node issues
  3. Re-building the contracts for bonding
  4. Activating the bid
  5. Checking the bid

The Inactive vs. Faulty Validator Nodes topic explains why a node would be evicted.

Detecting the Eviction

The validator selection occurs at the end of an Era. Due to the bonding delay, this determines the Validators for the Era after the Era is about to start. When a validating node does not participate in consensus for some time, it will be marked invalid and evicted at the end of the next Era.

For example, if we are in Era 100 and your node is invalid, your node will be marked for eviction to be removed at the start of Era 102. This is due to the bonding delay of 1 Era.

Detection using CSPR.live

If you were a previous validator and still exist on the Validators Auction tab but not in Validators, you may have been evicted or outbid.

Detection using the Casper Client

All auction information is returned with the casper-client get-auction-info command. It would help if you filtered this down to your public key.

You can replace the <public_key> with your public key manually and run this command:

casper-client get-auction-info | jq '.result.auction_state.bids[] | select( .public_key == "<public_key>")'

Or, if you set up the node as described in this documentation, you can run another command that will automatically put in your public key:

casper-client get-auction-info | jq --arg pk "$(cat /etc/casper/validator_keys/public_key_hex)" '.result.auction_state.bids[] | select( (.public_key | ascii_downcase) == ($pk | ascii_downcase) )'

You know you were evicted if the get-auction-info command returned your bid showing an inactive field. See the Inactive vs. Faulty Validator Nodes page for more information.

If you receive a parse error: Invalid numeric literal at, this usually means that your RPC port is not up yet. Get your node in sync, and the RPC will come up. This should be working before you try to recover. Try running the following command to check the status of your RPC port:

casper-client get-auction-info

Correcting any Underlying Node Issues

Before fixing the eviction, you need to correct the problem that caused your node to be evicted. Stage missed upgrades, correct any node issues, and get your node in sync.

To check if your node is in sync, compare the current block height at https://cspr.live/ with the height from your node with:

curl -s localhost:8888/status | jq .last_added_block_info

If you cannot figure out the issue, ask for help in the node-tech-support channel on Discord.

Activating the Bid

Once your node is in sync and ready to validate again, you must activate your invalid bid. There are two ways to reactivate your bid. The recommended and cheaper method is to call the activate_bid entry point from the system auction contract. The second method involves building the activate_bid.wasm contract as explained in Building the Required Contracts.

We recommend testing the following steps on the official Testnet before performing them in a live environment like the Casper Mainnet.

Method 1: Activating the Bid with the System Auction Contract

This method calls the existing activate_bid entry point from the system auction contract. Using this method, you do not need to build any contracts, reducing costs and complexity.

sudo -u casper casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT_IN_MOTES> \
--session-hash <SESSION_HASH> \
--session-entry-point activate_bid \
--session-arg "validator_public_key:public_key='$(cat /etc/casper/validator_keys/public_key_hex)'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes. You must check the network's chainspec. For example, this entry point call needs 10,000 motes for node version 1.5.1
  5. session-hash - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are:
  • Testnet: hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2
  • Mainnet: hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea
  1. session-entry-point - Name of the entry point that will be used when calling the system auction contract. In this case, it is activate_bid

The activate_bid entry point expects one argument:

  1. validator_public_key: The hexadecimal public key of the validator reactivating its bid. This key must match the secret key that signs the bid activation request

The command will return a deploy hash, which is needed to verify the deploy's processing results. Refer to the Deploy Status section for more details.

tip

Calling the activate_bid entry point on the auction contract has a fixed cost of 10,000 motes.

Example:

This example uses the Casper Testnet to reactivate a bid:

sudo -u casper casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--secret-key /etc/casper/validator_keys/secret_key.pem \
--chain-name casper-test \
--payment-amount 10000 \
--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \
--session-entry-point activate_bid \
--session-arg "validator_public_key:public_key='$(cat /etc/casper/validator_keys/public_key_hex)'"

Next, check the bid activation status.

Method 2: Activating the Bid with Compiled Wasm

The second method to rejoin the network is to reactivate your bid using the activate_bid.wasm.

sudo -u casper casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT_IN_MOTES> \
--session-path "$HOME/casper-node/target/wasm32-unknown-unknown/release/activate_bid.wasm" \
--session-arg "validator_public_key:public_key='$(cat /etc/casper/validator_keys/public_key_hex)'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes
  5. session-path - The path to the compiled Wasm on your computer

The activate_bid.wasm expects one argument:

  1. validator_public_key: The hexadecimal public key of the validator reactivating its bid. This key must match the secret key that signs the bid activation request

The command will return a deploy hash, which is needed to verify the deploy's processing results.

note

As described above, this method is much more expensive than calling the activate_bid entry point.

Example:

Here is an example that reactivates a bid using the activate_bid.wasm. You must modify the payment and other values in the deploy based on your environment and the network's chainspec.toml. For example, if you use the activate_bid.wasm on a network with node version 1.4.9, you will require a balance of at least 5 CSPR for this contract.

sudo -u casper casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--secret-key /etc/casper/validator_keys/secret_key.pem \
--chain-name casper-test \
--payment-amount 5000000000 \
--session-path "$HOME/casper-node/target/wasm32-unknown-unknown/release/activate_bid.wasm" \
--session-arg "validator_public_key:public_key='$(cat /etc/casper/validator_keys/public_key_hex)'"

Check that the deploy was successful with the casper-client get-deploy <deploy_hash> or by searching for the deploy hash on https://cspr.live/. Also, check the bid activation status as shown below.

Checking the Bid Activation

Once your deploy processes, you can check your bid again. You should now see "inactive": false in the output.

If you wait until the next Era starts, you should also see your public key as a future validator on the Validators tab.

Unbonding as a Validator

Once a bid is placed, it will remain in the state of the auction contract, even if the bid fails to win a slot immediately. New slots may become available if bonded validators leave the network or reduce their bond amounts. Therefore, a bid must be explicitly withdrawn to remove it from the auction.

Method 1: Unbonding with the System Auction Contract

This method withdraws a bid using the system auction contract. Call the existing withdraw_bid entry point from the system auction contract. Using this method, you do not need to build any contracts, reducing costs and complexity.

sudo -u casper casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT_IN_MOTES> \
--session-hash <SESSION_HASH> \
--session-entry-point withdraw_bid \
--session-arg="public_key:public_key='<PUBLIC_KEY_HEX>'" \
--session-arg="amount:u512='<AMOUNT_TO_WITHDRAW>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes. This entry point call needs 2.5 CSPR for node version 1.5.1
  5. session-hash - Hex-encoded hash of the stored auction contract, which depends on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:
  • Testnet: hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2
  • Mainnet: hash-ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea
  1. session-entry-point - Name of the entrypoint that will be used when calling the contract

The withdraw_bid entry point expects two arguments, while the third one is optional:

  1. public key: The hexadecimal public key of the account's purse to withdraw. This key must match the secret key that signs the deploy and has to match the public key of a bid in the auction contract
  2. amount: The amount being withdrawn

The command will return a deploy hash, which is needed to verify the deploy's processing results.

note

Calling the withdraw_bid entry point on the auction contract has a fixed cost of 2.5 CSPR.

Example:

This example command uses the Casper Testnet to withdraw 5 CSPR from the bid:

sudo -u casper casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--secret-key /etc/casper/validator_keys/secret_key.pem \
--chain-name casper-test \
--payment-amount 2500000000 \
--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \
--session-entry-point withdraw_bid \
--session-arg "public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'" \
--session-arg "amount:U512='$[5 * 1000000000]'"

Below is the same command with the optional purse set to a different purse where the amount will be returned. Adjust all the values to your use case.

sudo -u casper casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--secret-key /etc/casper/validator_keys/secret_key.pem \
--chain-name casper-test \
--payment-amount 2500000000 \
--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \
--session-entry-point withdraw_bid \
--session-arg "public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'" \
--session-arg "amount:U512='$[5 * 1000000000]'"

Method 2: Unbonding with Compiled Wasm

There is a second way to withdraw a bid, using the compiled Wasm withdraw_bid.wasm. The process is the same as bonding but uses a different contract.

sudo -u casper casper-client put-deploy \
--node-address <HOST:PORT> \
--secret-key <PATH> \
--chain-name <CHAIN_NAME> \
--payment-amount <PAYMENT_AMOUNT> \
--session-path <PATH>/casper-node/target/wasm32-unknown-unknown/release/withdraw_bid.wasm \
--session-arg="public_key:public_key='<PUBLIC_KEY_HEX>'" \
--session-arg="amount:u512='<AMOUNT_TO_WITHDRAW>'"
  1. node-address - An IP address of a peer on the network. The default port of nodes' JSON-RPC servers on Mainnet and Testnet is 7777
  2. secret-key - The file name containing the secret key of the account paying for the Deploy
  3. chain-name - The chain-name to the network where you wish to send the Deploy. For Mainnet, use casper. For Testnet, use casper-test
  4. payment-amount - The payment for the Deploy in motes estimated
  5. session-path - The path to the compiled Wasm on your computer

The withdraw_bid.wasm expects two arguments, while the third one is optional:

  1. public key: The hexadecimal public key of the account's purse to withdraw. This key must match the secret key that signs the deploy and has to match the public key of a bid in the auction contract
  2. amount: The amount being withdrawn

The command will return a deploy hash, which is needed to verify the deploy's processing results.

note

This method is more expensive than calling the withdraw_bid entrypoint in the system auction contract, which has a fixed cost of 2.5 CSPR.

Example:

Here is an example request to unbond stake using the withdraw_bid.wasm. The payment amount specified is 4 CSPR. You must modify the payment and other values in the deploy based on the network's chainspec.toml.

sudo -u casper casper-client put-deploy \
--node-address http://65.21.75.254:7777 \
--secret-key /etc/casper/validator_keys/secret_key.pem \
--chain-name casper-test \
--session-path $HOME/casper-node/target/wasm32-unknown-unknown/release/withdraw_bid.wasm \
--payment-amount 4000000000 \
--session-arg="public_key:public_key='01c297d2931fec7e22b2fb1ae3ca5afdfacc2c82ba501e8ed158eecef82b4dcdee'" \
--session-arg="amount:u512='1000000000000'"

Check the Auction Contract

Check the auction contract for updates to the bid amounts.

casper-client get-auction-info --node-address http://<HOST:PORT>

Unbonding Wait Period

To prevent long-range attacks, requests to unbond must go through a mandatory wait period, currently set to 7 eras lasting approximately 14-16 hours.

Operators Overview

Operators who wish to run node infrastructure on a Casper network, either as a standalone private network, or as part of the public network should explore this section.

Prior knowledge of Unix-based operating systems and proficiency with systemd and bash scripting are recommended. If you are unfamiliar with systemd, the Arch Linux page on systemd is a good introduction.

Operators should know the hardware requirements before running a node.

Also, the network requirements specify how to open ports and modify the network firewall to which the node is connected. This step is necessary to allow incoming connections, enabling communication among nodes.

Review the node's configuration first. Then, you can follow the node installation instructions.

TopicDescription
Node SetupHow to set up a Casper node
Becoming a ValidatorHow to join a network and become a validator
Private Network SetupHow to set up a private Casper network
MaintenanceTopics related to node maintenance

Archiving and Restoring a Database

This documentation describes processes for the compression and decompression of a Casper node database and streaming from a backup location.

Zstandard is the best method for compression speed and space for the current LMDB-based database system that the casper-node uses.

note

The values presented in this document assume that the trie-compact tool was run on a Mainnet database for compression. Contact the support team if you have questions.

Zstandard Limitations

The current DB implementation uses sparse files, which can be partially empty, thus not being processed efficiently. You can use tar as a pre-filter for stripping sparse data, as shown here, thus eliminating the need to read the full DB size and improving processing.

Zstandard Installation

To install Zstandard, run the following command:

sudo apt install zstd

Note that Zstandard version 1.4.4 is distributed with Ubuntu 20.04, while version 1.3.3 is distributed with Ubuntu 18.04. Later versions have more documentation.

Initial Warnings

You need to stop the casper-node-launcher process of the node (and, therefore, the casper-node process using the DB) before any compression or decompression into a location. Otherwise, strange things can and will occur.

Compression

Run the following basic tar command from the DB directory. For Mainnet, the directory would be /var/lib/casper/casper-node/casper, and for Testnet it would be /var/lib/casper/casper-node/casper-test.

tar -cv --sparse .

On some systems, you may get better performance if you specify the block number as an argument:

tar -b 4096 -cv --sparse .

You can then stream the result into zstd. The sections below discuss the level, thread count, and long arguments.

tar -b 4096 -cv --sparse . | zstd -[level] -cv -T[thread count] --long=31 > [path_to]/file.tar.zst

Compression level

The -[level] argument is the compression level from 1 to 19 (and 20-22 with expansion). In testing, we found 15 to be the sweet spot in compression time vs. size. We recommend lower compression if you plan to transfer the archive only once. If you are creating an archive to be downloaded by many, then the extra time for higher compression may be helpful.

Here are some examples of a Mainnet DB compression at block 741160:

LevelTime (min:sec)Size
1229:2015.8 GB
1546:1513.0 GB
1787:4213.0 GB
19197:0812.9 GB

For local backups, using 1-5 is a great compression speed-to-size trade-off.

Thread count

The -T[thread count] is the number of threads that zstd should use for compression. If running a script or command on varying machines, use T0 to allow zstd to detect the number of cores and run with the same number of threads as the detected cores. A speed-up can be obtained for machines with multiple threads per core by configuring a thread count near the number of threads. It is advisable to stay within the number of CPU threads. The recommendations in this article will use -T0.

Long-distance matching

The --long=31 argument is where we see the most space gained by the algorithm because it controls the size of the matching window in powers of 2 (2**31 is 2 GB). The downside is that it requires 2.0 GB memory during compression and decompression as it looks and rebuilds ahead. The default is 27 or 128 MB.

At compression 19, we see a 30 GB file using the default 128 MB look ahead, and a 13 GB file using 2 GB look ahead. Since all validators should have 16-32 GB of memory, we keep this at --long=31.

An important note is that decompression requires a compatible argument. Trying with a different long-distance matching value will result in an error. However, it will also return the necessary value to provide.

Summary of commands

The general command for compression is:

tar -b 4096 -cv --sparse . | zstd -15 -cv -T0 --long=31 > [path_to]/file.tar.zst

For local backups, use a lower compression level:

tar -b 4096 -cv --sparse . | zstd -5 -cv -T0 --long=31 > [path_to]/file.tar.zst

Decompression

zstd -d is the command for decompression; however, the same --long value used for compression must be specified. For all casper-node DB-related decompression, you will likely use this command:

zstd -cd --long=31 <.tar.zst file>

If --long=31 is omitted, you might see an error such as this, which also gives you the solution:

./casper.tar.zst : Decoding error (36) : Frame requires too much memory for decoding
./casper.tar.zst : Window size larger than maximum : 2147483648 > 134217728
./casper.tar.zst : Use --long=31 or --memory=2048MB

You can then use the zstd result to populate a tar -xv command. Also, create the decompressed files using sudo -u casper, because the files will be used by the casper-node. Run the following command inside an empty DB location:

zstd -cd --long=31 <.tar.zst file> | sudo -u casper tar -xv

To fix ownership, use this command:

sudo /etc/casper/node_util.py fix_permissions

Streamed Decompression

If a .tar.zst archive is hosted on a website and you will not need the file after decompressing, you can stream it into the process using curl, which can output to stdout with --output and stream binary to your terminal.

curl -s --output - <URL for tar.zstd file>

If you use the output along with the previous process, you can decompress the files from curl directly into a local directory:

curl -s --output - <tar.zst URL> | zstd -d --long=31 | sudo -u casper tar -xv

Starting a New Node with a Decompressed DB

If you are starting a node with a decompressed DB, you must tell the node to run at the protocol version of the tip of your DB. You can do this most efficiently with the node_util.py script included in the casper-node-launcher installation.

For example, if you are using a DB archive from node version 1.4.5, you would run this command:

sudo /etc/casper/node_util.py force_run_version 1_4_5

Node Maintenance

This section covers maintenance actions such as moving a node to a different location and restoring a database.

TitleDescription
Archiving and Restoring a DatabaseUsing zstd for the compression and decompression of a Casper node database and streaming from a backup location
Moving a Validating NodeWays to move a validator node to another machine

Moving a Validating Node

This guide is for active validators who want to move their node to another machine.

note

Starting with node version 1.5, operators need to move the unit files at the database level. This step allows moving the node with nearly zero rewards loss.

Swapping Keys with a Hot Backup

This method limits downtime and enables a smooth transition from the old to the new node. It keeps the node in sync with the tip of the chain.

  1. Once a node is running (current_node), create a second node (backup_node) on another machine. These two nodes will run in parallel.
  2. When the backup_node is up to date, stop the current_node.
  3. Move the unit files at the DB level using rsync. This step allows moving the node with nearly zero rewards loss.
  4. Stop the backup_node.
  5. Swap keys on the backup_node, now the new validator.
  6. Restart the backup_node.
  7. Swap keys on the current_node, now the new backup.
  8. Restart the current_node.

Preparation for swapping

  1. Let both nodes synchronize to the tip of the blockchain. Keep the current validating node running with the original validator keyset.

  2. Prepare to swap keys by following these steps:

    • Create the following folder structure on both nodes under the /etc/casper/validator_keys/ directory.
    • Create subdirectories for the current_node and backup_node.
    • Copy each node's keyset under the corresponding directories.
    /etc/casper/validator_keys/
├── public_key.pem
├── public_key_hex
├── secret_key.pem
├── current_node
│ ├── public_key.pem
│ ├── public_key_hex
│ └── secret_key.pem
└── backup_node
| ├── public_key.pem
| ├── public_key_hex
| └── secret_key.pem

This setup allows key swapping by running the sudo -u casper cp * ../ command, as shown below.

Swapping the nodes

  1. When the backup_node is up to date, stop the current_node.

  2. On the backup_node (the future validator), use rsync to move the unit files from the current_node, located in /var/lib/casper/casper-node/[NETWORK_NAME]/unit_files.

  3. On the backup_node, run these commands to stop the node, swap keys, and restart the node:

    sudo systemctl stop casper-node-launcher
    cd /etc/casper/validator_keys/current_node
    sudo -u casper cp * ../
    sudo systemctl start casper-node-launcher
  4. On the current_node, run these commands to stop the node and swap keys:

    sudo systemctl stop casper-node-launcher
    cd /etc/casper/validator_keys/backup_node
    sudo -u casper cp * ../
  5. Restart the original validator node (current_node), which is now the new backup:

    sudo systemctl start casper-node-launcher

Understanding rewards impact

After swapping, the new validator node shows no round length until an era transition occurs and will lose all rewards from the point of the switch until the end of that era. The validator is not ejected but will receive rewards starting with the next era.

tip

You could time the swap right before the era ends to minimize reward losses.

Checking file permissions

After the swap, check and fix file permissions by running the /etc/casper/node_util.py utility.

The Blockchain Specification

The blockchain specification, or chainspec, is a collection of configuration settings describing the network state at genesis and upgrades to basic system functionality (including system contracts and gas costs) occurring after genesis. This page describes each field in the chainspec, based on version 1.5.2 of the Casper node. The chainspec can and should be customized for private networks. The chainspec attributes are divided into categories based on what they are configuring.

protocol

These settings describe the active protocol version.

AttributeDescriptionMainnet Setting
versionThe Casper node protocol version.'1.5.2'
hard_resetWhen set to true, clear blocks and deploys back to the switch block (the end of the last era) just before the activation point. Used during the upgrade process to reset the network progress. In most cases, this setting should be true.true
activation_pointThe protocol version that should become active.

If it is a timestamp string, it represents the timestamp for the genesis block. This is the beginning of Era 0. By this time, a sufficient majority (> 50% + F/2 — see the finality_threshold_fraction below) of validator nodes must be running to start the blockchain. This timestamp is also used in seeding the pseudo-random number generator used in the contract runtime for computing the genesis post-state hash.

If it is an integer, it represents an era ID, meaning the protocol version becomes active at the start of this era.
9100

network

The following settings configure the networking layer.

AttributeDescriptionMainnet Setting
nameHuman readable network name for convenience. The state_root_hash of the genesis block is the true identifier. The name influences the genesis hash by contributing to seeding the pseudo-random number generator used in the contract runtime for computing the genesis post-state hash.'casper'
maximum_net_message_sizeThe maximum size of an acceptable networking message in bytes. Any message larger than this will be rejected at the networking level.25_165_824

core

These settings manage the core protocol behavior.

AttributeDescriptionMainnet Setting
era_durationEra duration.'120min'
minimum_era_heightMinimum number of blocks per era. An era will take longer than era_duration if that is necessary to reach the minimum height.20
minimum_block_timeMinimum difference between a block's and its child's timestamp.'16384ms'
validator_slotsNumber of slots available in the validator auction.100
finality_threshold_fractionA number between 0 and 1 representing the fault tolerance threshold as a fraction used by the internal finalizer.
It is the fraction of validators that would need to equivocate to make two honest nodes see two conflicting blocks as finalized.
Let's say this value is F. A higher value F makes it safer to rely on finalized blocks. It also makes it more difficult to finalize blocks, however, and requires strictly more than (F + 1)/2 validators to be working correctly.
[1, 3]
start_protocol_version_with_strict
_finality_signatures_required
Protocol version from which nodes are required to hold strict finality signatures.'1.5.0'
legacy_required_finalityThe finality required for legacy blocks. Options are 'Strict', 'Weak', and 'Any'.
Used to determine finality sufficiency for new joiners syncing blocks created in a protocol version before the start protocol version with strict finality signatures.
'Strict'
auction_delayNumber of eras before an auction defines the set of validators. If a validator bonds with a sufficient bid in era N, it will be a validator in era N + auction_delay + 1.1
locked_funds_periodThe period after genesis during which a genesis validator's bid is locked.'90days'
vesting_schedule_periodThe period in which the genesis validator's bid is released over time after it is unlocked.'13 weeks'
unbonding_delayDefault number of eras that need to pass to be able to withdraw unbonded funds.7
round_seigniorage_rateRound seigniorage rate represented as a fraction of the total supply.
- Annual issuance: 8%.
- Minimum block time: 2^15 milliseconds.
- Ticks per year: 31536000000.

(1+0.08)^((2^15)/31536000000)-1 is expressed as a fractional number below in Python:
Fraction((1 + 0.08)**((2**15)/31536000000) - 1).limit_denominator(1000000000)
[7, 87535408]
max_associated_keysMaximum number of associated keys for a single account.100
max_runtime_call_stack_heightMaximum height of the contract runtime call stack.12
minimum_delegation_amountMinimum allowed delegation amount in motes.500_000_000_000
prune_batch_sizeGlobal state prune batch size for tip pruning in version 1.4.15. Possible values:
- 0 when the feature is OFF
- Integer if the feature is ON, representing the number of eras to process per block.
0
strict_argument_checkingEnables strict arguments checking when calling a contract; i.e., all non-optional args are provided and they are of the correct CLType.false
simultaneous_peer_requestsNumber of simultaneous peer requests.5
consensus_protocolThe consensus protocol to use. Options are 'Zug' or 'Highway'.'Highway'
max_delegators_per_validatorThe maximum amount of delegators per validator. If the value is 0, there is no maximum capacity.1200

highway

These settings configure the Highway Consensus protocol.

AttributeDescriptionMainnet Setting
maximum_round_lengthHighway dynamically chooses its round length between minimum_block_time and maximum_round_length.'132seconds'
reduced_reward_multiplierThe factor by which rewards for a round are multiplied if the greatest summit has ≤50% quorum, i.e., no finality. Expressed as a fraction (1/5 by default on Mainnet).[1, 5]

deploys

These settings manage deploys and their lifecycle.

AttributeDescriptionMainnet Setting
max_payment_costThe maximum number of motes allowed to be spent during payment. 0 means unlimited.'0'
max_ttlThe duration after the deploy timestamp during which the deploy can be included in a block.'18hours'
max_dependenciesThe maximum number of other deploys a deploy can depend on (requiring them to have been executed before it can execute).10
max_block_sizeMaximum block size in bytes, including deploys contained by the block. 0 means unlimited.10_485_760
max_deploy_sizeMaximum deploy size in bytes. Size is of the deploy when serialized via ToBytes.1_048_576
block_max_deploy_countThe maximum number of non-transfer deploys permitted in a single block.50
block_max_transfer_countThe maximum number of Wasm-less transfer deploys permitted in a single block.1250
block_max_approval_countThe maximum number of approvals permitted in a single block.2600
block_gas_limitThe upper limit of the total gas of all deploys in a block.4_000_000_000_000
payment_args_max_lengthThe limit of length of serialized payment code arguments.1024
session_args_max_lengthThe limit of length of serialized session code arguments.1024
native_transfer_minimum_motesThe minimum amount in motes for a valid native transfer.2_500_000_000

wasm

The following are Wasm-related settings.

AttributeDescriptionMainnet Setting
max_memoryAmount of free memory (in 64 kB pages) each contract can use for its stack.64
max_stack_heightMax stack height (native WebAssembly stack limiter).500

wasm.storage_costs

These settings manage Wasm storage costs.

AttributeDescriptionMainnet Setting
gas_per_byteGas charged per byte stored in global state.630_000

wasm.opcode_costs

The following settings manage the cost table for Wasm opcodes.

AttributeDescriptionMainnet Setting
bitBit operations multiplier.300
addArithmetic add operations multiplier.210
mulMul operations multiplier.240
divDiv operations multiplier.320
loadMemory load operation multiplier.2_500
storeMemory store operation multiplier.4_700
constConst store operation multiplier.110
localLocal operations multiplier.390
globalGlobal operations multiplier.390
integer_comparisonInteger operations multiplier.250
conversionConversion operations multiplier.420
unreachableUnreachable operation multiplier.270
nopNop operation multiplier.200
current_memoryGet the current memory operation multiplier.290
grow_memoryGrow memory cost per page (64 kB).240_000

wasm.opcode_costs.control_flow

These settings manage costs for control flow operations.

AttributeDescriptionMainnet Setting
blockCost for block opcode.440
loopCost for loop opcode.440
ifCost for if opcode.440
elseCost for else opcode.440
endCost for end opcode.440
brCost for br opcode.35_000
br_ifCost for br_if opcode.35_000
returnCost for return opcode.440
selectCost for select opcode.440
callCost for call opcode.68_000
call_indirectCost for call_indirect opcode.68_000
dropCost for drop opcode.440

wasm.opcode_costs.control_flow.br_table

The following settings manage br_table Wasm opcodes.

AttributeDescriptionMainnet Setting
costFixed cost per br_table opcode.35_000
size_multiplierSize of target labels in the br_table opcode will be multiplied by size_multiplier.100

wasm.host_function_costs

The following settings specify costs for low-level bindings for host-side ("external") functions. More documentation and host function declarations are located in smart_contracts/contract/src/ext_ffi.rs.

  • add = { cost = 5_800, arguments = [0, 0, 0, 0] }
  • add_associated_key = { cost = 9_000, arguments = [0, 0, 0] }
  • add_contract_version = { cost = 200, arguments = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }
  • blake2b = { cost = 200, arguments = [0, 0, 0, 0] }
  • call_contract = { cost = 4_500, arguments = [0, 0, 0, 0, 0, 420, 0] }
  • call_versioned_contract = { cost = 4_500, arguments = [0, 0, 0, 0, 0, 0, 0, 420, 0] }
  • create_contract_package_at_hash = { cost = 200, arguments = [0, 0] }
  • create_contract_user_group = { cost = 200, arguments = [0, 0, 0, 0, 0, 0, 0, 0] }
  • create_purse = { cost = 2_500_000_000, arguments = [0, 0] }
  • disable_contract_version = { cost = 200, arguments = [0, 0, 0, 0] }
  • get_balance = { cost = 3_800, arguments = [0, 0, 0] }
  • get_blocktime = { cost = 330, arguments = [0] }
  • get_caller = { cost = 380, arguments = [0] }
  • get_key = { cost = 2_000, arguments = [0, 440, 0, 0, 0] }
  • get_main_purse = { cost = 1_300, arguments = [0] }
  • get_named_arg = { cost = 200, arguments = [0, 0, 0, 0] }
  • get_named_arg_size = { cost = 200, arguments = [0, 0, 0] }
  • get_phase = { cost = 710, arguments = [0] }
  • get_system_contract = { cost = 1_100, arguments = [0, 0, 0] }
  • has_key = { cost = 1_500, arguments = [0, 840] }
  • is_valid_uref = { cost = 760, arguments = [0, 0] }
  • load_named_keys = { cost = 42_000, arguments = [0, 0] }
  • new_uref = { cost = 17_000, arguments = [0, 0, 590] }
  • random_bytes = { cost = 200, arguments = [0, 0] }
  • print = { cost = 20_000, arguments = [0, 4_600] }
  • provision_contract_user_group_uref = { cost = 200, arguments = [0, 0, 0, 0, 0] }
  • put_key = { cost = 38_000, arguments = [0, 1_100, 0, 0] }
  • read_host_buffer = { cost = 3_500, arguments = [0, 310, 0] }
  • read_value = { cost = 6_000, arguments = [0, 0, 0] }
  • read_value_local = { cost = 5_500, arguments = [0, 590, 0] }
  • remove_associated_key = { cost = 4_200, arguments = [0, 0] }
  • remove_contract_user_group = { cost = 200, arguments = [0, 0, 0, 0] }
  • remove_contract_user_group_urefs = { cost = 200, arguments = [0, 0, 0, 0, 0, 0] }
  • remove_key = { cost = 61_000, arguments = [0, 3_200] }
  • ret = { cost = 23_000, arguments = [0, 420_000] }
  • revert = { cost = 500, arguments = [0] }
  • set_action_threshold = { cost = 74_000, arguments = [0, 0] }
  • transfer_from_purse_to_account = { cost = 2_500_000_000, arguments = [0, 0, 0, 0, 0, 0, 0, 0, 0] }
  • transfer_from_purse_to_purse = { cost = 82_000, arguments = [0, 0, 0, 0, 0, 0, 0, 0] }
  • transfer_to_account = { cost = 2_500_000_000, arguments = [0, 0, 0, 0, 0, 0, 0] }
  • update_associated_key = { cost = 4_200, arguments = [0, 0, 0] }
  • write = { cost = 14_000, arguments = [0, 0, 0, 980] }
  • write_local = { cost = 9_500, arguments = [0, 1_800, 0, 520] }

system_costs

The following settings manage protocol operating costs.

AttributeDescriptionMainnet Setting
wasmless_transfer_costDefault gas cost for a wasmless transfer.100_000_000

system_costs.auction_costs

These settings manage the costs of calling the auction system contract entrypoints.

AttributeDescriptionMainnet Setting
get_era_validatorsCost of calling the get_era_validators entrypoint.10_000
read_seigniorage_recipientsCost of calling the read_seigniorage_recipients entrypoint.10_000
add_bidCost of calling the add_bid entrypoint.2_500_000_000
withdraw_bidCost of calling the withdraw_bid entrypoint.2_500_000_000
delegateCost of calling the delegate entrypoint.2_500_000_000
undelegateCost of calling the undelegate entrypoint.2_500_000_000
run_auctionCost of calling the run_auction entrypoint.10_000
slashCost of calling the slash entrypoint.10_000
distributeCost of calling the distribute entrypoint.10_000
withdraw_delegator_rewardCost of calling the withdraw_delegator_reward entrypoint.10_000
withdraw_validator_rewardCost of calling the withdraw_validator_reward entrypoint.10_000
read_era_idCost of calling the read_era_id entrypoint.10_000
activate_bidCost of calling the activate_bid entrypoint.10_000
redelegateCost of calling the redelegate entrypoint.2_500_000_000

system_costs.mint_costs

These settings manage the costs of calling the mint system contract entrypoints.

AttributeDescriptionMainnet Setting
mintCost of calling the mint entrypoint.2_500_000_000
reduce_total_supplyCost of calling the reduce_total_supply entrypoint.10_000
createCost of calling the create entrypoint.2_500_000_000
balanceCost of calling the balance entrypoint.10_000
transferCost of calling the transfer entrypoint.10_000
read_base_round_rewardCost of calling the read_base_round_reward entrypoint.10_000
mint_into_existing_purseCost of calling the mint_into_existing_purse entrypoint.2_500_000_000

system_costs.handle_payment_costs

These settings manage the costs of calling entrypoints on the handle_payment system contract.

AttributeDescriptionMainnet Setting
get_payment_purseCost of calling the get_payment_purse entrypoint.10_000
set_refund_purseCost of calling the set_refund_purse entrypoint.10_000
get_refund_purseCost of calling the get_refund_purse entrypoint.10_000
finalize_paymentCost of calling the finalize_payment entrypoint.10_000

system_costs.standard_payment_costs

These settings manage the costs of calling entrypoints on the standard_payment system contract.

AttributeDescriptionMainnet Setting
payCost of calling the pay entrypoint and sending an amount to a payment purse.10_000

Setting Up a Private Casper Network

Casper private networks operate in a similar way to the Casper public network. The significant difference in private networks is a closed validator set and having administrator account(s) which can control regular accounts. Hence, there are specific configurations when setting up the genesis block and administrator accounts. Besides the main configuration options that the Casper platform provides, each customer may add other configuration options when setting up a private network.

Contents

  1. Prerequisites

  2. Setting up a Validator Node

  3. Setting up the Directory

  4. Configuring the Genesis Block

  5. Configuring the Administrator Accounts

  6. Starting the Casper Node

  7. Testing the Private Network

  8. Setting up a Block Explorer

Prerequisites

Follow these guides to set up the required environment and user accounts.

Step 1. Setting up a Validator Node

A Casper node is a physical or virtual device participating in a Casper network. You need to set up several validator nodes on your private network. An operator who has won an auction bid will be a validator for the private network.

Use the below guides to set up and manage validator nodes.

  • Casper node setup - GitHub guide: A guide to configuring a system with the new Rust node to operate within a network.
  • Basic node setup tutorial: A guide on using the casper-node-launcher, generating directories and files needed for running casper-node versions and performing upgrades, generating keys, and setting up the configuration file for nodes.
  • Set up Mainnet and Testnet validator nodes: A set of guides for Mainnet and Testnet node-operators on setting up and configuring their Casper network validator nodes.

Use these FAQ collections for tips and details for validators.

Step 2. Setting up the Directory

Use these guides to set up your private network directories. You will find several main directories dedicated to different purposes.

  • Go through the file location section to understand how directories are created and managed in a Casper private network.
  • Refer to the setting up a new network guide to identify the required configuration files to set up a genesis block.

Step 3. Configuring the Genesis Block

A Casper private network contains a different set of configurations when compared to the public network. The chainspec.toml file contains the required configurations for the genesis process in a private network.

You should add the configuration options below to the chainspec.toml file inside the private network directory.

Unrestricted transfers configuration

This option disables unrestricted transfers between regular account purses. A regular account user cannot do a fund transfer when this attribute is set to false. Only administrators can transfer tokens freely between users and other administrators.

[core]
allow_unrestricted_transfers = false

In contrast, users in the public network can freely transfer funds to different accounts.

A Casper private network doesn't support the minting process. Only admininstrator accounts can maintain funds. This is enabled by configuring these options:
[core]
allow_unrestricted_transfers = false
compute_rewards = false
allow_auction_bids = false
refund_handling = { type = "refund", refund_ratio = [1, 1] }
fee_handling = { type = "accumulate" }
administrators = ["ADMIN_PUBLIC_KEY"]

Refund handling configuration

This option manages the refund behavior at the finalization of a deploy execution. It changes the way the Wasm execution fees are distributed. After each deploy execution, the network calculates the amount of gas spent for the execution and manages to refund any remaining tokens to the user.

A refund_ratio is specified as a proper fraction (the numerator must be lower or equal to the denominator). In the example below, the refund_ratio is 1:1. If 2.5 CSPR is paid upfront and the gas fee is 1 CSPR, 1.5 CSPR will be given back to the user.

[core]
refund_handling = { type = "refund", refund_ratio = [1, 1] }

After deducting the gas fee, the distribution of the remaining payment amount is handled based on the fee_handling configuration.

The default configuration for a public chain, including the Casper Mainet, looks like this:

[core]
refund_handling = { type = "refund", refund_ratio = [0, 100] }

The refund variant with refund_ratio of [0, 100] means that 0% is given back to the user after deducting gas fees. In other words, if a user paid 2.5 CSPR and the gas fee is 1 CSPR, the user will not get the remaining 1.5 CSPR in return.

Fee handling configuration

This option defines how to distribute the fees after refunds are handled. While refund handling defines the amount we pay back after a transaction, fee handling defines the methods of fee distribution after a refund is performed.

Set up the configuration as below:

[core]
fee_handling = { type = "pay_to_proposer" }

The fee_handling configuration has three variations:

  • pay_to_proposer: The rest of the payment amount after deducing the gas fee from a refund is paid to the block's proposer.
  • burn: The tokens paid are burned, and the total supply is reduced.
  • accumulate: The funds are transferred to a special accumulation purse. Here, the accumulation purse is owned by a handle payment system contract, and the amount is distributed among all the administrators defined at the end of a switch block. The fees are paid to the purse owned by the handle payment contract, and no tokens are transferred to the proposer when this configuration is enabled.

Auction behavior configuration

A private network requires to have a fixed set of validators. This configuration restricts the addition of new validators to the private network. Hence, you are not allowed to bid new entries into the validator set.

Use the configuration below to limit the auction validators:

[core]
allow_auction_bids = false

Other configurations related to the auction:

  • allow_auction_bids - if this option is set to false then add_bid and delegate options are disabled. It also disables adding new validators to the system. Invoking those entry points leads to an AuctionBidsDisabled error.
  • core.compute_rewards - if this option is set to false, then all the rewards on a switch block will be set to 0. The auction contract wouldn't process rewards distribution that would increase validator bids.

In a public network, allow_auction_bid is set to true, which allows bidding for new entries and validator nodes.

Step 4. Configuring the Administrator Accounts

An administrator is mandatory for a private network since it manages all the other validator accounts. There should be at least one administrator account configured within a network to operate it as a private network. You can create new administrators and rotate the validator set in a single configuration update. The operator must first ensure the global_state.toml file contains new administrators. The validator set is updated after if an administrator is also a validator. Also, only purses of administrator accounts can hold and distribute token balances.

Configuring administrator accounts

Use this configuration option in the chainspec.toml to add administrator accounts to the private network:

[core]
administrators = ["NEW_ACCOUNT_PUBLIC_KEY"]

Note: Regular accounts are not allowed to manage their associated keys on a private network.

Generating new administrator accounts

Use the command below to generate new administrator accounts in your private network. This generates the contents of a global_state.toml with the entries required to create new administrator accounts at the upgrade point.

global-state-update-gen \
generate-admins --data-dir $DATA_DIR/global_state \
--state-hash $STATE_ROOT_HASH \
--admin $PUBLIC_KEY_HEX, $BALANCE
  • NEW_PUBLIC_KEY - Public key of the administrator in a hex format.
  • NEW_BALANCE - Balance for the administrator’s main purse.
  • DATA_DIR - Path to the global state directory.
  • STATE_ROOT_HASH - State root hash, taken from the latest block before an upgrade.

Managing accounts and smart contracts

Only administrators have permission to control accounts and manage smart contracts in a private network. An example implementation can be found in Casper node's private chain control management file. This is not an existing contract. You can use the existing client contracts as an administrator to perform actions as a user. This is done by sending a deploy under a regular user's public key but signed using the administrator's secret key.

Use this command to generate these contracts:

make build-contracts-rs

Only the administrator can use the related Wasm to send the deploy to the network and then use it to manage, enable, and disable contracts. This is achieved through entry points that handle enabling and disabling options for account and smart contracts:

  • To disable a contract: Execute the disable_contract.wasm with contract_hashand contract_package_hash as parameters.
  • To enable a contract: Execute the enable_contract.wasm with contract_hashand contract_package_hash as parameters.
  • To disable an account: Execute set_action_thresholds.wasm with argument deploy_threshold:u8='255' and key_management_threshold:u8='255'.
  • To enable an account: Execute set_action_thresholds.wasm with deploy_threshold:u8='1' set to 1 and key_management_threshold:u8='0'.

Step 5. Starting the Casper Node

After preparing the administrator accounts and validator nodes, you should start and run the Casper node to see the changes. Use this command to start the node:

sudo systemctl start casper-node-launcher

Refer to the Casper node setup GitHub guide to know more details about configuring a new node to operate within a network.

Additionally, refer to the casper-node-launcher to check whether the installed node binaries match the installed configurations by comparing the version numbers.

Step 6. Rotating the Validator Accounts

You need to go through setting up a validator node guide before starting this section.

To rotate the validators set, you must perform a network upgrade using a global_state.toml with new entries generated by the global-state-update-gen command.

When rotating validators manually, you will need to do so after the start of a new era. This allows you to obtain the state root hash from the final block in an era, known as the switch block.

After acquiring the state root hash from the switch block, you must stop the network. The following command allows you to use the acquired state root hash to generate a new global_state.toml.


global-state-update-gen validators \
--data-dir $DATA_DIR/global_state \
--state-hash $STATE_ROOT_HASH \
–-validator $PUBLIC_KEY_HEX,$STAKE \
–-validator $PUBLIC_KEY_HEX,$STAKE

Each use of the --validator parameter designates a validator for the next era. Only validators added using this parameter will be included in the new era, hence removing a validator only requires you to not add them with this parameter.

After designating the next era's validators, you must set the chainspec activation point and last_emergency_restart to X, where X is equal to the new era after the switch block from above. Finally, set hard_reset = true. This makes the network revert to the end of the previous era when restarted with the upgrade.

For example, to rotate the validators in era 10, one would need to wait for the end of era 9. After acquiring the state root hash from the final block of era 9, you would stop the network, run global-state-update-gen, set the activaction point and last_emergency_restart to 10 and hard_reset to true.

You can now stage the upgrade by copying the chainspecs, configs and binaries where they should be while the network is still down. Once these are in place, you can restart the network with rotated validators.

note

Please make sure you are running this tool as the same user that owns $DATA_DIR. Otherwise, you may receive a permission denied error.

You can find more details on enabling new validators in the joining a running network guide. The guide explains how to join the network and provide additional security to the system.

Step 7. Testing the Private Network

We will describe the testing flow using an example customer and the configuration below. These options are relative to this example customer.

Sample configuration files

Here are sample configurations that can be adapted for testing:

Specifying IP addresses

Here is an example set of IP addresses in use:

http://18.224.190.213:7777
http://18.188.11.97:7777
http://18.188.206.170:7777
http://18.116.201.114:7777

Setting up the node

Set up the node address, chain name, and the administrator's secret key.

export NODE_ADDR=http://18.224.190.213:7777
export CHAIN_NAME="private-test"

This testing example will also use an alice/secret_key.pem file, a secret key generated through the keys generation process. Alice is a regular user in this testing example.

Network access control

With a default configuration each node generates a self-signed certificate to encrypt peer-to-peer communication. This means any person can join an existing network, and sync with the network, which in private chains may not be allowed.

To restrict access for new nodes joining an existing private chain network, the node software supports loading signed client certificates by a certificate authority (CA).

[network.identity]
tls_certificate = "local_node_cert.pem"
secret_key = "local_node.pem"
ca_certificate = "ca_cert.pem"
  • tls_certificate is the certificate signed by a ca_cert.pem.
  • secret_key refers to a secret key that should be unique to a specific node in the network. All peer-to-peer communication coming from this node will be signed by this key.
  • ca_certificate is the network CA that should be the same on each of the nodes.

To set up CA and sign client certificates for a network here are the steps to follow using an openssl command line:

# Recommended EC curve algorithm to use
export CURVE="secp521r1"

# Generate secret key for CA and save it to ca_key.pem
openssl ecparam -out ca_key.pem -name $CURVE -genkey
# Create ca_cert.pem signed by ca_key.pem
openssl req -new -x509 -days 3650 -extensions v3_ca -key ca_key.pem -out ca_cert.pem

# Generate secret key for a node and a certificate signed by the CA
openssl ecparam -out node_1.pem -name $CURVE -genkey
openssl req -new -key node_1.pem -out node_1.csr -sha256
openssl x509 -req -days 3650 -CA ca_cert.pem -CAkey ca_key.pem -CAcreateserial -in node_1.csr -out node_1_cert.pem

And then configure the node with the following settings:

[network.identity]
tls_certificate = "node_1_cert.pem"
secret_key = "node_1.pem"
ca_certificate = "ca_cert.pem"

Every node in the private chain network has to be configured with the same CA certificate, and each tls_certificate and secret_key pair has to be signed by it. Any node trying to join with a certificate signed by an incorrect CA ends up with the following log message:

2022-09-01T12:08:53.031417Z DEBUG init:incoming{; peer_addr=127.0.0.1:50998}: [casper_node::components::small_network small_network.rs:501] incoming connection failed early; err=TLS validation error of peer certificate: the certificate is not signed by provided certificate authority

Keep in mind that for security reasons ca_key.pem should be stored securely and never present on each of participating machines.

Funding Alice's account

The following command transfers tokens to Alice's main purse.

casper-client \
transfer \
-n $NODE_ADDR \
--chain-name $CHAIN_NAME \
--secret-key admin/secret_key.pem \
--session-account=$(<admin/public_key_hex) \
--target-account=$(<alice/public_key_hex) \
--amount=100000000000 \
--payment-amount=3000000000 \
--transfer-id=123

To check the account information, use this command:

casper-client get-account-info -n $NODE_ADDR
--public-key alice/public_key.pem

Adding a bid as Alice

The following command attempts to add an auction bid on the network. It should return ApiError::AuctionError(AuctionBidsDisabled) [64559].

tip

All payment amounts in these examples must be adjusted based on the network chainspec.

casper-client \
put-deploy \
-n $NODE_ADDR \
--chain-name $CHAIN_NAME \
--secret-key alice/secret_key.pem \
--session-path add_bid.wasm \
--payment-amount 5000000000 \
--session-arg "public_key:public_key='$(<alice/public_key_hex)'" \
--session-arg "amount:u512='10000'" \
--session-arg "delegation_rate:u8='5'"

# Error: ApiError::AuctionError(AuctionBidsDisabled) [64559]"

We should get a similar error for the delegate entry point.

Disabling Alice's account

The following command disables Alice's account. In this case, executing deploys with Alice's account will not be successful.

casper-client \
put-deploy \
-n $NODE_ADDR \
--chain-name $CHAIN_NAME \
--secret-key admin/secret_key.pem \
--session-account=alice/public_key_hex
--session-path set_action_thresholds.wasm \
--payment-amount=2500000000 \
--session-arg "key_management_threshold:u8='255'" \
--session-arg "deploy_threshold:u8='255'"

Enabling Alice's account

The following command enables Alice's account. In this case, executing deploys with Alice's account will be successful.

casper-client \
put-deploy \
-n $NODE_ADDR \
--chain-name $CHAIN_NAME \
--secret-key admin/secret_key.pem \
--session-account=alice/public_key_hex
--session-path set_action_thresholds.wasm \
--payment-amount=2500000000 \
--session-arg "key_management_threshold:u8='0'" \
--session-arg "deploy_threshold:u8='1'"

Enabling a contract

The following command enables a contract using its hash.

casper-client \
put-deploy \
-n $NODE_ADDR \
--chain-name $CHAIN_NAME \
--secret-key admin/secret_key.pem \
--session-account=$(<alice/public_key_hex) \
--session-path enable_contract.wasm \
--payment-amount 3000000000 \
--session-arg "contract_package_hash:account_hash='account-hash-$CONTRACT_PACKAGE_HASH'" \
--session-arg "contract_hash:account_hash='account-hash-$CONTRACT_HASH'"

Disabling a contract

The following command disables a contract using its hash. Executing this contract using CONTRACT_HASH again should fail.

casper-client \
put-deploy \
-n $NODE_ADDR \
--chain-name $CHAIN_NAME \
--secret-key admin/secret_key.pem \
--session-account=$(<alice/public_key_hex) \
--session-path disable_contract.wasm \
--payment-amount 3000000000 \
--session-arg "contract_package_hash:account_hash='account-hash-$CONTRACT_PACKAGE_HASH'" \
--session-arg "contract_hash:account_hash='account-hash-$CONTRACT_HASH'"

Alice needs a container access key for the contract package in her named keys.

Verifying seigniorage allocations

Seigniorage allocations should be zero at each switch block. This is the related configuration:

[core]
compute_rewards = false

Validator stakes should not increase on each switch block. Run this command to verify this:

casper-client get-era-info -n $NODE_ADDR -b 153

The total supply shouldn't increase, and the validator's stakes should remain the same.

Operating guide

Some configuration options such as allow_auction_bids require a private chain operator to perform specific tasks manually through a network upgrade with chainspec and contents of global_state.toml file generated by a provided tool global-state-update-gen.

You can find this tool by either downloading a package or by installing it manually from the sources:

$ cargo install --git https://github.com/casper-network/casper-node/ --tag private-1.4.6 global-state-update-gen
$ global-state-update-gen --help
Global State Update Generator 0.2.0
Generates a global state update file based on the supplied parameters

USAGE:
global-state-update-gen [SUBCOMMAND]

FLAGS:
-h, --help Prints help information
-V, --version Prints version information

SUBCOMMANDS:
balances Generates an update changing account balances
generate-admins Generates entries to create new admin accounts on a private chain
help Prints this message or the help of the given subcommand(s)
system-contract-registry Generates an update creating the system contract registry
validators Generates an update changing the validators set

The standard output of running commands listed above is the content of a global_state.toml file, which contains a list of direct global state modifications.

Example output of running a generate-admins subcommand:

[[entries]]
key = "balance-97bbcc2425b3eda5149a893c6180b62f1472d5143bb1450d01c8e1e96be09f13"
value = "AAIAAAABCgg="

[[entries]]
key = "uref-97bbcc2425b3eda5149a893c6180b62f1472d5143bb1450d01c8e1e96be09f13-007"
value = "AAAAAAAJ"

[[entries]]
key = "account-hash-ac2f4caa3e3ce1cd1dfb3d089854020b18a50cac49977d0a4c873c4d3d5a2409"
value = "AawvTKo+POHNHfs9CJhUAgsYpQysSZd9CkyHPE09WiQJAAAAAJe7zCQls+2lFJqJPGGAti8UctUUO7FFDQHI4elr4J8TBwEAAACsL0yqPjzhzR37PQiYVAILGKUMrEmXfQpMhzxNPVokCQEBAQ=="

# total supply increases from 200000000000000000 to 200000000000000010
[[entries]]
key = "uref-f8475fd4125484be39a0793530f09a29d220ffda8e48387b3d2194ddfc22894e-007"
value = "AAkAAAAICgAUu/CKxgII"

Currently, this tool outputs contents into standard output. You should redirect standard output to a file named global_state.toml and place this file in the same directory as chainspec.toml before performing a network upgrade.

$ global-state-update-gen generate-admins --data-dir $DATA_DIR --state-hash $STATE_HASH --admin NEW_PUBLIC_KEY,BALANCE >> global_state.toml

By using >> shell redirection you will always append contents to existing file without overwriting it. This is helpful when you need to chain multiple operations in a single upgrade.

Common options:

  • --data-dir path to a global state directory where data.lmdb can be found
  • --state-hash is the state root hash at the latest block. You should use the client to obtain the most recent state root hash to generate the global_state.toml.

Rotating validators

The following command rotates the validator set. Perform a network upgrade with a global_state.toml with the new entries generated by the global-state-update-gen command.

global-state-update-gen validators \
--data-dir $DATA_DIR \
--state-hash $STATE_ROOT_HASH \
--validator NEW_PUBLIC_KEY,NEW_STAKE \
--validator NEW_PUBLIC_KEY2,NEW_STAKE2

Adding new administrators

The following command produces the administrator content in the global_state.toml file.

global-state-update-gen generate-admins --admin NEW_PUBLIC_KEY,NEW_BALANCE --data-dir $DATA_DIR --state-hash $STATE_ROOT_HASH

Remember that new administrators can be created, and the validator set can also be rotated in a single update.

The chainspec.toml file should contain the following entries that include new administrators as well as existing ones for an upgrade:

[core]
administrators = ["NEW_PUBLIC_KEY"]

After this step, the private network would be ready for use.

Setting up a Block Explorer

Private and hybrid blockchains can find information on how to set up and operate our free version of a block explorer here.

The Genesis Block

The Casper node software creates a genesis block from the following input files:

  • chainspec.toml
  • accounts.toml

chainspec.toml

A version of the chainspec is downloaded by the pull_casper_node_version.sh script installed with the casper-node-launcher debian package. This script pulls the chainspec.toml file from the appropriate path defined in the network config file used (casper.conf for MainNet and casper-test.conf for TestNet).

The production version of the file from which this is based on can be found at casper-node/resources/production/chainspec.toml in the code base. To create a custom network, this file can be updated as desired. Any changes to this file will result in a different genesis hash. Refer to this page for detailed documentation on each of the variables in the file.

accounts.toml

This file contains the genesis validator set information, starting accounts and associated balances and bond amounts.

If an account is not bonded at genesis, specify a 0 for the bond amount.

Similar to the chainspec.toml, this is pulled from the appropriate path defined in the network config file used.

Setting up Private Networks

Some projects may require a private Casper network or a hybrid setup involving a private and public Casper network. This section covers the requirements for creating a private network.

TitleDescription
The Genesis BlockFiles needed to create a genesis block
The Chain SpecificationConfiguration settings describing the network state
Setting up a Private Casper NetworkA step-by-step guide to establishing and configuring a private Casper network
Staging Files for a New NetworkA guide to hosting protocol files for a new Casper network

Staging Files for a New Network

info

Staging files is not needed for already established running networks.

Only use these instructions if you are creating a new Casper network and hosting protocol files for this network.

Hosting Server

Files for staging protocol versions are hosted on a typical HTTP(S) server.

Scripts included with the casper-node-launcher have network configurations for Mainnet and Testnet. These scripts point to the server hosting files and network name.

Since a given server can be used for multiple networks, a network named directory is used to hold files for that network.

This is a description of Mainnet protocol version hosting (with network name: casper).

genesis.casperlab.io is the web server URL with the following directory structure:

  • casper
    • protocol_versions - File listing active protocol versions so scripts know what directories to use
    • 1_0_0 - Genesis protocol version
      • config.tar.gz - Configuration files to be expanded into /etc/casper/1_0_0
      • bin.tar.gz - Binary files to be expanded into /var/lib/casper/bin/1_0_0
    • 1_1_0 - First upgrade
      • config.tar.gz - Configuration files to be expanded into /etc/casper/1_1_0
      • bin.tar.gz - Binary files to be expanded into /var/lib/casper/bin/1_1_0
    • ... (skipping many other protocol versions)
    • 1_4_6 - A later upgrade
      • config.tar.gz - Configuration files to be expanded into /etc/casper/1_4_6
      • bin.tar.gz - Binary files to be expanded into /var/lib/casper/bin/1_4_6

More on protocol_versions

At the root of the hosting server directory for a given network, a protocol_versions file exists. This holds the valid protocol versions for a network.

We can look at this manually on Mainnet using curl. As of writing this, 1.4.6 is the latest version and the contents of this file will change.


$ curl -s genesis.casperlabs.io/casper/protocol_versions
1_0_0
1_1_0
1_1_2
1_2_0
1_2_1
1_3_2
1_3_4
1_4_1
1_4_3
1_4_4
1_4_5
1_4_6

We should find bin.tar.gz and config.tar.gz in those directories under casper.

Protocol Version

The protocol version of a network is not related to the casper-node version. In Mainnet, these have often been the same. However, with a new network, you would use the latest casper-node version for your 1.0.0 protocol.

Network Configuration File

When the casper-node-launcher package is installed, both casper.conf and casper-test.conf are installed in /etc/casper/network_configs. Once a valid config file for a new network is copied to this location, all commands with node_util.py will work as they do on existing networks.

By convention, we name the config file the same as the network. So Mainnet has a network name of casper and we use casper.conf for the config file.

For a new network using server casper.mydomain.com to host files for our-network network, we would have a our-network.conf file that looks like this:

SOURCE_URL=casper.mydomain.com
NETWORK_NAME=our-network

Host this our-network.conf in the root of casper.mydomain.com/our-network at the same level as protocol_versions.

This allows any node which wants to use the new network to run the following to install this configuration:

cd /etc/casper/network_configs
sudo -u casper curl -JLO casper.mydomain.com/our-network/our-network.conf

Any command needing a network config from node_util.py can use our-network.conf.

Staging protocol versions for a new node with this network or staging an upcoming upgrade would just need this command:

sudo -u casper /etc/casper/node_util.py stage_protocols our-network.conf

Setup Configuration Files

For a network to be started, we to build the configuration files for a certain genesis time and with nodes that will be running. These files need to be configured in advanced, so a genesis time should be selected that allows packaging the files, loading onto nodes and starting nodes prior to the genesis time.

chainspec.toml

The chainspec.toml file is configuration for the network and must be exactly the same on all nodes.

The name for a network is specified network.name.

Each protocol will have a version and activation_point. At genesis this is a date and time in format shown below. For future upgrades it would be an integer of the era_id for activation of the upgrade.

[protocol]
version = '1.0.0'
activation_point = '2022-08-01T10:00:00Z'

[network]
name = 'mynetwork'

config-example.toml

The config-example.toml is used to generate config.toml for a protocol after the node's IP is inserted. The public_address is auto-detected with node_util.py stage_protocols. If using a NAT environment, the public IP can be specified with the --ip argument.

This file should have known_addresses added that are relevant to the network. Nodes that will be genesis validators are added to this list in the form:

[network]
known_addresses = ['<ip 1>:35000','<ip 2>:35000','<ip 3>:35000']

The config.toml can be setup to customized fields for a given node. config-example.toml is a default configuration.

Staging a Protocol Version

For the initial genesis protocol version or future upgrade protocol versions, you will typically use prebuilt and tested bin.tar.gz that have been tested and staged for existing networks. The config.tar.gz file must be customized for the specific network with a network name, protocol version and activation point at the very least.

These archives should be created with no directory information stored. This is done by using tar in the same directory as the files.

mkdir config
cd config
mv [source of chainspec.toml] ./chainspec.toml
mv [source of config-example.toml] ./config-example.toml
tar -czvf ../config.tar.gz .

You can test what was compressed with untar'ing the file.

mkdir conftest
cd conftest
tar -xzvf ../config.tar.gz .

This will expand files for verification.

For custom casper-node builds, the minimum contents of bin.tar.gz is the casper-node executable.

mkdir bin
cd bin
cp [source of casper-node] ./casper-node
tar -czvf ../bin.tar.gz .

A directory for the protocol_version will be created on the server. For example: 1_1_0.

We will copy bin.tar.gz and config.tar.gz into 1_1_0. Once this is done, we are safe to update protocol_versions by appending 1_1_0 to the end of the file and uploading it into the root of the network directory.

Any node that runs the following command will get this new upgrade:

sudo -u casper /etc/casper/node_util.py stage_protocols <network.conf>

Basic Node Configuration

This page outlines the processes and files involved in setting up a Casper node. For step-by-step node installation instructions, follow the Node Setup guide.

The Casper Node Launcher

A node is usually run by executing the casper-node-launcher, which executes the casper-node as a child process and also handles upgrades to bring the node to the latest version released.

The casper-node-launcher can be installed via a Debian package, which also creates the casper user and directory structures and sets up a systemd unit and logging.

The casper-node-launcher Debian package can be obtained from https://repo.casperlabs.io. You only need to run the steps detailed there once.

Then, proceed to install the casper-node-launcher by running these commands:

sudo apt update
sudo apt install casper-node-launcher

You can also build from source. However, all the setup and pull of casper-node releases will be manual.

File Locations

The casper-node-launcher Debian installation creates the directories and files needed to run casper-node versions and perform upgrades. A casper user and casper group are created during installation and used to run the software. Two main folders are relevant for our software: /etc/casper and /var/lib/casper.

The casper-node install version

Each version of the casper-node install is located based on the semantic version with underscores. For example, version 1.0.3 is represented by a directory named 1_0_3. This convention applies to both binary and configuration file locations. Versioning with [m_n_p] represents the major, minor, and patch of a semantic version.

note

Multiple versioned folders will exist on a system when upgrades are set up.

The following is the filesystem's state after installing the casper-client and casper-node-launcher Debian packages, and after running the command sudo -u casper /etc/casper/node_util.py stage_protocols casper.conf (Use casper-test.conf if on Testnet).

/usr/bin/

The default location for executables from the Debian package install is /usr/bin.

  • casper-client - A client for interacting with a Casper network
  • casper-node-launcher - The launcher application which starts the casper-node as a child process

/etc/casper/

This is the default location for configuration files. It can be overwritten with the CASPER_CONFIG_DIR environment variable. The paths in this document assume the default configuration file location of /etc/casper. The data is organized as follows:

  • delete_local_db.sh - Removes *.lmdb* files from /var/lib/casper/casper-node
  • pull_casper_node_version.sh - Pulls bin.tar.gz and config.tar.gz from genesis.casperlabs.io for a specified protocol version and extracts them into /var/lib/bin/<protocol_version> and /etc/casper/<protocol_version>
  • config_from_example.sh - Gets external IP to replace and create the config.toml from config-example.toml
  • node_util.py - A script that will be replacing other scripts and is the preferred method of performing the actions of pull_casper_node_version.sh, config_from_example.sh, and delete_local_db.sh. Other scripts will be deprecated in future releases of casper-node-launcher.
  • casper-node-launcher-state.toml - The local state for the casper-node-launcher which is created during the first run
  • validator_keys/ - The default folder for node keys, containing:
    • README.md - Instructions on how to create validator keys using the casper-client
    • secret_key.pem - Secret key used by the validator node to sign blocks and peer-to-peer messages
    • public_key.pem - Public key associated with the secret key above, stored in PEM format
    • public_key_hex - Public key associated with the secret key above, stored in hex format
  • 1_0_0/ - Folder for genesis configuration files, containing:
    • accounts.toml - Contains the genesis validators and delegators
    • chainspec.toml - Contains invariant network settings, with the activation_point (network start time) as a timestamp
    • config-example.toml - Example for creating a config.toml file
    • config.toml - Contains variable node configuration settings, created by a node operator manually or by running config_from_example.sh 1_0_0
  • m_n_p/ - Folder for each installed upgrade package's configuration files, containing:
    • chainspec.toml - Contains invariant network settings, with the activation_point as an era ID (the era at which this protocol version of the node became or will become active)
    • config-example.toml - As per 1_0_0/config-example.toml, but compatible with the m.n.p version of the node
    • config.toml - As per 1_0_0/config.toml, but compatible with the m.n.p version of the node

/var/lib/casper/

This is the location for larger and variable data for the casper-node, organized in the following folders and files:

  • bin/ - The parent folder storing the versions of casper-node executables. This location can be overwritten with the CASPER_BIN_DIR environment variable. The paths in this document assume the default of /var/lib/casper/bin/.

    • 1_0_0/ - Folder for genesis binary files, containing:
      • casper-node - The node executable - defaults to the Ubuntu 20.04 compatible binary
      • README.md - Information about the repository location and the Git hash used for compilation to allow a rebuild on other platforms
    • m_n_p/ - Folder for each installed upgrade package, containing:
      • casper-node - As per 1_0_0/casper-node, but the m.n.p version of the node
      • README.md - As per 1_0_0/README.md, but compatible with the m.n.p version of the node
  • casper-node/<NETWORK NAME> - Folder containing databases and related files produced by the node binary. For Mainnet, the network name is casper and for Testnet it is casper-test.

    • data.lmdb - Persistent global state store of the network
    • data.lmbd-lock - Lockfile for the data.lmdb database
    • storage.lmdb - Persistent store of all other network data, primarily Blocks and Deploys
    • storage.lmdb-lock - Lockfile for the storage.lmdb database
    • unit_files/ - Folder containing transient caches of consensus information

Node Version Installation

Included with the casper-node-launcher is node_util.py for installing casper-node versions. This command will stage all current casper-node versions:

sudo -u casper /etc/casper/node_util.py stage_protocols <NETWORK_CONFIG>

For <NETWORK_CONFIG>, we use casper.conf for Mainnet and casper-test.conf for Testnet. This will install all currently released protocols in one step.

This command will do the following:

  • Create /var/lib/casper/bin/1_0_2/ and expand the bin.tar.gz containing at a minimum casper-node
  • Create /etc/casper/1_0_2/ and expand the config.tar.gz containing chainspec.toml, config-example.toml, and possibly accounts.csv and other files
  • Remove the archive files and run /etc/casper/config_from_example.sh 1_0_2 to create a config.toml from the config-example.toml

Release versions are invoked using the underscore format, such as:

sudo -u casper /etc/casper/pull_casper_node_version.sh 1_0_2

The Node Configuration File

One config.toml file exists for each casper-node version installed. It is located in the /etc/casper/[m_n_p]/ directory, where m_n_p is the current semantic version. This can be created from the config-example.toml by using /etc/casper/config_from_example.sh [m_n_p] where [m_n_p] is replaced with the current version, using underscores.

Below are some fields in the config.toml that you may need to adjust.

The Trusted Hash for Synchronizing

Each Casper network is a permissionless, Proof-of-Stake network, implying that nodes can join and leave the network. As a result, some nodes may not be synchronized or as secure as bonded validators. Ideally, all nodes will join the network using a trusted source, such as a bonded validator.

When joining the network, the system will start from the hash of a recent block and then work backward to obtain the finalized blocks from the linear block store. Here is the process to get the trusted hash of a bonded validator:

  • Find a list of trusted validators
  • Query the status endpoint of a trusted validator (http://<NODE_IP_ADDRESS>:8888/status)
  • Obtain the hash of a block from the status endpoint
  • Update the config.toml for the node to include the trusted hash. There is a field dedicated to this near the top of the file

Here is an example command for obtaining a trusted hash. Replace the node address with an updated address from a node on the network.

sudo sed -i "/trusted_hash =/c\trusted_hash = '$(casper-client get-block --node-address http://3.14.161.135:7777 -b 20 | jq -r .result.block.hash | tr -d '\n')'" /etc/casper/1_0_0/config.toml

Known Addresses

For the node to connect to a network, the node needs a set of trusted peers for that network. For Mainnet, these are listed in the config.toml as known_addresses. For other networks, locate and update the list to include at least two trusted IP addresses for peers in that network. Here is an example configuration. The casper-protocol-release repository stores configurations for various environments, which you can also use as examples.

Updating the config.toml file

At the top of a config.toml file as shown here, enter the trusted block hash to replace the 'HEX-FORMATTED BLOCK HASH' and uncomment the line by deleting the leading '#'. See the Configuration File for more details.

# ================================
# Configuration options for a node
# ================================
[node]

# If set, use this hash as a trust anchor when joining an existing network.
#trusted_hash = 'HEX-FORMATTED BLOCK HASH'

Secret Keys

Provide the path to the secret keys for the node. This path is set to etc/casper/validator_keys/ by default. See Creating Keys and Funding Accounts for more details.

Networking and Gossiping

The node requires a publicly accessible IP address. The config_from_example.sh and node_util.py both allow IP for network address translation (NAT) setup. Specify the public IP address of the node. If you use the config_from_example.sh external services are called to find your IP and this is inserted into the config.toml created.

The following default values are specified in the file if you want to change them:

  • The port that will be used for status and deploys
  • The port used for networking
  • Known_addresses - these are the bootstrap nodes (there is no need to change these)

Enabling Speculative Execution

The speculative_exec endpoint provides a method to execute a Deploy without committing its execution effects to global state. This can be used by developers to roughly estimate the gas costs of sending the Deploy in question. By default, speculative_exec is disabled on a node.

speculative_exec can be enabled within config.toml by changing enable_server to true under the configuration options for the speculative execution JSON-RPC HTTP server.

Node operators may also change the incoming request port for speculative execution, which defaults to 7778. Further, you can choose to alter the qps_limit and max_body_bytes, which limit the amount and size of requests to the speculative execution server.

Example Config.toml configuration with speculative execution enabled

# ========================================================================
# Configuration options for the speculative execution JSON-RPC HTTP server
# ========================================================================
[speculative_exec_server]

# Flag which enables the speculative execution JSON-RPC HTTP server.
enable_server = true

# Listening address for speculative execution JSON-RPC HTTP server. If the port
# is set to 0, a random port will be used.
#
# If the specified port cannot be bound to, a random port will be tried instead.
# If binding fails, the speculative execution JSON-RPC HTTP server will not run,
# but the node will be otherwise unaffected.
#
# The actual bound address will be reported via a log line if logging is enabled.
address = '0.0.0.0:7778'

# The global max rate of requests (per second) before they are limited.
# Request will be delayed to the next 1 second bucket once limited.
qps_limit = 1

# Maximum number of bytes to accept in a single request body.
max_body_bytes = 2_621_440

# Specifies which origin will be reported as allowed by speculative execution server.
#
# If left empty, CORS will be disabled.
# If set to '*', any origin is allowed.
# Otherwise, only a specified origin is allowed. The given string must conform to the [origin scheme](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin).
cors_origin = ''

Rust Client Installation

The Prerequisites page lists installation instructions for the Casper client, which is useful for generating keys and retrieving information from the network.

Creating Keys and Funding Accounts

The following command will create keys in the /etc/casper/validator_keys folder.

sudo -u casper casper-client keygen /etc/casper/validator_keys

To learn about other options for generating keys, see Accounts and Cryptographic Keys or run the Rust client keygen command with the --help option.

sudo -u casper casper-client keygen --help

More about keys and key generation can also be found in /etc/casper/validator_keys/README.md if the casper-node-launcher was installed from the Debian package.

note

Save your keys in a secure location, preferably offline.

To submit a bonding request, you will need to fund your account as well.

Introducing Fast Sync

A Casper Network requires new nodes to download and execute every block to join the network. From genesis (start of the Mainnet), the node executes each deploy in every block. This process continues until the node has arrived at the current state of the blockchain. Syncing a node this way can take a very long time.

We have introduced a fast syncing process (fast sync) to provide a faster alternative to joining a Casper network. Fast sync does not start syncing at the genesis block; instead, the operator verifies a recent block and provides a trusted hash to the node software. The global state, account balances, and all other on-chain information is the storage layer of the blockchain and is massive in size, so fast sync downloads the global state of only the most recent block. The following section briefly describes the fast sync process.

How Fast Sync Works

For fast sync, operators must provide the trusted hash of a block in the config.toml file. An example can be found here.

Fast sync uses this trusted block as part of the cryptographic verification for the later blocks. The node downloads the trusted block first, then newer blocks up to and including the most recent block from the current era. For example, if the trusted hash is 5 hours old, it will first download that block, then newer blocks, until it arrives at one that is only a few minutes old. It then downloads the newer block's global state. Finally, it executes all the blocks the network created while the download was in progress until it is entirely in sync.

Recommended Hardware Specifications

System Requirements

The following hardware specifications are recommended for the Casper Mainnet and Testnet:

  • 4 Cores
  • 32 GB Ram
  • 2 TB SSD or network SSD backed disk
  • Linux machine running Ubuntu 20.04
Notes
  • SSD is required because HDD cannot perform random writes at the performance needed to keep in sync with the full speed of the network.

  • For non-archival nodes, disc usage will drop once data recovery is implemented. It is safe to slowly increase the disc space as needed while monitoring on a server capable of this.

CPU Requirements

Attempting to run a Casper node on older hardware can result in unexpected crashes. This is due to the CPU not supporting instructions used by our official binaries, including AVX2 and Intel SHA extensions.

To avoid these issues, we recommend a CPU running AMD Zen, Intel Ice Lake or newer architecture.

note

This only applies to official binaries released by Casper. If you are compiling your node from scratch, you may choose to disable the extensions in question.

Setting up a Node

The prerequisite for becoming a validator is to set up a node and join a network as described here.

TitleDescription
Recommended Hardware SpecificationsSystem requirements for the Casper Mainnet and Testnet
Basic Node ConfigurationProcesses and files involved in setting up a Casper node
Node EndpointsPorts for communicating with other nodes and dApps
Installing a NodeStep-by-step instructions to install a Casper node
Setting the Open Files LimitRequired setting for the Casper node to run correctly
Upgrading the NodeBefore joining the network, the node needs to be upgraded
Joining a Running NetworkSteps to join an existing Casper network
Setting up a Non-Root UserLogging into the node remotely using a key

Installing a Node

Ensure the requirements listed in the following sections are met before you start setting up the node on the network, either on Mainnet or Testnet.

Network Requirements

The following ports are used by the node:

  • 35000 (required to be externally visible)
  • 7777 RPC endpoint for interaction with JSON-RPC API
  • 8888 REST endpoint for status and metrics (having this accessible allows your node to be part of network status)
  • 9999 SSE endpoint for event stream

Of these 35000 is the only port required to be open for your node to function, however, opening 8888 will allow others to know general network health. For more details, see the additional information on Node Endpoints.

Operating System Requirements

The recommended OS version is Ubuntu 20.04.

Using Ubuntu 22.04

Installing using Ubuntu 22.04 follows the same instructions as 20.04 with one exception:

If you try to install packages, you will receive:

casper-client : Depends: libssl1.1 (>= 1.1.0) but it is not installable

This message is due to the default openssl moving to 3. with Ubuntu 22.04. You need to install OpenSSL 1. for prior versions of Ubuntu to use the Casper binaries with the following command:

curl -f -JLO http://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2.20_amd64.deb
sudo apt install ./libssl1.1_1.1.1f-1ubuntu2.19_amd64.deb

Required Number of Open Files

Before beginning, update the maximum open files limit for your system. Specifically, update the node's /etc/security/limits.conf file as described here, to ensure proper node operation.

Required Clean Up

If you were running a previous node on this box, this will clean up state. If packages are not installed, the apt remove may give errors, but this is not a problem.

sudo systemctl stop casper-node-launcher.service
sudo apt remove -y casper-client
sudo apt remove -y casper-node
sudo apt remove -y casper-node-launcher
sudo rm /etc/casper/casper-node-launcher-state.toml
sudo rm -rf /etc/casper/1_*
sudo rm -rf /var/lib/casper/*

Required Packages

The following commands will set up the Casper Labs repository for packages:

echo "deb [arch=amd64] https://repo.casperlabs.io/releases focal main" | sudo tee -a /etc/apt/sources.list.d/casper.list
curl -O https://repo.casperlabs.io/casper-repo-pubkey.asc
sudo apt-key add casper-repo-pubkey.asc
sudo apt update

Required Tools

sudo apt install -y casper-client casper-node-launcher jq

Enable Bash Auto-Completion for casper-client (Optional)

sudo casper-client generate-completion

It defaults to bash but can be changed with the --shell argument:

--shell <STRING>    The type of shell to generate the completion script for [default: bash]  [possible values:
zsh, bash, fish, powershell, elvish]

sudo casper-client generate-completion --shell powershell

You need to source the new auto completion script or log out and log in again to activate it for the current shell:

source /usr/share/bash-completion/completions/casper-client

Now you can use casper-client and press the tab key to get auto completion for your commands.

Installing All Protocols

On Mainnet, run:

sudo -u casper /etc/casper/node_util.py stage_protocols casper.conf

On Testnet, run:

sudo -u casper /etc/casper/node_util.py stage_protocols casper-test.conf

Validator Keys

If you do not have keys yet, you can create them using the following command:

sudo -u casper casper-client keygen /etc/casper/validator_keys

For more details, see the Node Setup page.

Getting a Trusted Hash

In the past, we have used a lower trusted_hash. Connecting at the tip, we now use as high of a trusted_hash as possible. Find out more about Fast Sync.

Node Address

NODE_ADDR can be set to an IP of a trusted node, or to Casper Labs' public nodes

You can find active peers at https://cspr.live/tools/peers or use the following Casper Labs public nodes:

Protocol Version

Protocol version should be set to the largest available protocol version you see in ls /etc/casper. As of writing this, it was 1_5_2:

PROTOCOL=1_5_2

Load trusted_hash in Config.toml of the Protocol Version

The following command uses the previously established NODE_ADDR and PROTOCOL to load the trusted_hash:

NODE_ADDR=https://rpc.mainnet.casperlabs.io
PROTOCOL=1_5_2
sudo sed -i "/trusted_hash =/c\trusted_hash = '$(casper-client get-block --node-address $NODE_ADDR | jq -r .result.block.hash | tr -d '\n')'" /etc/casper/$PROTOCOL/config.toml

Syncing to Genesis

In the latest protocol version's Config.toml, you will find the option sync_to_genesis. By default, this value will be set to true.

If you are planning to run a validator node, it is better to not sync your node to genesis. This will increase node performance. In this case, the option should be changed to:

sync_to_genesis = false

If you are using the node for historical data and want to query back to genesis, you can leave the default value in place.

Starting the Node

Start the node using the following commands:

sudo /etc/casper/node_util.py rotate_logs
sudo /etc/casper/node_util.py start

Monitoring the Synchronization Process

The following command will display the node synchronization details:

/etc/casper/node_util.py watch

When you first run the watch command, you may see the message RPC: Not Ready. Once the node is synchronized, the status will change to RPC: Ready and a similar output:

Last Block: 630151 (Era: 4153)
Peer Count: 297
Uptime: 4days 6h 40m 18s 553ms
Build: 1.4.5-a7f6a648d-casper-mainnet
Key: 0147b4cae09d64ab6acd02dd0868722be9a9bcc355c2fdff7c2c244cbfcd30f158
Next Upgrade: None

RPC: Ready

● casper-node-launcher.service - Casper Node Launcher
Loaded: loaded (/lib/systemd/system/casper-node-launcher.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2022-03-16 21:08:50 UTC; 4 days ago
Docs: https://docs.casper.network
Main PID: 2934 (casper-node-lau)
Tasks: 12 (limit: 4915)
CGroup: /system.slice/casper-node-launcher.service
├─ 2934 /usr/bin/casper-node-launcher
└─16842 /var/lib/casper/bin/1_4_5/casper-node validator /etc/casper/1_4_5/config.toml

The reactor state will be in CatchUp mode until it acquires the full tip state, at which point it will shift to KeepUp mode. If you left sync_to_genesis as true, it will begin syncing back history at this time.

Seeing available block range - Low: 0 High: 0 is normal until the fill tip is downloaded. You can see download progress with a look at metrics:

$ curl -s 127.0.0.1:8888/metrics | grep trie_or_chunk
# HELP trie_or_chunk_fetch_total number of trie_or_chunk all fetch requests made
# TYPE trie_or_chunk_fetch_total counter
trie_or_chunk_fetch_total 102647
# HELP trie_or_chunk_found_in_storage number of fetch requests that found trie_or_chunk in local storage
# TYPE trie_or_chunk_found_in_storage counter
trie_or_chunk_found_in_storage 0
# HELP trie_or_chunk_found_on_peer number of fetch requests that fetched trie_or_chunk from peer
# TYPE trie_or_chunk_found_on_peer counter
trie_or_chunk_found_on_peer 102263
# HELP trie_or_chunk_timeouts number of trie_or_chunk fetch requests that timed out
# TYPE trie_or_chunk_timeouts counter
trie_or_chunk_timeouts 0

If the node is not showing active (running) status, it is either stopped or in the process of restarting.

Monitoring the Running Node

The community has created a few tools to monitor your node once it is running, such as:

A Note on Speculative Execution

The speculative_exec_server defaults to off and can be enabled in your Config.toml file.

While this is a useful tool, understand that it is also an attack vector for a node. The intent is for someone to run on their node as a tool. You should not use this if you are an active validator, as requests into this port can block execution_engine processing for legitimate network traffic.

Joining a Running Network

Each Casper network is permissionless, enabling new validators to join the network and provide additional security to the system. This page outlines the sequence of recommended steps to spin up a validating node and join an existing network.

Step 1: Provisioning Hardware

Visit the Hardware Specifications section and provision your node hardware.

Step 2: Setting Up the Node

Follow the instructions on the Node Setup page.

Step 3: Building the Required Contracts

Use the commands below to build all the necessary contracts for bonding, retrieving rewards, and unbonding.

  1. Clone the casper-node repository.
git clone https://github.com/casper-network/casper-node
  1. Install these prerequisites, which are also listed here.
  • Rust
  • CMake
  • pkg-config - On Ubuntu, use sudo apt-get install pkg-config
  • openssl - On Ubuntu, use sudo apt-get install openssl
  • libssl-dev - On Ubuntu, use sudo apt-get install libssl-dev
  1. Install the Rust casper-client and fund the keys you will use for bonding.

  2. Use the following commands to build the contracts in release mode. Make sure you have installed Rust.

cd casper-node
make setup-rs
make build-client-contracts

These commands will build all the necessary Wasm contracts for operating as a validator:

  • activate_bid.wasm - Reactivates an ejected validator
  • add_bid.wasm - Enables bonding for validator stake
  • delegate.wasm - Delegates stake
  • undelegate.wasm - Undelegates stake
  • withdraw_bid.wasm - Enables unbonding for validator stake

Step 4: Creating and Fund Keys for Bonding

See the Node Setup instructions if you have not generated and funded your validator keys.

Step 5: Updating the Trusted Hash

The node's config.toml needs to be updated with a recent trusted hash.

See the Trusted Hash for Synchronizing instructions if you have not set up a trusted hash during node installation.

Step 6: Starting the Node

Start the node with the casper-node-launcher:

sudo systemctl start casper-node-launcher

The above Debian package installs a casper-node service for systemd.

For more information, visit GitHub.

Step 7: Confirming the Node is Synchronized

While the node is synchronizing, the /status endpoint is available. You will be able to compare this to another node's status endpoint era_id and height to determine if you are caught up. You will not be able to perform any casper-client calls to your 7777 RPC port until your node is fully caught up.

Towards the end of the following output, notice the era_id and height that you can use to determine if your node has completed synchronizing.

Sample output of the /status endpoint
{
"api_version": "1.4.3",
"chainspec_name": "casper-test",
"starting_state_root_hash": "e2218b6bdb8137a178f242e9de24ef5db06af7925e8e4c65fa82d41df38f4576",
"peers": [
{
"node_id": "tls:0097..b253",
"address": "18.163.249.168:35000"
},
...
...
...
{
"node_id": "tls:ff95..c014",
"address": "93.186.201.14:35000"
}
],
"last_added_block_info": {
"hash": "8280de05cb34071f276fbe7c69a07cb325ddd373f685877911238b614bdcc5b1",
"timestamp": "2022-01-04T15:33:08.224Z",
"era_id": 3240,
"height": 430162,
"state_root_hash": "ec4ff5c4d0a9021984b56e2b6de4a57188101c24e09b765c3fee740353690076",
"creator": "01ace6578907bfe6eba3a618e863bbe7274284c88e405e2857be80dd094726a223"
},
"our_public_signing_key": "01cb41ee07d1827e243588711d45040fe46402bf3901fb550abfd08d1341700270",
"round_length": null,
"next_upgrade": null,
"build_version": "1.4.3-a44bed1fd-casper-mainnet",
"uptime": "25days 1h 48m 22s 47ms"
}

Step 8: Sending the Bonding Request

You can submit a bonding request to change your synchronized node to a validating node.

The bonding request must be sent after the node has synchronized the protocol state and linear blockchain to avoid being ejected for liveness failures.

Node Endpoints

As specified in the Network Requirements, a Casper node uses specific ports to communicate with client applications and other nodes on the network. Each node has an identity linked with an IP and port pair where the node is reachable. This address is also called an endpoint. The Network Communication page explains how the nodes connect and communicate securely. Node connections are established using TLS, presenting a client certificate to encrypt peer-to-peer communication.

This document describes in more detail a Casper node's default endpoints:

Node operators can modify a node's configuration options, including the port settings, by updating the node's config.toml file. An example configuration file can be found here.

The default endpoints for Mainnet and Testnet are open by default and are described below in more detail. If the node connects to a different network, the ports may differ depending on how the network was set up.

Default Networking Port: 35000

The configuration options for networking are under the network section of the config.toml file. The bind_address using port 35000 is the only port required to be open for the node to function. A Casper node taking part in the network should open connections to every other node it is aware of and has not blocked. In the config.toml file, the setting is:

bind_address = '0.0.0.0:35000'

If the networking port is closed, the node becomes unreachable, and the node won't be discoverable in the network. If this is a validator, it will face eviction. A read-only node will be considered to be offline.

Default JSON-RPC HTTP Server Port: 7777

The configuration options for the JSON-RPC HTTP server are under the rpc_server section in the config.toml file. The address using port 7777 is the listening address for JSON-RPC HTTP server.

address = '0.0.0.0:7777'

DApps would use this address to interact with the Casper JSON-RPC API. Users would use this address to interact with the network using CLI. Validators would use this address to bond or unbond. If this port is closed, the requests coming to this port will not be served, but the node remains unaffected.

Default REST HTTP Server Port: 8888

The configuration options for the JSON-RPC HTTP server are under the rest_server section in the config.toml file. The address listing port 8888 is the listening address for the REST HTTP server.

address = '0.0.0.0:8888'

Opening port 8888 is recommended but not required. This port allows the node to be included in the general network health metrics, thus giving a more accurate picture of overall network health. If this port is closed, the requests coming to this port will not be served, but the node remains unaffected.

One may use this port to get a trusted hash, verify successful staging during an upgrade, or to confirm that the node is synchronized.

Example usage

For general health metrics, use this command:

curl -s http://<node_address>:8888/metrics

You can check the node's status using this command:

curl -s http://<node_address>:8888/status

The status endpoint provides a JSON response that can be parsed with jq.

curl -s http://<node_address>:8888/status | jq
Sample response
{
"api_version": "1.4.15",
"chainspec_name": "casper-test",
"starting_state_root_hash": "4c3856bd6a95b566301b9da61aaf84589a51ee2980f3cc7bbef78e7745386955",
"peers": [
{
"node_id": "tls:007e..e14b",
"address": "89.58.52.245:35000"
},
{
"node_id": "tls:00eb..ac11",
"address": "65.109.17.120:35000"
},
...{
"node_id": "tls:ffc0..555b",
"address": "95.217.228.224:35000"
}
],
"last_added_block_info": {
"hash": "7acd2f48b573704e96eab54322f7e91a0624252baca3583ad2aae38229fe1715",
"timestamp": "2023-05-10T09:20:10.752Z",
"era_id": 9085,
"height": 1711254,
"state_root_hash": "1ac74071c1e76937c372c8d2ae22ea036a77578aad03821ec98021fdc1c5d06b",
"creator": "0106ca7c39cd272dbf21a86eeb3b36b7c26e2e9b94af64292419f7862936bca2ca"
},
"our_public_signing_key": "0107cba5b4826a87ddbe0ba8cda8064881b75882f05094c1a5f95e957512a3450e",
"round_length": "32s 768ms",
"next_upgrade": null,
"build_version": "1.4.15-039d438f2-casper-mainnet",
"uptime": "5days 13h 46m 54s 520ms"
}

You can filter the result with dot notation, specifying one of the following parameters:

  • api_version - The RPC API version
  • chainspec_name - The chainspec name, used to identify the currently connected network
  • starting_state_root_hash - The state root hash used at the start of the current session
  • peers - The node ID and network address of each connected peer
  • last_added_block_info - The minimal info of the last Block from the linear chain
  • our_public_signing_key - Our public signing key
  • round_length - The next round length if this node is a validator.
  • next_upgrade - Information about the next scheduled upgrade
  • build_version - The compiled node version
  • uptime - Time that has passed since the node has started.

Here is an example command for retrieving general network information:

curl -s http://<node_address>:8888/status | jq -r '.api_version, .last_added_block_info, .build_version, .uptime'
Sample response
"1.4.15"
{
"hash": "dca9959b21df52633f85cd373a8117fe8e89629dd2a0455781484a439f7d9f62",
"timestamp": "2023-05-10T09:26:43.968Z",
"era_id": 9085,
"height": 1711266,
"state_root_hash": "5f374529e747a06ec825e07a030df7b9d80d1f7ffac9156779b4466620721872",
"creator": "0107cba5b4826a87ddbe0ba8cda8064881b75882f05094c1a5f95e957512a3450e"
}
"1.4.15-039d438f2-casper-mainnet"
"5days 13h 53m 10s 763ms"

To get information about the next upgrade, use:

curl -s http://<node_address>:8888/status | jq .next_upgrade

To get information about the last added block, use:

curl -s http://<node_address>:8888/status | jq .last_added_block_info

To monitor the downloading of blocks to your node:

watch -n 15 'curl -s http://<node_address>:8888/status | jq ".peers | length"; curl -s http://<node_address>:8888/status | jq .last_added_block_info'

To monitor local block height as well as RPC port status:

watch -n 15 'curl -s http://<node_address>:8888/status | jq ".peers | length"; curl -s http://<node_address>:8888/status | jq .last_added_block_info; casper-client get-block -n http://<node_address>:8888/status'

Default SSE HTTP Event Stream Server Port: 9999

The configuration options for the SSE HTTP event stream server are listed under the event_stream_server section of the config.toml file. The address listing port 9999 is the listening address for the SSE HTTP event stream server.

address = '0.0.0.0:9999'

If this port is closed, the requests coming to this port will not be served, but the node remains unaffected. For details and useful commands, see Monitoring and Consuming Events.

Setting up Firewall Rules

To limit inbound traffic to the node’s endpoints, you can set firewall rules similar to the ufw commands below:

sudo apt install ufw -y
sudo ufw disable
sudo ufw reset
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw limit ssh
sudo ufw limit 7777/tcp
sudo ufw limit 8888/tcp
sudo ufw limit 35000/tcp
sudo ufw enable

These commands will limit requests to the available ports of your node. Port 35000 should be left open, although you can limit traffic, as it is crucial for node-to-node communication.

If you have any concerns, questions, or issues, please submit a request to the Casper support team.

Restricting Access for Private Networks

Any node can join Mainnet and Testnet and communicate with the nodes in the network. Private networks may wish to restrict access for new nodes joining the network as described here.

Here is a summary of the links mentioned on this page:

Setting up a Non-Root User

Operators may log into their servers remotely using a key. The following steps explain how to create a non-root user and log in using a private key instead of the root user. Replace <username> in the instructions below with your username.

  1. Use ssh-keygen to generate a new SSH key.

  2. Create the user with no password, as the key is your password.

sudo adduser <username> --disabled-password
  1. Create authorized_keys with your key to log in.
sudo su - <username>
mkdir .ssh
chmod 700 .ssh
touch .ssh/authorized_keys
  1. Use the editor of your choice and paste your .ssh public key i the .ssh/authorized_keys file.

  2. Exit out of the <username> account and log into the root or previous sudo-er account.

exit
  1. Add your user to sudo-ers under the root account or your previous sudo-er account.
sudo visudo
  1. Type <username> ALL=(ALL:ALL) NOPASSWD:ALL below the row containing root ALL=(ALL:ALL) ALL.
# User privilege specification
root ALL=(ALL:ALL) ALL
<username> ALL=(ALL:ALL) NOPASSWD:ALL
  1. You should be able to log in with the key and not use the root user.
ssh -i <your ssh private key> <username>@<server ip>

Here is an example command:

ssh -i ~/.ssh/id_rsa casper@10.21.10.200

Setting the Open Files Limit

When the casper-node launches, it tries to set the maximum open files limit (nofile) for the process to 64000. With some systems, this limit will be larger than the default hard limit of 4096.

The node software uses file handles for both files and network connections. Since network connections are unpredictable, running out of file handles can stop critical file writes from occurring. Therefore, the default nofile limit needs to be increased.

With the casper-node-launcher running, you can see what the system allocated by finding the process ID (PID) for the casper-node with the following command.

pgrep "casper-node$"
Sample output
$ pgrep "casper-node$"
275928
note

This PID will change, so you need to run the above command to get the current version with your system. Also, it will not be 275928 each time.

If you do not get a value in return, you do not have the casper-node-launcher running correctly.

To find the current nofile (number of open files) hard limit, run prlimit with the PID from the previous command:

sudo prlimit -n -p <PID>
Sample output
$ sudo prlimit -n -p 275928
RESOURCE DESCRIPTION SOFT HARD UNITS
NOFILE max number of open files 1024 4096 files

You can also embed both commands as shown here:

sudo prlimit -n -p $(pgrep "casper-node$")
Sample output
$ sudo prlimit -n -p $(pgrep "casper-node$")
RESOURCE DESCRIPTION SOFT HARD UNITS
NOFILE max number of open files 1024 4096 files

If you receive prlimit: option requires an argument -- 'p', then pgrep "casper-node$" is not returning anything because the casper-node-launcher is no longer running.

Setting the Limit Manually

Run the command below to set the nofile limit for an active process without restarting the casper-node-launcher and casper-node processes. Note that this setting is active only while the casper-node process runs. To make this setting permanent, update the limits.conf file instead.

sudo prlimit --nofile=64000 --pid=$(pgrep "casper-node$")`

Next, check that the prlimit has changed:

sudo prlimit -n -p $(pgrep "casper-node$")
Sample output
$ sudo prlimit -n -p $(pgrep "casper-node$")
RESOURCE DESCRIPTION SOFT HARD UNITS
NOFILE max number of open files 64000 64000 files

Updating the limits.conf File

It is possible to persist the nofile limit across server reboots, casper-node-launcher restarts, and protocol upgrades, by adding the nofile setting for the casper user in /etc/security/limits.conf.

Add the following row to the bottom of the /etc/security/limits.conf file:

casper          hard    nofile          64000

Afterward, log out of any shells to enable this change. Restarting the node should maintain the correct nofile setting.

Upgrading the Node

The chainspec.toml contains a section to indicate from which era the given casper-node version should start running.

[protocol]
# This protocol version becomes active at the start of this era.
activation_point = 100

At every block finalization, the casper-node looks for newly configured versions. When a new version is configured, the running node will look at future era_id in the chainspec.toml file. This will be the era before where the current casper-node will cleanly shut down.

The casper-node-launcher will detect a clean exit 0 condition and start the next version of the casper-node.

Upgrading Protocol Versions

All Casper Mainnet participants are requested to stage the upgrade of their nodes to a new version of casper-node immediately. Staging an upgrade is a process in which you tell your node to download the upgrade files and prepare them so that they can automatically be applied at the pre-defined activation point.

Do not restart the node, only run the commands provided. The upgrade will automatically occur at the activation point.

Upgrade Staging Instructions

The process to upgrade your node is very straightforward. Log in to your node, and execute the following command on Mainnet:

sudo -u casper /etc/casper/node_util.py stage_protocols casper.conf

On Testnet, use casper-test.conf:

sudo -u casper /etc/casper/node_util.py stage_protocols casper-test.conf

Note: To only view the list of staged and unstaged protocols, use this command: sudo -u casper /etc/casper/node_util.py check_protocols casper.conf

Verifying Successful Staging

After you have successfully executed the staging commands, wait a few minutes for a new block to be issued before checking that your node is correctly staged with the upgrade. After a few minutes, take a look at your status end-point, as follows:

curl -s http://127.0.0.1:8888/status | jq .next_upgrade

You should expect this output if properly staged, prior to upgrading:

$ curl -s localhost:8888/status | jq .next_upgrade
{
"activation_point": 4968,
"protocol_version": "1.4.6"
}

If you see null after waiting for a few minutes, then your upgrade staging was not executed successfully.

Note: The protocol version will change as per the next upgrade available.

Working with Authorization Keys

caution

These examples should not be used in a production environment. They are intended only for teaching and must be tested and adapted for production use.

This tutorial demonstrates retrieving and using the authorization keys associated with a deploy using the list_authorization_keys function.

let authorization_keys = runtime::list_authorization_keys();

Remember that authorization keys are listed under a Deploy's approvals section, which lists the signatures and the public keys of the signers, also called authorizing keys. Here is an example of a deploy's approvals:

"approvals": [
{
"signer": "02021a4da3d6f32ea3ebd2519e1a37a1b811671085bf4f1cf2a36b931344a99b756a",
"signature": "02df8cdf0bff3bd93e831d24563d5acbefa0ed13814550e910d03208d5fb3c11770dd3d918784ec84342e53666eacf59aeecbf4ce0cdd60e167c4a4b20e4b8f481"
}
]

The contract code in this example retrieves the set of authorization keys for a given deploy by calling the runtime::list_authorization_keys function. In other words, list_authorization_keys returns the set of account hashes representing the keys used to sign a deploy. Upon installation, the contract code stores the authorization keys for the installer deploy into a NamedKey. The contract also contains an entry point that returns the intersection of the caller deploy's, and installer deploy's authorization keys. The tests in this repository verify different scenarios and check the resulting intersection.

Prerequisites

Workflow

To start, clone the tutorials-example-wasm repository. Then, open the authorization-keys-example directory, prepare your Rust environment, and build the tests with the following commands.

git clone https://github.com/casper-ecosystem/tutorials-example-wasm
cd tutorials-example-wasm/authorization-keys-example
make prepare
make test

Review the repository's structure:

  • client - A client folder containing two Wasm files
    • add_keys.wasm - Session code that adds an associated key to the calling account
    • contract_call.wasm - Session code that calls the contract's entry point and stores the result into a named key
  • contract - A simple contract that demonstrates the usage of authorization keys and compiles into a contract.wasm file
  • tests - Tests and supporting utilities to verify and demonstrate the contract's expected behavior
note

This tutorial highlights certain lines of code found in GitHub.

The example contract

Upon installation, the contract in this example stores the authorization keys that signed the installer deploy into a named key.

#[no_mangle]
pub extern "C" fn init() {
if runtime::get_key(AUTHORIZATION_KEYS_INSTALLER).is_none() {
let authorization_keys: Vec<AccountHash> =
runtime::list_authorization_keys().iter().cloned().collect();

let authorization_keys: Key = storage::new_uref(authorization_keys).into();
runtime::put_key(AUTHORIZATION_KEYS_INSTALLER, authorization_keys);
}
}

The contract contains an entry point that returns the intersection of the caller deploy's authorization keys and the installer deploy's authorization keys saved during contract installation. The following usage of runtime::list_authorization_keys retrieves the set of account hashes representing the keys signing the caller deploy.

let authorization_keys_caller: Vec<AccountHash> =
runtime::list_authorization_keys().iter().cloned().collect();

Client Wasm files

add_keys.wasm

This file contains session code that adds an associated key to the calling account. For more details and a similar example, visit the Two-Party Multi-Signature tutorial.

contract_call.wasm

This session code calls the contract's entry point, which returns the intersection between two sets of keys:

  • The authorization keys that signed the deploy that installed the contract (referred to in this tutorial as the installer deploy)
  • The authorization keys that signed the deploy calling the entry point (referred to in this tutorial as the caller deploy).

The intersection result is a list stored under a named key of the account calling the contract_call.wasm.

let key_name: String = runtime::get_named_arg(ARG_KEY_NAME);
let intersection =
runtime::call_contract::<Vec<AccountHash>>(contract_hash, ENTRY_POINT, runtime_args! {});
runtime::put_key(&key_name, storage::new_uref(intersection).into());
}

Testing this example

This section highlights the tests written for this example, demonstrating the usage of authorization keys. The tests are divided into three parts:

  • Testing the contract installation
  • Testing the contract's unique entry point
  • Testing the entry point using a client contract call

These tests focus on testing the contract installation.

Test 1: should_allow_install_contract_with_default_account

Installer deploy authorization keysExpected outcome
DEFAULT_ACCOUNT_ADDRSuccessful contract installation

This test signs the installer deploy with an authorization key DEFAULT_ACCOUNT_ADDR that belongs to the calling accounts's associated keys. In other words, since the caller is the default account, DEFAULT_ACCOUNT_ADDR can be used to sign the deploy.

let session_code = PathBuf::from(CONTRACT_WASM);
let session_args = RuntimeArgs::new();

let deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])
.with_address(*DEFAULT_ACCOUNT_ADDR)
.with_session_code(session_code, session_args)
.build();

Test 2: should_disallow_install_with_non_added_authorization_key

Installer deploy authorization keysExpected outcome
DEFAULT_ACCOUNT_ADDR, account_addr_1Failed contract installation

This test tries to sign the installer deploy with an authorization key that is not part of the caller's associated keys. This is not allowed because the authorization keys used to sign a deploy need to be a subset of the caller's associated keys. So, the installer deploy fails as expected.

let session_code = PathBuf::from(CONTRACT_WASM);
let session_args = RuntimeArgs::new();

let deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR, account_addr_1])
.with_address(*DEFAULT_ACCOUNT_ADDR)
.with_session_code(session_code, session_args)
.build();

let execute_request = ExecuteRequestBuilder::from_deploy_item(deploy_item).build();
builder.exec(execute_request).commit().expect_failure();
let error = builder.get_error().expect("must have error");
assert_eq!(error.to_string(), "Authorization failure: not authorized.");

Test 3: should_allow_install_with_added_authorization_key

Installer deploy authorization keysExpected outcome
DEFAULT_ACCOUNT_ADDR, account_addr_1Successful contract installation

This test demonstrates a successful installer deploy using an added authorization key. After the initial test framework setup, the test calls session code to add the associated account account_addr_1 to the default account's associated keys.

// Add account_addr_1 to the default account's associated keys
let session_code = PathBuf::from(ADD_KEYS_WASM);
let session_args = runtime_args! {
ASSOCIATED_ACCOUNT => account_addr_1
};

let add_keys_deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])
.with_address(*DEFAULT_ACCOUNT_ADDR)
.with_session_code(session_code, session_args)
.build();

let add_keys_execute_request =
ExecuteRequestBuilder::from_deploy_item(add_keys_deploy_item).build();

builder
.exec(add_keys_execute_request)
.commit()
.expect_success();

Since the deploy threshold is now 2, the installer deploy is signed with the default account hash and with account_addr_1. See GitHub.

let session_code = PathBuf::from(CONTRACT_WASM);

let deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR, account_addr_1])
.with_address(*DEFAULT_ACCOUNT_ADDR)
.with_session_code(session_code, session_args)
.build();

let execute_request = ExecuteRequestBuilder::from_deploy_item(deploy_item).build();
builder.exec(execute_request).commit().expect_success();

The next tests exercise the contract's unique entry point to calculate the intersection between the caller deploy's authorization keys and the installer deploy's authorization keys.

Test 4: should_allow_entry_point_with_installer_authorization_key

Installer deploy authorization keysCaller deploy authorization keysIntersection returned by the entry point
DEFAULT_ACCOUNT_ADDRaccount_addr_1, DEFAULT_ACCOUNT_ADDRaccount_addr_1

This test builds upon the previous test, which adds an associated account to the default account's associated keys and installs the contract using these two keys. Additionally, on line 201, the test invokes the contract's entry point using a deploy that runs under ACCOUNT_USER_1 signed only with account_addr_1. This is possible because the deploy action threshold for ACCOUNT_USER_1 is 1 as you can see here.

let contract_hash = builder
.get_expected_account(*DEFAULT_ACCOUNT_ADDR)
.named_keys()
.get(CONTRACT_HASH)
.expect("must have this entry in named keys")
.into_hash()
.map(ContractHash::new)
.unwrap();

let entry_point_deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[account_addr_1])
.with_address(account_addr_1)
.with_stored_session_hash(contract_hash, ENTRYPOINT, runtime_args! {})
.build();

let entry_point_request =
ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();

builder.exec(entry_point_request).expect_success().commit();

The entry point returns the intersection of the caller deploy's authorization keys and the installer deploy's authorization keys. The intersection is a list containing the key account_addr_1. Thus, the caller deploy is expected to succeed and return a result.

Test 5: should_allow_entry_point_with_account_authorization_key

Installer deploy authorization keysCaller deploy authorization keysIntersection returned by the entry point
DEFAULT_ACCOUNT_ADDRaccount_addr_1, DEFAULT_ACCOUNT_ADDRDEFAULT_ACCOUNT_ADDR

This is the main test in this example repository. After installing the contract using the default account, the test adds the default account hash to ACCOUNT_USER_1 as an associated key.

let session_code = PathBuf::from(ADD_KEYS_WASM);
let session_args = runtime_args! {
ASSOCIATED_ACCOUNT => *DEFAULT_ACCOUNT_ADDR
};

let add_keys_deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[account_addr_1])
.with_address(account_addr_1)
.with_session_code(session_code, session_args)
.build();

Then, the test creates a deploy to invoke the contract's entry point. This deploy executes under ACCOUNT_USER_1 and has two authorization keys, account_addr_1 and the default account hash. Note that both authorization keys must sign the deploy to meet the deploy's action threshold, which is set to 2. The deploy should be executed successfully because the resulting intersection should contain the default account hash.

let entry_point_deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[account_addr_1, *DEFAULT_ACCOUNT_ADDR])
.with_address(account_addr_1)
.with_stored_session_hash(contract_hash, ENTRYPOINT, runtime_args! {})
.build();

let entry_point_request =
ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();

builder.exec(entry_point_request).expect_success().commit();

Test 6: should_disallow_entry_point_without_authorization_key

Installer deploy authorization keysCaller deploy authorization keysIntersection returned by the entry point
DEFAULT_ACCOUNT_ADDRaccount_addr_2None

This test verifies that the entry point returns an error when there is no intersection between the caller deploy's authorization keys and the installer deploy's authorization keys.

The default account hash is used to sign the installer deploy.

let session_code = PathBuf::from(CONTRACT_WASM);

let deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])
.with_address(*DEFAULT_ACCOUNT_ADDR)
.with_session_code(session_code, runtime_args! {})
.build();

In the test, a new account, ACCOUNT_USER_2, creates a deploy invoking the contract's entry point and signs the deploy with account_addr_2. When calling the entry point, an error is returned because the caller and the installer deploys do not have any authorization keys in common.

    // Here ACCOUNT_USER_2 does not have DEFAULT_ACCOUNT_ADDR (from the contract installer) in its associated keys
// The deploy will therefore revert with PermissionDenied
let entry_point_deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[account_addr_2])
.with_address(account_addr_2)
.with_stored_session_hash(contract_hash, ENTRYPOINT, runtime_args! {})
.build();

let entry_point_request =
ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();

builder.exec(entry_point_request).commit().expect_failure();
let error = builder.get_error().expect("must have User error: 0");
assert_expected_error(
error,
0,
"should fail execution since DEFAULT_ACCOUNT_ADDR is not in ACCOUNT_USER_2 associated keys",
);

The following tests exercise the entry point using a contract call and verifying the result returned.

Test 7: should_allow_entry_point_through_contract_call_with_authorization_key

Installer deploy authorization keysCaller deploy authorization keysIntersection returned by the entry point
DEFAULT_ACCOUNT_ADDRaccount_addr_1, DEFAULT_ACCOUNT_ADDRDEFAULT_ACCOUNT_ADDR

This test validates the contract's entry point using a client contract call. The contract is installed using the default account hash in the deploy's authorization keys.

let session_code = PathBuf::from(CONTRACT_WASM);

let deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR])
.with_address(*DEFAULT_ACCOUNT_ADDR)
.with_session_code(session_code, runtime_args! {})
.build();

The caller deploy is signed by account_addr_1 and DEFAULT_ACCOUNT_ADDR:

let entry_point_deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[account_addr_1, *DEFAULT_ACCOUNT_ADDR])
.with_address(account_addr_1)
.with_session_code(session_code, session_args)
.build();

let entry_point_request =
ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();
builder.exec(entry_point_request).expect_success().commit();

The test then verifies that the result returned was saved in the named keys for ACCOUNT_USER_1, containing the default account hash.

let intersection_receipt: Key = *builder
.get_expected_account(account_addr_1)
.named_keys()
.get(INTERSECTION_RECEIPT)
.expect("must have this entry in named keys");

let actual_intersection = builder
.query(None, intersection_receipt, &[])
.expect("must have stored_value")
.as_cl_value()
.map(|intersection_cl_value| {
CLValue::into_t::<Vec<AccountHash>>(intersection_cl_value.clone())
})
.unwrap()
.unwrap();

let expected_intersection = vec![*DEFAULT_ACCOUNT_ADDR];

assert_eq!(actual_intersection, expected_intersection);

Test 8: should_disallow_entry_point_through_contract_call_without_authorization_key

Installer deploy authorization keysCaller deploy authorization keysIntersection returned by the entry point
DEFAULT_ACCOUNT_ADDRaccount_addr_1, account_addr_2None

The final test in this tutorial checks that when there is no intersection between the caller deploy's authorization keys (account_addr_1, account_addr_2) and the installer deploy's authorization keys (DEFAULT_ACCOUNT_ADDR), the entry point returns an error.

 let session_code = PathBuf::from(CONTRACT_CALL_WASM);

let session_args = runtime_args! {
ARG_CONTRACT_HASH => Key::from(contract_hash),
ARG_KEY_NAME => INTERSECTION_RECEIPT
};

// account_addr_2 as an associated key is not among the default account's associated keys
// The deploy will therefore revert with PermissionDenied
let entry_point_deploy_item = DeployItemBuilder::new()
.with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT})
.with_authorization_keys(&[account_addr_1, account_addr_2])
.with_address(account_addr_1)
.with_session_code(session_code, session_args)
.build();

let entry_point_request =
ExecuteRequestBuilder::from_deploy_item(entry_point_deploy_item).build();

builder.exec(entry_point_request).commit().expect_failure();

let error = builder.get_error().expect("must have User error: 0");
assert_expected_error(
error,
0,
"should fail execution since ACCOUNT_USER_2 as associated key is not in installer (DEFAULT_ACCOUNT_ADDR) associated keys",
);

Multi-Signature Workflow

The purpose of this tutorial is to provide an example of how to integrate key management on Casper accounts. This guide assumes previous completion of the Two-Party Multi-Signature Deploys tutorial, among other prerequisites. You will also need the Casper CLI client to use the make-deploy, sign-deploy, and send-deploy Casper CLI client commands.

danger

Understanding the multi-sig feature and trying it out on Testnet before using it on Mainnet is essential. Incorrect account configurations could render accounts unusable, and you could lose access to all the corresponding CSPR tokens.

Prerequisites

The following prerequisites are required for this workflow:

  1. Set up all the development environment prerequisites, including a funded account and the Casper CLI client
  2. Complete the Two-Party Multi-Signature Deploys workflow and set up the source account for multi-signature deploys
  3. Understand the Casper account-based model before proceeding

Session Code Required for Key Management

To manage an account's associated keys and thresholds, you must run session code that executes within the account's context. Note that the session code provided in this workflow is not a general-purpose program and needs to be modified for each use case.

caution

Do not run these examples on Mainnet. Update each command for your environment.

Tutorial Workflow

Step 1: Clone the example Wasm for this workflow

The multi-sig GitHub repository contains session code that can be used for learning how to configure Casper accounts using associated keys and multi-signature deploys. Clone the repository and navigate to the corresponding folder.

git clone https://github.com/casper-ecosystem/tutorials-example-wasm/ && cd multi-sig

If you take a look at the repository structure and open the contracts folder, you will see session code with different functionality:

  • add_account.wasm - adds an associated account with a specified weight
  • update_associated_keys.wasm - updates a key’s weight
  • update_thresholds.wasm - updates the account's action thresholds for deployment and account management
  • remove_account.wasm - removes an associated account from the primary account

Step 2: Build the sample Wasm provided

Prepare your environment, build and test the session code provided with the following commands:

rustup update
make prepare
make test
  • rustup update - checks and updates your Rust installation
  • make prepare - sets the Wasm target
  • make test - builds and verifies the session code

Note that in the test folder there is a contract.wasm that is needed for the tests to pass. If you run make clean that file will be deleted.

Step 3: Increase the primary key's weight to set thresholds

This workflow starts by increasing the weight of the primary key from 1 to 3. To make account updates, a key's weight must equal or exceed the key_management threshold. In a later step, you will add the associated accounts that will participate in signing deploys.

Retrieve the account hash of the primary key you are working with using a block explorer or the Casper CLI client.

casper-client account-address --public-key <INSERT_PUBLIC_KEY_HEX>

Update the weight of the primary key to 3 by calling the update_associated_keys.wasm.

casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \
--chain-name "casper-test" \
--payment-amount 500000000 \
--secret-key $PATH/secret_key.pem \
--session-path target/wasm32-unknown-unknown/release/update_associated_keys.wasm \
--session-arg "associated_key:key='account-hash-<ACCOUNT_HASH>'" \
--session-arg "new_weight:u8='3'"

Verify that the deploy ran successfully.

casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ <DEPLOY_HASH>

Retrieve the latest state root hash and check the primary account details.

casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/

casper-client query-global-state \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash <STATE_ROOT_HASH> \
--key account-hash-<PRIMARY_ACCOUNT_HASH>

The primary key in this account should now have weight 3.

Account details
"Account": {
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"weight": 3
}
],
"main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",
"named_keys": []
}

The table below summarizes the updates.

Threshold / KeyPrevious weightCurrent weight
deployment11
key_management11
Primary key (1ed5...)13

Step 4: Update the account's action thresholds

Set up a multi-signature scheme for the account by updating the deployment and key_management thresholds. The update_thresholds.wasm will take two arguments and set the deployment threshold to 2 and the key_management threshold to 3.

casper-client put-deploy \
--node-address https://rpc.testnet.casperlabs.io \
--chain-name casper-test \
--payment-amount 500000000 \
--secret-key $PATH/secret_key.pem \
--session-path target/wasm32-unknown-unknown/release/update_thresholds.wasm \
--session-arg "deployment_threshold:u8='2'" \
--session-arg "key_management_threshold:u8='3'"

Verify that the deploy ran successfully.

casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ <DEPLOY_HASH>

Retrieve the latest state root hash and check the primary account details.

casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/

casper-client query-global-state \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash <STATE_ROOT_HASH> \
--key account-hash-<PRIMARY_ACCOUNT_HASH>

The account's action thresholds should look like this:

"action_thresholds": {
"deployment": 2,
"key_management": 3
},

This account configuration requires a cumulative weight of 3 to manage keys and a cumulative weight of 2 to send deploys. For example, if two associated keys have weight 1, they must both sign and send the deploy as part of this account context. The cumulative weight of these two keys would not meet the threshold for key management.

Account details
"Account": {
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"action_thresholds": {
"deployment": 2,
"key_management": 3
},
"associated_keys": [
{
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"weight": 3
}
],
"main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",
"named_keys": []
}

The table below summarizes the updates.

Threshold / KeyPrevious weightCurrent weight
deployment12
key_management13
Primary key (1ed5...)13

Step 5: Add associated keys to the primary account

To add an associated key to the primary account, use the add_account.wasm provided. This example adds two keys to the primary account (account-hash-d89c*): user_1 with account-hash-e2d0*, and user_2 with account-hash-04a9*.

casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \
--chain-name "casper-test" \
--payment-amount 500000000 \
--secret-key $PATH/secret_key.pem \
--session-path target/wasm32-unknown-unknown/release/add_account.wasm \
--session-arg "new_key:key='account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7" \
--session-arg "weight:u8='1'"

Verify that the deploy ran successfully.

casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ <DEPLOY_HASH>
casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \
--chain-name "casper-test" \
--payment-amount 500000000 \
--secret-key $PATH/secret_key.pem \
--session-path target/wasm32-unknown-unknown/release/add_account.wasm \
--session-arg "new_key:key='account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f" \
--session-arg "weight:u8='1'"

Verify that the deploy ran successfully.

casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ <DEPLOY_HASH>

Retrieve the latest state root hash and check the primary account details.

casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/

casper-client query-global-state \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash <STATE_ROOT_HASH> \
--key account-hash-<PRIMARY_ACCOUNT_HASH>

Now, the account should have one primary key with weight 3, and two associated accounts, each with weight 1.

Account details
"Account": {
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"action_thresholds": {
"deployment": 2,
"key_management": 3
},
"associated_keys": [
{
"account_hash": "account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f",
"weight": 1
},
{
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"weight": 3
},
{
"account_hash": "account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7",
"weight": 1
}
],
"main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",
"named_keys": []
}
note
  1. All associated keys should be kept incredibly secure to ensure the security and integrity of the account.
  2. After all associated keys and action thresholds have been set to the desired multi-signature scheme, the weight of the original primary key can be increased or lowered, depending on your use case. Be careful with this! If you lower the primary key's weight below the key management threshold, the account will require multiple signatures for key management. The account will be unusable if you do not have enough associated keys set up.

The table below summarizes the updates.

Threshold / KeyPrevious weightCurrent weight
deployment12
key_management13
Primary key (1ed5...)13
Associated key (04a9...)N/A1
Associated key (e2d0...)N/A1

Step 6: Send a deploy from the primary account

This step sends a deploy containing Wasm (contract.wasm), which adds a named key to the account. The source code for the Wasm comes from the hello-world repository. The deploy should succeed as the primary account has a weight of 3, which is greater than the deployment threshold.

casper-client put-deploy --chain-name casper-test \
--payment-amount 3000000000 \
--session-path tests/wasm/contract.wasm \
--secret-key $PATH/secret_key.pem \
--session-arg "my-key-name:string='primary_account_key'" \
--session-arg "message:string='Hello, World'"

Verify that the deploy ran successfully.

casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ <DEPLOY_HASH>

Retrieve the latest state root hash and check the primary account details.

casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/

casper-client query-global-state \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash <STATE_ROOT_HASH> \
--key account-hash-<PRIMARY_ACCOUNT_HASH>

The hello_world.wasm should have run and added a named key to the account.

"named_keys": [
{
"key": "uref-9b9ecaa9e5e235fc6955d4d528cb1b5b38f2d800f6cbbc55351131a3701b5a81-007",
"name": "my-key-name"
}
]

Step 7: Send a multi-signature deploy from an associated key

Given the multi-signature scheme set up in this example, two associated keys need to sign to send a deploy from one of the associated keys. This example uses the following commands to sign a deploy with multiple keys and send it to the network:

  • make-deploy - creates and signs a deploy, saving the output to a file
  • sign-deploy - adds additional signatures for a multi-signature deploy
  • send-deploy - sends the deploy to the network

Similar to step 6, this example uses Wasm (contract.wasm), which adds a named key to the account. The deploy originates from the primary account, specified with the --session-account argument. The deploy needs two signatures to meet the deployment weight equal to 2. Once both associated keys sign the deploy, either can send it to the network.

When using the --session-account argument, specify the hex-encoded public key of the primary account context under which the session code will be executed.

One associated key creates and signs the deploy with the make-deploy command, indicating the account context under which the session code will be executed.

casper-client make-deploy --chain-name casper-test \
--payment-amount 300000000 \
--session-path tests/wasm/contract.wasm \
--secret-key $PATH/user_1_secret_key.pem \
--session-arg "my-key-name:string='user_1_key'" \
--session-arg "message:string='Hello, World'" \
--session-account 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986 \
--output hello_world_one_signature

The second associated key signs the deploy with sign-deploy to meet the deployment threshold for the account.

casper-client sign-deploy -i hello_world_one_signature -k $PATH/user_2_secret_key.pem  -o hello_world_two_signatures

The deploy can be sent to the network using the send-deploy command:

casper-client send-deploy --node-address https://rpc.testnet.casperlabs.io -i hello_world_two_signatures

Verify that the deploy ran successfully.

casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ <DEPLOY_HASH>

Retrieve the latest state root hash and check the primary account details.

casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/

casper-client query-global-state \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash <STATE_ROOT_HASH> \
--key account-hash-<PRIMARY_ACCOUNT_HASH>

The hello_world.wasm should have run and added a named key to the account.

Removing a Compromised Key

This example shows how to remove a compromised key from an account. The example adds an associated key only to remove it using the remove_account.wasm session code.

caution

Remove keys with caution! Do not run this example on Mainnet.

Before removing a key, ensure the remaining associated keys can combine their weight to meet the threshold for key management. Otherwise, the account could become unusable. Changing key weights or adding new associated keys would only be possible by meeting the key management threshold. Proceed with caution.

Given the current setup, the primary account will add an associated key, and then remove it. In other use cases, associated keys may need to combine their signatures to send a multi-sig deploy that removes a key.

casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \
--chain-name "casper-test" \
--payment-amount 500000000 \
--secret-key $PATH/secret_key.pem \
--session-path target/wasm32-unknown-unknown/release/add_account.wasm \
--session-arg "new_key:key='account-hash-1fed34baa6807a7868bb18f91b161d99ebf21763810fe4c92e39775d10bbf1f8" \
--session-arg "weight:u8='1'"

Verify that the deploy ran successfully.

casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ <DEPLOY_HASH>

Retrieve the latest state root hash and check the primary account details.

casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/

casper-client query-global-state \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash <STATE_ROOT_HASH> \
--key account-hash-<PRIMARY_ACCOUNT_HASH>
Account details
"Account": {
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"action_thresholds": {
"deployment": 2,
"key_management": 3
},
"associated_keys": [
{
"account_hash": "account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f",
"weight": 1
},
{
"account_hash": "account-hash-1fed34baa6807a7868bb18f91b161d99ebf21763810fe4c92e39775d10bbf1f8",
"weight": 1
},
{
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"weight": 3
},
{
"account_hash": "account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7",
"weight": 1
}
],
"main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",
"named_keys": []
}

The table below summarizes the updates after calling the add_account.wasm.

Threshold / KeyPrevious weightCurrent weight
deployment12
key_management13
Primary key (1ed5...)13
Associated key (04a9...)11
Associated key (e2d0...)11
Associated key (1fed...)N/A1

The remove_account.wasm will remove the newly added account to demonstrate the possibility of removing associated keys that may have been compromised.

casper-client put-deploy --node-address https://rpc.testnet.casperlabs.io/ \
--chain-name "casper-test" \
--payment-amount 500000000 \
--secret-key $PATH/secret_key.pem \
--session-path target/wasm32-unknown-unknown/release/remove_account.wasm \
--session-arg "remove_key:key='account-hash-1fed34baa6807a7868bb18f91b161d99ebf21763810fe4c92e39775d10bbf1f8"

Verify that the deploy ran successfully.

casper-client get-deploy --node-address https://rpc.testnet.casperlabs.io/ <DEPLOY_HASH>

Retrieve the latest state root hash and check the primary account details.

casper-client get-state-root-hash --node-address https://rpc.testnet.casperlabs.io/

casper-client query-global-state \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash <STATE_ROOT_HASH> \
--key account-hash-<PRIMARY_ACCOUNT_HASH>

The resulting account should not contain the associated key that was just removed.

Account details
"Account": {
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"action_thresholds": {
"deployment": 2,
"key_management": 3
},
"associated_keys": [
{
"account_hash": "account-hash-04a9691a9f8f05a0f08bd686f188b27c7dbcd644b415759fd3ca043d916ea02f",
"weight": 1
},
{
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"weight": 3
},
{
"account_hash": "account-hash-e2d00525cac31ae2756fb155f289d276c6945b6914923fe275de0cb127bffee7",
"weight": 1
}
],
"main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",
"named_keys": []
}

The table below summarizes the updates after calling the remove_account.wasm.

Threshold / KeyPrevious weightCurrent weight
deployment12
key_management13
Primary key (1ed5...)13
Associated key (04a9...)11
Associated key (e2d0...)11
Associated key (1fed...)1N/A (Removed)

Next Steps

The next section contains additional examples where Casper's multi-signature feature would be helpful.

Additional Examples

This section presents examples of single and multi-signature schemes, where accounts have multiple associated keys and thresholds for signing transactions.

Example 1: An account with a single (primary) key

In this example, only one key (account-hash-a1…) can sign transactions in the name of this account. This key is the primary key of the account and has a weight equal to 1. For deployments or key management, the weight required is also 1. Therefore, the key meets the deployment and key management thresholds and can perform both actions.

Account details in example 1:

"Account": {
"account_address": "account-hash-a1…",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_address": "account-hash-a1…", // primary key
"weight": 1
}
],
"main_purse": "uref-1234…",
"named_keys": []
}

Example 2: An account with primary and associated keys

In this example, the account has a primary key with weight 2 and an associated key with a lower weight for signing deploys. The primary key can perform account updates and deploys, while the associated key can only sign deploys.

Account details in example 2:

"Account": {
"account_address": "account-hash-a1…",
"action_thresholds": {
"deployment": 1,
"key_management": 2
},
"associated_keys": [
{
"account_address": "account-hash-a1…", // primary key for key management
"weight": 2
},
{
"account_address": "account-hash-b2…", // associated key used for deploys
"weight": 1
}
],
"main_purse": "uref-1234…",
"named_keys": []
}

Example 3: Multi-sig setup for deploys and account updates

The following account has associated keys that can manage the account and send deploys independently of the primary key. The two associated keys have a cumulative weight of 2, which meets the deployment and key management thresholds. Both keys must sign the deploy to make updates.

Account details in example 3:

"Account": {
"account_address": "account-hash-a1…",
"action_thresholds": {
"deployment": 2,
"key_management": 2
},
"associated_keys": [
{
"account_address": "account-hash-a1…", // primary key
"weight": 2
},
{
"account_address": "account-hash-b2…", // associated key
"weight": 1
},
{
"account_address": "account-hash-c3…", // associated key
"weight": 1
}
],
"main_purse": "uref-1234…",
"named_keys": []
}

Example 4: Signing deploys but restricting account updates

This scenario builds on the previous example. The account has a primary key with a weight of 3, equal to the key management threshold, and two associated keys with a cumulative weight of 2, for signing deploys. The associated keys can sign deploys but not make account updates because they do not meet the key management threshold. Only the primary key can update the account. If the primary key is lost or compromised, the entire account becomes compromised because the associated keys do not have enough cumulative weight to remove the compromised key.

Account details in example 4:

"Account": {
"account_address": "account-hash-a1…",
"action_thresholds": {
"deployment": 2,
"key_management": 3
},
"associated_keys": [
{
"account_address": "account-hash-a1…", // primary key
"weight": 3
},
{
"account_address": "account-hash-b2…", // associated key
"weight": 1
},
{
"account_address": "account-hash-c3…", // associated key
"weight": 1
}
],
"main_purse": "uref-1234…",
"named_keys": []
}

Example 5: Recovering a lost primary key

This account has a primary key with a weight of 3, equal to the key management threshold, and three associated keys with a cumulative weight of 3. Two associated keys can combine their weight to sign deploys. All three associated keys can combine their weight to make account updates. If the primary key is lost or compromised, the associated keys can remove it and secure the account.

Account details in example 5:

"Account": {
"account_address": "account-hash-a1…",
"action_thresholds": {
"deployment": 2,
"key_management": 3
},
"associated_keys": [
{
"account_address": "account-hash-a1…", // primary key
"weight": 3
},
{
"account_address": "account-hash-b2…", // associated key
"weight": 1
},
{
"account_address": "account-hash-c3…", // associated key
"weight": 1
},
{
"account_address": "account-hash-d4…", // associated key
"weight": 1
}
],
"main_purse": "uref-1234…",
"named_keys": []
}

Casper-Client Commands

State Root Hash

casper-client get-state-root-hash --node-address [NODE_SERVER_ADDRESS]

Example:

casper-client get-state-root-hash --node-address http://[IP]:7777

You can find a list of Testnet IP addresses at CSPR live.

The first command to cover is the get-state-root-hash command from the casper-client tool. The state root hash is an identifier of the current network state. It is similar to a Git commit ID for commit history. It gives a snapshot of the blockchain state at a moment in time. For this tutorial, it will be used to query the network state after sending deploys.

note

After sending deploys to the network, you must get the new state root hash to see the changes reflected. Otherwise, you will be looking at events in the past.

Querying Network State

casper-client query-global-state \
--node-address [NODE_SERVER_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] \
-q "[SESSION_NAME]/[SESSION_NAMED_KEY]" (OPTIONAL)

This command allows you to query the state of a Casper network at a given moment in time, which is specified by the state-root-hash described above.

  • The node-address is the server on the network.
  • The key is the identifier for the query. It must be either the account public key, account hash, contract address hash, transfer hash, or deploy hash. The tutorial demonstrates two of these key types.
  • The optional query path argument (q) allows you to drill into the specifics of a query concerning the key.

Put Deploys (onto the Chain)

Deploy via a compiled Wasm binary

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name casper-test \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path [CONTRACT_PATH]/counter-v1.wasm

This command creates a deploy and sends it to the network for execution. In this first usage of the command,

  • The session-path points to a compiled Wasm contract.
  • This contract is then installed on the network specified by the chain-name. The Testnet is "casper-test" but this is configurable.
  • The payment-amount is in units of motes (1 nano-CSPR) and is required to pay the transaction fee for the deploy. If it is too small, the transaction will get denied due to insufficient funds.

Deploy via a named key already on the blockchain

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name casper-test \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-name "counter" \
--session-entry-point "counter_inc"

This second usage of put-deploy does not place a new contract on the chain, but it allows you to call entry points (functions) defined in smart contracts.

This examples uses "counter" and "counter_inc" from the tutorial walkthrough. However, these will be different when you write your contracts.

Get Deploys (from the Chain)

casper-client get-deploy \
--node-address [NODE_SERVER_ADDRESS] \
[DEPLOY_HASH]

The get-deploy command is complementary to the put-deploy command. It retrieves a deploy from the network and allows you to check the status of the deploy. The DEPLOY_HASH is the identifier to a specific deploy and is returned by the put-deploy command.

Overview

This flowchart outlines the process you will go through in this tutorial. Since there are quite a few things taking place, you must keep in mind the overall flow as you proceed through the tutorial on your own.

To summarize the flowchart, this tutorial will walk you through installing a contract on the blockchain and then calling two separate contract entry points to increment a counter variable. Along the way, you will learn how to query the network state to see when the network has successfully incremented the counter.

image

Tutorial Walkthrough

Now that you are familiar with the basic commands, you can begin the tutorial walkthrough.

Clone the Repository

First, you will need to clone the counter contract repository on our local machine.

git clone https://github.com/casper-ecosystem/counter

If you explore the source code, you will see that there are two versions of the counter contract and one file with session code that calls the contract's entry-points:

  • contract-v1

    • This is the first version of the counter contract.
    • Defines two named keys: counter to reference the contract and an associated variable count to store a value.
    • Provides a function to get the current count (count_get).
    • Provides a function to increment the current count (counter_inc).
  • contract-v2

    • This is a second version of the counter contract, which will not be used in this tutorial.
    • This version provides an additional function to decrement the counter and to demonstrate contract upgrades in another tutorial.
  • counter-call

  • This is session code that retrieves the contract-v1 contract, gets the current count value, increments it, and ensures the count was incremented by 1.

View the Network State

With a network up and running, you can use the casper-client query-global-state command to check the status of the network. However, you first need an account hash and the state-root-hash so that you can get the current snapshot. Once you have that information, you can check the status of the network.

You will need to use the following three commands:

  1. casper-client account-address --public-key [PATH_TO_PUBLIC_KEY] - Get the account-hash
  2. casper-client get-state-root-hash - Get the state-root-hash
  3. casper-client query-state - Query the network state

Run through these commands in order.

casper-client account-address --public-key [PATH_TO_PUBLIC_KEY]

You will need to specify the location of your public-key files. If you used the block explorer to generate the keys, you will need to download them first.

Next, get the state-root-hash:

casper-client get-state-root-hash --node-address http://[NODE_IP]:7777

You need to use the IP address of one of the connected peers on the Testnet as the node server since the network is running in a decentralized fashion. Make a note of the returned state root hash, but keep in mind that this hash value will need to be updated every time you modify the network state.

Finally, query the actual state:

casper-client query-global-state \
--node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH]

Substitute the state root hash and account hash values you just retrieved into this command and execute it. Do not be surprised if you see nothing on the network. That is because you have not sent anything to the network yet.

Install the Contract

Before installing the contract on the chain, you will need to compile it to Wasm.

The Makefile included in the repository makes compilation trivial. With these two commands, you can build (in release mode) and test the contract before installing it. make prepare sets the Wasm target and make test builds the contracts and verifies them.

cd counter
make prepare
make test

With the compiled contract, you can call the casper-client put-deploy command to install the contract on the chain.

casper-client put-deploy \
--node-address http://[NODE_IP]:7777 \
--chain-name casper-test \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path ./contract-v1/target/wasm32-unknown-unknown/release/counter-v1.wasm
  • Replace the [PATH_TO_YOUR_KEY] field with the actual path of where your secret key is stored.
  • The session-path argument should point to wherever you compiled the counter-v1.wasm on your computer. The code snippet shows you the default path if the counter folder is in the same directory.

Once you call this command, it will return a deploy hash. You can use this hash to verify that the deploy successfully took place.

casper-client get-deploy \
--node-address http://[NODE_IP]:7777 [DEPLOY_HASH]

View the Updated Network State

Hopefully, the deploy was successful. Call the casper-client query-global-state command to check if the named key is visible on the chain.

note

You must get the new state root hash since you just wrote a deploy to the chain.

If you run these two commands, there will be a new counter named key on the chain.

Get the NEW state-root-hash:

casper-client get-state-root-hash --node-address http://[NODE_IP]:7777

Get the network state:

casper-client query-global-state \
--node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH]

You can actually dive further into the data stored on the chain using the query path argument or directly querying the deploy hash. Try the following commands and notice that each one gives you a different level of detail.

Retrieve the specific counter contract details:

casper-client query-global-state --node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] -q "counter"

Retrieve the specific count value:

casper-client query-global-state --node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] -q "counter/count"

Retrieve the specific deploy details:

casper-client query-global-state --node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH] --key deploy-[DEPLOY_HASH]

The first two commands access the counter and count named keys, respectively, using the query path argument. The third command uses the deploy hash (the return value of put-deploy) to query the state of that specific deploy only.

Increment the Counter

You now have a counter on the chain, and you can increment it by calling the entry-point counter_inc, the function defined in the contract. You can call an entry-point in an installed contract by using the put-deploy command as illustrated here:

casper-client put-deploy \
--node-address http://[NODE_IP]:7777 \
--chain-name casper-test \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-name "counter" \
--session-entry-point "counter_inc"

Notice that this command is nearly identical to the command used to deploy the contract. However, instead of session-path pointing to the Wasm binary, you have session-name and session-entry-point identifying the on-chain contract and its associated entry-point to execute.

View the Updated Network State Again

After calling the entry-point, theoretically, the count value should increment by one, but how can you be sure of that? You can query the network again, however, remember that you have to get a new state root hash. Check if the count was incremented by looking at it with the query argument.

Get the NEW state-root-hash:

casper-client get-state-root-hash --node-address http://[NODE_IP]:7777

Get the network state, specifically for the count variable this time:

casper-client query-global-state --node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] -q "counter/count"

You should be able to see the count value and observe that it has increased.

Increment the Counter Again

If you recall, in the repository there is session code called counter-call. Try to increment the count using that session code instead of the session entry-point used above.

Keep in mind, this is another put-deploy call just like when you installed the contract. The session-path is once again going to be different for you depending on where you compiled the contract.

casper-client put-deploy \
--node-address http://[NODE_IP]:7777 \
--chain-name casper-test \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path ./counter/target/wasm32-unknown-unknown/release/counter-call.wasm

View the Final Network State

To make sure that the session code ran successfully, get the new state root hash and query the network.

casper-client get-state-root-hash --node-address http://[NODE_IP]:7777

Get the network state, specifically for the count variable this time:

casper-client query-global-state --node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH]
--key [ACCOUNT_HASH] -q "counter/count"

If all went according to plan, your count value should be 2 at this point.

Congratulations on building, installing, and using a smart contract on the Testnet!

Casper-Client Commands

Faucet Account Information

nctl-view-faucet-account

This command is part of NCTL and provides a view into the faucet account details. The faucet is the default account created on the network. Generally on the Mainnet, your own account is used to fund transactions. However, for the sake of this tutorial, you do not need accounts and will use the faucet to execute deploys. This command supplies two key pieces of information: the account's secret key location and the account hash, which are used to sign deploys and query the network state, respectively.

State Root Hash

casper-client get-state-root-hash --node-address [NODE_SERVER_ADDRESS]

The first command to cover is the get-state-root-hash command from the casper-client tool. The state root hash is an identifier of the current network state. It is similar to a Git commit ID for commit history. It gives a snapshot of the blockchain state at a moment in time. For this tutorial, it will be used to query the network state after sending deploys.

note

After sending deploys to the network, you must get the new state root hash to see the new changes reflected. Otherwise, you will be looking at events in the past.

Querying Network State

casper-client query-global-state \
--node-address [NODE_SERVER_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] \
-q "[SESSION_NAME]/[SESSION_NAMED_KEY]" (OPTIONAL)

This command allows you to query the state of a Casper network at a given moment in time, which is specified by the state-root-hash described above.

  • The node-address is the location of the RPC endpoint, which is typically represented in the form http://IP:PORT. In this particular tutorial, for a default-configured NCTL network running locally, the address you can use is http://localhost:11101.
  • The key is the identifier for the query. It must be either the account public key, account hash, contract address hash, transfer hash, or deploy hash. The tutorial demonstrates two of these key types.
  • The optional query path argument (q) allows you to drill into the specifics of a query concerning the key.

Put Deploys (onto the Chain)

Deploy via a compiled Wasm binary

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name casper-net-1 \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path [CONTRACT_PATH]/counter-v1.wasm

This command creates a deploy and sends it to the network for execution. In this first usage of the command,

  • The session-path points to a compiled Wasm contract.
  • This contract is then installed on the network specified by the chain-name. By default, NCTL names the chain "casper-net-1" but this is configurable.
  • The payment-amount is in units of motes (1 nano-CSPR) and is required to pay the transaction fee for the deploy. If it is too small, the transaction will get denied due to insufficient funds.

Deploy via a named key already on the blockchain

casper-client put-deploy \
--node-address [NODE_SERVER_ADDRESS] \
--chain-name casper-net-1 \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-name "counter" \
--session-entry-point "counter_inc"

This second usage of put-deploy does not place a new contract on the chain, but it allows you to call entry points (functions) defined in smart contracts.

This examples uses "counter" and "counter_inc" from the tutorial walkthrough. However, these will be different when you write your contracts.

Get Deploys (from the Chain)

casper-client get-deploy \
--node-address [NODE_SERVER_ADDRESS] \
[DEPLOY_HASH]

The get-deploy command is complementary to the put-deploy command. It retrieves a deploy from the network and allows you to check the status of the deploy. The DEPLOY_HASH is the identifier to a specific deploy and is returned by the put-deploy command.

Overview

This flowchart outlines the process you will go through in this tutorial. Since there are quite a few things taking place, you must keep in mind the overall flow as you proceed through the tutorial on your own.

To summarize the flowchart, this tutorial will walk you through installing a contract on the blockchain and then calling two separate contract entry points to increment a counter variable. Along the way, you will learn how to query the network state to see when the network has successfully incremented the counter.

image

Tutorial Walkthrough

Now that you are familiar with the basic commands, you can begin the tutorial walkthrough.

Clone the Repository

First, you will need to clone the counter contract repository on our local machine.

git clone https://github.com/casper-ecosystem/counter

If you explore the source code, you will see that there are two versions of the counter contract and one file with session code that calls the contract's entry-points:

  • contract-v1

    • This is the first version of the counter contract.
    • Defines two named keys: counter to reference the contract and an associated variable count to store a value.
    • Provides a function to get the current count (count_get).
    • Provides a function to increment the current count (counter_inc).
  • contract-v2

    • This is a second version of the counter contract, which will not be used in this tutorial.
    • This version provides an additional function to decrement the counter and to demonstrate contract upgrades in another tutorial.
  • counter-call

    • This is session code that retrieves the contract-v1 contract, gets the current count value, increments it, and ensures the count was incremented by 1.

Create a Local Network

After getting familiar with the counter source code, you need to create a local Casper network to install the contract. If you completed the NCTL tutorial, all you need to do is allocate the network assets and then start the network.

If you run the following line in your terminal, you should be able to spin up a network effortlessly.

nctl-assets-setup && nctl-start
note

If it fails for any reason, please refer the NCTL tutorial and make sure that all your packages are up to date.

View the Network State

With a network up and running, you can use the casper-client query-global-state command to check the status of the network. However, you first need an AccountHash and the state-root-hash so that you can get the current snapshot. Once you have that information, check the status of the network.

You will need to use the following three commands:

  1. nctl-view-faucet-account - Get the faucet's account hash
  2. casper-client get-state-root-hash - Get the state root hash
  3. casper-client query-global-state - Get the network state

Run through these commands in order.

nctl-view-faucet-account

If NCTL is correctly up and running, this command should return quite a bit of information about the faucet account. Feel free to look through the records and make a note of the account-hash field and the secret_key.pem path because you will often use both.

Get the state root hash:

casper-client get-state-root-hash --node-address http://localhost:11101

You are using localhost as the node server since the network is running on our local machine. Make a note of the state-root-hash that is returned, but keep in mind that this hash value will need to be updated every time you modify the network state.

Finally, query the actual state:

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH]

Substitute the state root hash and account hash values you just retrieved into this command and execute it. Do not be surprised if you see nothing on the network. That is because you have not sent anything to the network yet.

Install the Contract

Before installing the contract on the chain, you will need to compile it to Wasm.

The Makefile included in the repository makes compilation trivial. With these two commands, you can build (in release mode) and test the contract before installing it. make prepare sets the Wasm target and make test builds the contracts and verifies them.

cd counter
make prepare
make test

With the compiled contract, you can call the casper-client put-deploy command to install the contract on the chain.

casper-client put-deploy \
--node-address http://localhost:11101 \
--chain-name casper-net-1 \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path ./contract-v1/target/wasm32-unknown-unknown/release/counter-v1.wasm
  • Replace the [PATH_TO_YOUR_KEY] field with the actual path of where your secret key is stored. It is one of the fields that gets returned when you call nctl-view-faucet-account.
  • The session-path argument should point to wherever you compiled the counter-v1.wasm on your computer. The code snippet shows you the default path if the counter folder is in the same directory.

Once you call this command, it will return a deploy hash. You can use this hash to verify that the deploy successfully took place.

casper-client get-deploy \
--node-address http://localhost:11101 [DEPLOY_HASH]

View the Updated Network State

Hopefully, the deploy was successful. Call the casper-client query-global-state command to check if the named key is visible on the chain.

note

You must get the new state root hash since you just wrote a deploy to the chain.

If you run these two commands, there will be a new counter named key on the chain.

Get the NEW state-root-hash:

casper-client get-state-root-hash --node-address http://localhost:11101

Get the network state:

casper-client query-global-state \
--node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH]

You can actually dive further into the data stored on the chain using the query path argument or directly querying the deploy hash. Try the following commands and notice that each one gives you a different level of detail.

Retrieve the specific counter contract details:

casper-client query-global-state --node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] -q "counter"

Retrieve the specific count value:

casper-client query-global-state --node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] -q "counter/count"

Retrieve the specific deploy details:

casper-client query-global-state --node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH] --key deploy-[DEPLOY_HASH]

The first two commands access the counter and count named keys, respectively, using the query path argument. The third command uses the deploy hash (the return value of put-deploy) to query the state of that specific deploy only.

Increment the Counter

You now have a counter on the chain, and you can increment it by calling the entry-point counter_inc, the function defined in the contract. You can call an entry-point in an installed contract by using the put-deploy command as illustrated here:

casper-client put-deploy \
--node-address http://localhost:11101 \
--chain-name casper-net-1 \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-name "counter" \
--session-entry-point "counter_inc"

Notice that this command is nearly identical to the command used to install the contract. However, instead of session-path pointing to the Wasm binary, you have session-name and session-entry-point identifying the on-chain contract and its associated entry-point to execute.

View the Updated Network State Again

After calling the entry-point, theoretically, the count value should increment by one, but how can you be sure of that? You can query the network again, however, remember that you have to get a new state root hash. Check if the count was incremented by looking at it with the query argument.

Get the NEW state-root-hash:

casper-client get-state-root-hash --node-address http://localhost:11101

Get the network state, specifically for the count variable this time:

casper-client query-global-state --node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] -q "counter/count"

You should be able to see the count value and observe that it has increased.

Increment the Counter Again

If you recall, in the repository there is session code called counter-call. Try to increment the count using that session code instead of the session entry-point used above.

Keep in mind, this is another put-deploy call just like when you installed the contract. The session-path is once again going to be different for you depending on where you compiled the contract.

casper-client put-deploy \
--node-address http://localhost:11101 \
--chain-name casper-net-1 \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path ./counter/counter-call/target/wasm32-unknown-unknown/release/counter-call.wasm

View the Final Network State

To make sure that the session code ran successfully, get the new state root hash and query the network.

casper-client get-state-root-hash --node-address http://localhost:11101

Get the network state, specifically for the count variable this time:

casper-client query-global-state --node-address http://localhost:11101 \
--state-root-hash [STATE_ROOT_HASH]
--key [ACCOUNT_HASH] -q "counter/count"

If all went according to plan, your count value should be 2 at this point.

Congratulations on building, installing, and using a smart contract on your local network!

Ecosystem Open-Source Software

This page lists open-source software available within the Casper ecosystem. Developers and the community may use the listed software as a basis for new projects and solutions.

NameDescriptionAuthorLanguageLicenseLast Update DateType
Basic Yield FarmStaking RewardsRengo LabsRustApache-2.0 license2022-06-24Staking
Blockcerts on CasperIssues Blockcerts using the Bitcoin, Ethereum, or Casper blockchainamazanzanPythonMIT license2022-07-22Tokens
BlockMatcher Frontend BackendPrivate Trade (OTC) Platform for Compliant Brokers. This system allows the creation of OTC token deals, matching buyers and sellers together. The admin, or broker, can then clear them in batches.LedgerLeapJavaScript-PHPMIT license2022-01-15Exchange
Camel CasperApache Camel connector for the Casper BlockchainM.AbahmaneJavaMIT license2022-03-26Tools
Casper .NET SDKCasper .NET Client SDK to interact with Casper network nodes via RPC.MAKE Software.NETApache-2.0 license2022-04-19Client SDK
Casper Analytics AppCasper Analytics App. Built with Ionic. Easily exportable as iOS and Andriod Appcaspercommunity.ioPHPMIT license2022-01-20Tools
Casper C++ SDKC++ library to interact with Casper network nodes via RPCYusuf KetenC++Apache-2.0 license2022-09-13Client SDK
Casper CalculatorCasper Earnings Calculator and Node MonitorCharles NguyenJavaScriptMIT license2021-09-26Tools
Casper Contract UpgradeExample contract to demonstrate the general way of upgrading a contract and the necessary stepsCasper LabsRustApache-2.0 license2022-06-21Example Contracts
Casper Dart SDKCasper Dart SDK is for interacting with the Casper Blockchain using RPC.TemiltasDartApache-2.0 license2022-06-26Client SDK
Friendly Market's Casper variant of ERC20Implementation of the ERC20 standard for Casper networksFriendly MarketRustApache-2.0 license2022-08-10Tokens
Casper Go SDKCasper Go SDKMAKE SoftwareGoApache-2.0 license2023-06-01Client SDK
Casper Hello World ContractThis example demonstrates the session code that accepts a message string and stores it in the calling account under the special_value NamedKeyCasper LabsRustNA2022-07-13Example contracts
Casper JavaScript SDKCasper Client JavaScript SDKCasper LabsTypeScript-JavaScriptApache-2.0 license2022-09-13Client SDK
Casper Kotlin SDKCasper Kotlin Client SDK to interact with a Casper network.tqhuy2018KotlinMIT license2022-07-21Client SDK
Casper MetricsCasper Metrics - fast blockchain crawler, API, and analysis toolA3MCTypeScriptMIT license2022-09-09Tools
Casper NCTL DockerA Docker container that runs Casper NCTL as a serviceMAKE SoftwareShellApache-2.0 license2022-03-17Tools
Casper Node-REDNodes to communicate with the Casper's Blockchain using node-redcaspercommunity.ioJavaScriptMIT license2022-02-08Tools
Casper Objective-C SDKCasper Objective-C SDK is for interacting with the Casper Blockchain using RPC.hienbui9999Objective-CMIT license2022-06-18Client SDK
Casper PHP SDKPHP SDK to interact with Casper network nodes via RPC. The PHP SDK allows developers to interact with a Casper network using PHPMAKE SoftwarePHPApache-2.0 license2022-06-29Client SDK
Casper Ruby Client SDKRuby SDK to interact with Casper network nodes via RPC.Sait GulmezRubyApache-2.0 license2022-03-08Client SDK
Casper Scala SDKCasper Scala client SDK to interact with the Casper Network nodes via RPCM.AbahmaneScalaMIT license2022-03-23Client SDK
Casper WalletA browser wallet for the Casper NetworkMAKE SoftwareTypeScript-JavaScriptApache-2.0 license2023-04-12Wallet
Casper SSI Web AppCasper SSI Framework in the form of a demo web application.Credentia NetworkTypeScriptMIT license2022-06-29Tools
Casper StorageCasper storage - HD walletsCasperDashTypeScriptApache-2.0 license2022-09-14Wallet
Casper Swift SDKCasper Client SDK. Casper SDK methods implementation in Swift.hienbui9999SwiftMIT license2022-06-08Client SDK
Casper Two-Party MultiSig ContractThis example demonstrates how to configure an account on a Casper network to require two-party multi-signature deploys.Casper LabsRustNA2022-04-26Example contracts
Casper WorldCasper network status and decentralization map web applicationNodes GuruTypeScriptMIT license2022-01-26Blockchain Explorer
CasperDash WalletA non-custodial wallet for the Casper blockchainCasperDashJavaScriptMIT license2022-09-14Wallet
CasperFYRE APIDispensory API interface for Casper MainnetLedgerLeapJavaScript-PHPApache-2.0 license2022-09-06Tools
CasperHoldersFirst 3rd party UI to interact with Casper BlockchainCasperHoldersJavaScriptApache-2.0 license2022-08-23Blockchain Explorer
CasperSignThe First Casper-Native Dapp. CasperSign Allows Users to Sign Contracts Confidentially & Securely on the Casper BlockchainChronoLogic and Digital StrategiesTypeScriptNA2022-08-31dApp
CEP-78 Enhanced NFT StandardStandard Contract Generator for NFTsCasper LabsRustApache-2.0 license2022-08-23NFT
CES Rust Event EmitterRust library for smart contracts that emits contract-level events that follow the Casper Event Standard (CES)MAKE SoftwareRustApache-2.0 license2023-05-11dApp library
CES JS ParserJS library for dApp developers that parses contract-level events that follow the Casper Event Standard (CES) from deploy execution resultsMAKE SoftwareJavaScriptApache-2.0 license2023-03-27dApp library
CES Go ParserGo library for dApp developers that parses contract-level events that follow the Casper Event Standard (CES) from deploy execution resultsMAKE SoftwareGoApache-2.0 license2023-06-02dApp library
Clearest StakeStaking Asset Manager for Node operators and groupsLedgerLeapPHPApache-2.0 license2022-04-02DeFi
DAO ContractsSmart Contracts for the MVPR On-Chain Governance System on CasperMAKE SoftwareRustApache-2.0 license2022-07-17DAO
DHF PAYThe crypto currency payment gateway on the CSPR blockchainDHFinanceTypeScriptApache-2.0 license2022-08-28Payments
DLN DAODLN DAOAlphaFinTypeScriptMIT license2022-09-10DAO
DotOracleRealtime decentralized Oracle and Cross-chain liquidity network for EVM, non-EVM Casper, and L2 blockchains.DotOracle NetworkTypeScriptNA2022-09-26Bridge
Dragon’s Lair Style StakingLair Style StakingRengo LabsRustApache-2.0 license2022-06-24Staking
Subscription BillingERC-1337 subscription billingRengo LabsRustMIT license2022-04-07Tokens
Casper Fungible TokenImplementation of Fungible Tokens for Casper networksCasper LabsRustApache-2.0 license2022-09-01Tokens
Advanced Fungible TokenERC-777 + 1820 Advanced Fungible Token with Callbacks & Self IdentificationRengo LabsRustApache-2.0 license2022-08-16Tokens
Helper BotHelper bot for improving DevDao VAs productivityA3MCTypeScriptMIT license2022-08-19Tools
Java SDKCasper Client Java SDKSyntiFiJavaApache-2.0 license2021-04-20Client SDK
KYC Proxy ContactThis is a proxy contract to check if an account is KYC approved through registered providers (KYC Contracts)Casper LabsRustNA2022-07-01Example contracts
LiquidNFTNFT Collateralized LoansRengo LabsJavaScriptGNU General Public License v3.02022-09-15NFT
Payment Example ContractThis example demonstrates the usage of purses to transfer motes inside a contractCasper LabsRustNA2022-06-22Example contracts
ServicesDAOThe ServicesDAO portal provides a platform for the service DAOs which provide services in a decentralized manner through a modular implementation of MVPR.Ekon YazilimHTML-CSS-C#MIT license2022-09-13DAO
Uniswap DemoAppUniswap UI + ContractsRengo LabsJavaScriptGPL-3.0 license2022-09-15DeFi
Verified Impact NFTAn NFT platform dedicated to impact causes with verification of the beneficiariesAlphaFinJavaScript-RustMIT license2022-07-08NFT
UseWalletuseWallet is a collection of React Hooks containing everything you need to start working with a Casper networkCasperDashTypescript-ReactMIT license2023-09-19dApp library
Testnet FaucetA faucet is a Casper tool that distributes Testnet tokens to anyone requesting them for freeCasperDashTypescript-ReactMIT license2023-09-19Tools

Building on Casper

This guide intends to briefly show you the current features and advantages of building on the Casper Mainnet.

Thriving Ecosystem

The Casper Ecosystem is growing every day through the addition of new dApps and tools. Here is a short list of tools you can use.

Wallets

Block Explorers

Developer Tools

Open Source Software

Developer-Friendly Language

Casper Network's development ecosystem supports WebAssembly by design, rather than requiring proprietary languages like Solidity. Casper contracts function just like regular software. This feature simplifies the development path for enterprises and development teams that want to build on the Casper Mainnet.

Rust is a beloved programming language for its safety and performance. We offer a Rust experience and a runtime environment for developing smart contracts . The Rust smart contracts are compiled to WebAssembly (Wasm), which is an open standard for performance and portability of modern web applications.

note

Wasm can support any language compiled or interpreted on any operating system with the help of appropriate tools. Therefore, we can support more languages for smart contracts as compilation targets for WebAssembly become available.

Powerful Accounts

Each Casper network offers powerful accounts that are more than just public keys. Accounts offer weights for separate key management and transaction signing rights, and the ability to run session code (Wasm) in an account's context. By running session code, it's possible to delegate transaction signing to multiple keys, revoke lost keys to recover accounts and store data within the account itself. It is also possible to securely share state between accounts and contracts (without expensive cryptographic checks). Refer to the Casper Permissions Model for more details.

Contract Upgrades

Casper smart contracts use a package management model, which allows the direct upgrading of on-chain smart contracts, eliminating the need for complex migration processes and making it easy for developers to add new features or fix bugs by adding a new version of the contract. When installing a contract, it's possible to designate a contract as 'not upgradeable', which is suitable for DeFi contracts.

Development Tools

IDE Integration

The Casper development process strives to be familiar to all developers. You can run and build code locally within an IDE and use assertions and tests to verify the functionality of your application. You can set the contract's starting state and create and run tests on your development machine. Casper contracts function like regular software, so there is little you need to know about the blockchain to get started.

CI/CD

Casper also provides the instrumentation and tooling that seamlessly integrates existing Continuous Integration/Continuous Deployment pipelines. Build servers can run the Casper Virtual Machine without the overhead of a full node, tracking the blockchain internal state and running assertions, thus enabling a solid development pipeline.

Local Network Testing

We also offer a tool to run a local Casper Network Even though you don't need a stand-alone node for smart contract development, you can configure your local network to test your deployments and estimate gas costs. A local network is helpful when integrating your dApp into a mobile or web interface.

Public Mainnet and Testnet

The Casper Mainnet is a public, open-source, community-driven ecosystem. You can also explore the Testnet to test drive your applications and estimate gas costs.

AWS

We also offer several tools to run AWS instances of Casper nodes.

SDK Client Libraries

In addition to the default command-line Rust client, the Casper community is building other clients in JavaScript, Java, Golang, Python, C#, and other languages.

Low Gas Fees

Casper seeks to eliminate volatility and improve developer and enterprise experiences by establishing transparent, consistent, and low gas prices. This feature seeks to promote active and diverse network behaviour and we are researching innovative pricing models that will favor dApp developers as the ecosystem grows.

Resources Overview

Building on Casper

TopicDescription
Wallets and Block ExplorersWallets that support the native Casper token $CSPR
WebAssemblyLearn why WebAssembly is an advantage in contract development
AccountsThe Casper account-model allowing for multi-signature deploys
Developer toolsAvailable development tools
Ecosystem ProjectsExplore some open-source code available in the Casper ecosystem

Move to Casper

TopicDescription
Move to CasperLearn how to start working with Casper, having previous knowledge of other blockchains

Tutorials

TopicDescription
QuickstartInstall Rust and setup a Casper environment
BeginnerLearn the basics, such as installing and upgrading contracts
AdvancedLearn about multi-sig, authorization keys, exchange integration, and storage

Moving to Casper from another Blockchain

This page covers various considerations for moving to Casper from another blockchain by comparing Casper to Ethereum, Near, Aptos, and Solana in these aspects:

  1. Smart Contract Platform Overview
  2. Variable Storage and State Management
  3. Contract Functions
  4. Passing Arguments

Since other blockchain projects use different technologies, it is essential to consider how those technologies serve your use case.

When choosing a blockchain, it is also essential to compare consensus mechanisms, tokenomics, cross-contract capabilities, contract upgradability, and software development kits (SDKs) as described here.

Smart Contract Platform

Casper smart contracts are written in Rust.

Variables defined within the smart contract can be stored as either Named Keys or Dictionaries as described in Reading and Writing Data to the Blockchain.

The call function serves as the main entry point of the smart contract. It automatically executes when the smart contract is installed, setting the initial state of the contract and defining all other entry points.

It's worth noting that Casper only supports public entry points for contracts. Additionally, contracts can be defined as upgradable or immutable as described here.

Variable Storage and State Management

Variables can be stored as Named Keys or Dictionaries as described in Reading and Writing Data to the Blockchain.

Additionally, local variables are available within the entry points and can be used to perform necessary actions or computations within the scope of each entry point.

Contract Functions

For Casper smart contracts, public functions are called entry points. To declare them, the following format is used:

#[no_mangle]
pub extern "C" fn counter_inc() {

// Entry point body
}

It's important to note that entry points do not have input arguments in their definition, but the arguments can be accessed using the RuntimeArgs passed to the contract. Entry points are instantiated within the call entry point.

If a return value is needed, it should be declared using the syntax described in the Interacting with Runtime Return Values tutorial.

runtime::ret(value);

Each call to an entry point is treated as a Deploy to the network, and therefore, each call incurs a cost paid in motes (the network's native accounting unit).

Passing Arguments

Named arguments are passed as strings with type specifiers. To provide session arguments to the entry point during a Deploy, you can utilize the following approach:

casper-client put-deploy \
--node-address http://65.21.235.219:7777 \
--chain-name casper-test \
--secret-key [KEY_PATH]/secret_key.pem \
--payment-amount 2500000000 \
--session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \
--session-entry-point "delegate" \
--session-arg "validator:public_key='0145fb72c75e1b459839555d70356a5e6172e706efa204d86c86050e2f7878960f'" \
--session-arg "amount:u512='500000000000'" \
--session-arg "delegator:public_key='0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf'"

To understand the context of this example, refer to: Delegating with the Casper Client.

In the contract, you can access the session arguments as follows:

let uref: URef = runtime::get_key(Key_Name)

Use the get_key function to retrieve the desired session argument by specifying the key's name.

If you are uncertain how to use the get_key function to obtain a specific session argument, check how to write a basic smart contract on Casper.

Additional Considerations

When choosing a blockchain, you may also look into the network's consensus mechanism, the tokenomics or economic model, cross-contract communication, smart contract upgrades, and the available software development kits (SDKs).

  1. Consensus mechanism refers to the algorithm the blockchain network uses to achieve agreement on the validity and ordering of transactions. Different blockchains employ various consensus mechanisms such as Proof-of-Work (PoW), Proof-of-Stake (PoS), or Delegated Proof-of-Stake (DPoS). The choice of consensus mechanism impacts factors like security, scalability, and energy efficiency.

  2. Tokenomics relates to the economic model of the blockchain network and its native tokens, involving token distribution, inflation, utility, and governance. Understanding the tokenomics of the network is crucial for evaluating the ecosystem's long-term viability and potential value.

  3. Cross-contract capabilities refer to the ability of smart contracts to interact and communicate within the blockchain network. This feature is essential for building complex decentralized applications (dApps) and implementing inter-contract functionality.

  4. Contract upgradability determines whether the smart contracts installed on the network can be modified or updated after installation. It is essential to assess the flexibility of the chosen blockchain in terms of contract maintenance, bug fixes, and incorporating new features or improvements without disrupting the existing ecosystem.

  5. SDK availability also plays a significant role in the development process. SDKs provide tools, libraries, and documentation to simplify the creation of applications and smart contracts on the blockchain. Evaluating the maturity, community support, and compatibility of the available SDKs is crucial for developers.

Considering these aspects helps when selecting a blockchain that aligns with a project or application's specific requirements and goals.

The Casper ecosystem aims to fulfill all of these aspects, including supporting enterprise-grade projects.

Quickstart

Here is a list of commands for developers who already meet the prerequisites and want to quickly send a sample contract to the Testnet. Consult the complete documentation for context and additional help.

Prerequisites

  1. You have installed Rust. Verify the installation with this command: rustup --version. Restart the shell if needed.
  2. You have installed cmake. Verify the installation with this command: cmake --version.
    • On Ubuntu, you can follow this guide.
    • On MacOS, use this command: brew install cmake.
  3. You have an integrated development environment (IDE). On Windows, you will need to download the C++ build developer tools, without which you cannot install cargo-casper.
  4. You have download Git.

Steps

  1. Install Cargo Casper with this command:

    cargo install cargo-casper

  2. Install the Casper client:

    cargo install casper-client

    If you have issues installing the casper-client, you may need additional libraries.

    • On MacOS:

      brew install pkg-config
      brew install openssl
    • On Ubuntu:

      sudo apt-get install pkg-config
      sudo apt-get install openssl
      sudo apt-get install libssl-dev

    Note: Make sure you also have the development packages of openssl installed. For example, libssl-dev on Ubuntu or openssl-devel on Fedora.

  3. Test the casper-client by querying a node on the network and getting the latest state root hash.

    casper-client get-state-root-hash --node-address http://65.21.235.219:7777
  4. Set up a Casper Account.

  5. Clone a simple counter contract or download it from GitHub:

    git clone https://github.com/casper-ecosystem/counter

  6. Navigate to the folder and prepare the dependencies to build the contract:

cd counter
make prepare
  1. Build the contract and tests:

make test

  1. Install the contract on Testnet using the casper-client's put-deploy command. Replace the secret key with your path. Record the deploy hash from the output. This example uses 30 CSPR to pay for contract installation on chain. You may need to adjust this value based on the latest Testnet chainspec.
casper-client put-deploy \
--node-address [NODE_ADDRESS] \
--chain-name casper-test \
--secret-key [YOUR_PATH_TO_SECRET_KEY_FILE] \
--payment-amount 30000000000 \
--session-path contracts/counter-v1/target/wasm32-unknown-unknown/release/counter-v1.wasm
  1. Check the deploy status given the deploy hash from the previous command:
casper-client get-deploy --node-address [NODE_ADDRESS] [DEPLOY_HASH]
  1. Get the latest state root hash:
casper-client get-state-root-hash --node-address [NODE_ADDRESS]
  1. Open the deploy tab of the account on the Testnet to see the deploy details.
  • As an alternative to step 15, check your account using the command line:
casper-client query-global-state \
--node-address [NODE_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [PATH_TO_PUBLIC_KEY]
  • As another alternative, use the account hash for the --key argument. To get the account hash, look at the account details on the block explorer, or run this command:
casper-client account-address --public-key [PATH_TO_PUBLIC_KEY]

Then, query the blockchain using the account hash:

casper-client query-global-state \
--node-address [NODE_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH]
  1. Now, you can play with the smart contract and increment the value it manages from 0 to 1. First, let's make sure the value is 0. Look at the "parsed" value returned in the output. An expected example output is shown below.
casper-client query-global-state \
--node-address [NODE_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] \
-q "counter/count"

Example output:

{
"id": 8523290678829319485,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.6",
"block_header": null,
"merkle_proof": "[85716 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "01000000",
"cl_type": "I32",
"parsed": 0
}
}
}
}
  1. Now increment the count value by calling the entry point counter_inc.
casper-client put-deploy \
--node-address [NODE_ADDRESS] \
--chain-name [CHAIN_NAME] \
--secret-key [PATH_TO_YOUR_KEY] \
--payment-amount 100000000 \
--session-name "counter" \
--session-entry-point "counter_inc"
  1. Get the NEW state root hash, to get the latest snapshot of the blockchain state – this is EXTREMELY IMPORTANT!
casper-client get-state-root-hash --node-address [NODE_ADDRESS]
  1. Query the state of the network.
casper-client query-state \
--node-address [NODE_ADDRESS] \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] \
-q "counter/count"

If everything went according to plan, the value should be 1. Look at the "parsed" value below.

{
"id": 8523290678829319485,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.6",
"block_header": null,
"merkle_proof": "[85716 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "01000000",
"cl_type": "I32",
"parsed": 1
}
}
}
}

You have successfully invoked a contract on the Casper Testnet to increment a value from 0 to 1. Now you have all the infrastructure required to work with more meaningful contracts.

Casper Fungible Token Tutorial

This tutorial introduces an implementation of the CEP-18 standard for the Casper blockchain, known as the Casper Fungible Token. The code for this tutorial is available in GitHub.

The Ethereum Request for Comment (ERC-20) standard is an integral part of the Ethereum ecosystem. This standard allows for building new tokens based on smart contracts. These ERC-20 tokens are blockchain-based assets that have value and can be transferred or recorded.

The Casper Fungible Token standard is the Casper Platform's ER-C20 equivalent. It defines a set of rules that dictate the total supply of tokens, how the tokens are transferred, how transactions are approved, and how token data is accessed.

The following functions implement the rules defined by Casper Fungible Tokens: totalSupply, transfer, transferFrom, approve, balanceOf, and allowance. A portion of this tutorial reviews the contract and the casper_fungible_token library.

The Writing Rust Contracts on Casper document outlines many aspects of this tutorial and should be read first.

Preparation

First clone the contract from GitHub:

git clone https://github.com/casper-ecosystem/cep18 && cd cep18

Prepare your environment with the following command:

make prepare

If your environment is set up correctly, you will see this output:

rustup target add wasm32-unknown-unknown
info: component 'rust-std' for target 'wasm32-unknown-unknown' is up to date

If you do not see this message, check the Getting Started Guide.

Next, compile your contract and run the contract unit tests.

make build-contract
make test

Contract Implementation

In GitHub, you will find a library and an example implementation of the Fungible Token for Casper networks. This section explains the example contract in more detail.

There are four steps to follow when you intend to create your own implementation of the Fungible Token contract, as follows:

  1. Fork the code from the example repository listed above.
  2. Perform any customization changes necessary on your personal fork of the example contract.
  3. Compile the customized code to Wasm.
  4. Send the customized Wasm as a deploy to a Casper network.

Installing Required Crates

This tutorial applies to the Rust implementation of the Casper Fungible Token standard, and requires the following Casper crates:

  • casper_contract - A Rust library for writing smart contracts on Casper networks
  • casper_types - Types used to allow creation of Wasm contracts and tests for use on Casper networks
  • casper_erc20 - A library for developing Fungible Tokens for Casper networks

Here is the code snippet which imports those crates:


use casper_contract::{contract_api::runtime, unwrap_or_revert::UnwrapOrRevert};

use casper_types::{CLValue, U256};

Note: In Rust, the keyword use is like an include statement in C/C++.

Initializing the Contract

Initializing the contract happens through the call() function inside the contract file. When you deploy the contract, you need to initialize it with a call() function and define name, symbol, decimals, and total_supply.

The code snippet for initializing the contract should look like this:


#[no_mangle]
fn call() {
let name: String = runtime::get_named_arg(NAME_RUNTIME_ARG_NAME);
let symbol: String = runtime::get_named_arg(SYMBOL_RUNTIME_ARG_NAME);
let decimals = runtime::get_named_arg(DECIMALS_RUNTIME_ARG_NAME);
let total_supply = runtime::get_named_arg(TOTAL_SUPPLY_RUNTIME_ARG_NAME);

let _token = CEP18::install(name, symbol, decimals, total_supply).unwrap_or_revert();
}

Contract Methods

This section briefly explains the contract methods used in the Casper Fungible Token contract.

To see the full implementation of the below contract methods, refer to the contract file in Github. If you have any questions, review the casper_erc20 library and the EIP-20 standard.

Also, for further unresolved issues please contact the Casper support team via the Discord channel.

Contract methods are:

  • allowance - Returns the amount of owner’s tokens allowed to be spent by the spender
  • approve - Allows a spender to transfer up to an amount of the direct caller’s tokens
  • balance_of - Returns the token balance of the owner
  • burn - Burns tokens, reducing the total supply.
  • change_security - An administrator-level entry point to manipulate security access granted to users
  • decimals - Returns the decimals of the token
  • decrease_allowance - Decrease the allotted allowance for an account approved to spend from an owner's token balance
  • increase_allowance - Increases the allotted allowance for an account approved to spend from an owner's token balance
  • mint - Mints additional tokens, increasing the total supply
  • name- Returns the name of the token
  • symbol - Returns the symbol of the token
  • total_supply - Returns the total supply of the token
  • transfer - Transfers an amount of tokens from the direct caller to a recipient
  • transfer_from - Transfers an amount of tokens from the owner to a recipient, if the direct caller has been previously approved to spend the specified amount on behalf of the owner

Installing the Contract

After customizing your instance of the CEP-18 token contract, it's time to install it in global state. Installing the Fungible Token contract is similar to installing other smart contracts, while only the Wasm files and parameters will differ. Refer to the Sending Deploys to a Casper network using the Rust Client section to learn more about install contracts.

Deploy Prerequisites

Basic Flow

Here are the basic steps to install the Casper Fungible Token contract on a Casper Network.

Cloning the Token Contract

This step includes cloning and preparing the token contract for the deployment.

  1. Clone the Fungible Token contract from the repository.

git clone https://github.com/casper-ecosystem/cep18.git

  1. Make any necessary changes to the code for your customization requirements.

  2. Compile the contract to create the target .wasm file and build the Wasm.


cd cep18
make prepare
make build-contracts

  1. Build and verify the compiled contract.

make test

Getting an IP Address from a Testnet Peer

We will use a Testnet peer to send the deploy. Read the guide to acquiring a node address if needed.

Viewing the Network Status

This query captures any information related to the state of the blockchain at the specific time denoted by the network's state root hash. You need to have the state root hash and the account hash to run the query.

Getting the state root hash

Get the state root hash, which marks a snapshot of the network state at a moment in time. Use the Node IP address taken from a Testnet peer.

casper-client get-state-root-hash --node-address http://<HOST:PORT>

Getting the account hash

Run the following command and supply the path to your public key in hexadecimal format to get the account hash.

casper-client account-address --public-key "[PATH_TO_YOUR_KEY]/public_key_hex"

Querying global state

Use the command template below to query the network status with regard to your account.

casper-client query-global-state \
--node-address http://<HOST:PORT> \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH]

Installing the Contract

Now you can install the contract to the network and check how it behaves.

If you are sending the deploy on Mainnet, try several put deploys on the Testnet to understand the exact gas amount required for that deploy. Refer to the note about gas price to understand more about payment amounts and gas price adjustments.

The Casper platform currently does not refund any tokens as part of sending a deploy. For example, if you spend 10 CSPR for the deployment and it only costs 1 CSPR, you will not receive the remaining 9 CSPR. Refer to the Gas and the Casper Blockchain documentation for further details.

Use the following command template to deploy the contract:

casper-client put-deploy \
--node-address http://<HOST:PORT> \
--chain-name [NETWORK_NAME]] \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [AMOUNT] \
--session-path [WASM_FILE_PATH]/[File_Name].wasm
--session-arg <"NAME:TYPE='VALUE'" OR "NAME:TYPE=null">
  • NETWORK_NAME: Use the relevant network name. Here we use 'casper-test'
  • PATH_TO_YOUR_KEY: Replace this with the actual path of your secret key
  • PAYMENT_AMOUNT: Gas amount in tokens needed for contract execution. If there are no adequate tokens, the deploy will not execute and will return an error
  • WASM FILE PATH: The session-path argument should point to the location of your compiled Fungible Token Wasm file

Here is a sample put-deploy command:

casper-client put-deploy \
--node-address http://95.216.24.237:7777 \
--chain-name casper-test \
--secret-key "/home/ubuntu/secret_key.pem" \
--payment-amount 1000000 \
--session-path "<machine-path>/cep18/target/wasm32-unknown-unknown/release/cep18.wasm"
--session-arg "name='Token test', symbol='TEST', decimals:u8=10, total_supply:u256=1000"

Querying the Network Status

You will need the newest state root hash to view the network status, as it changed with the deploy. The account hash remains the same since you are using the same account. Follow the viewing the network state section to execute this step with the new state root hash.

Verifying the Deploy

Now you can verify the sent deploy using the get-deploy command. This will output the details of the sent deploy.

casper-client get-deploy \
--node-address http://<HOST:PORT> [DEPLOY_HASH]

Querying with Arguments

This step will narrow down the context and check the status of a specific entry point. You will use the details inside the Fungible Token contract to derive arguments.

Use the command template below to query the network state with arguments:

casper-client query-global-state \
--node-address http://<HOST:PORT> \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] \
-q "[CONTRACT_NAME/ARGUMENT]"

Example Deploy on Testnet

The following steps will guide you through the process with sample values and results.

Cloning the Fungible Token Contract

git clone https://github.com/casper-ecosystem/cep18.git

Getting an IP Address from a Testnet Peer

Use peers to get the node IP address.

Viewing the Network Status

Here is the command to query the state of the network:

casper-client query-global-state \
--key account-hash-<account-address> \
--node-address http://<HOST:PORT> \
--state-root-hash E5B679BD1562fE6257257F5f969A79482E8DCEBBD501501BfA6d5844b61cBE3f

Result:

This result contains the network state before the deploy. You can see the named-key field is empty since we haven't sent the deploy to the network yet.

Result from querying the network status
{
"id": 401803927542812599,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.3",
"merkle_proof": "[25564 hex chars]",
"stored_value": {
"Account": {
"account_hash": "account-hash-<account-address> ",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_hash": "account-hash-<account-address> ",
"weight": 1
}
],
"main_purse": "uref-<hash>",
"named_keys": []
}
}
}
}

Sending the Deploy

Send the Deploy containing your contract with this command:

casper-client put-deploy \
--node-address http://<HOST:PORT> \
--chain-name casper-test \
--secret-key "/home/ubuntu/secret_key.pem" \
--payment-amount 1000000 \
--session-path "<machine-path>/cep18/target/wasm32-unknown-unknown/release/cep18.wasm"
--session-arg "name='Token test', symbol='TEST', decimals:u8=10, total_supply:u256=1000"

Result:

This command execution will output the deploy_hash of the applied deploy. We can use the deploy_hash to get the details of the deploy.

{
"id": 931694842944790108,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.3",
"deploy_hash": "b00E59f8aBA5c7aB9...."
}
}

Viewing the Deploy Details

You can view the details of the sent deploy using the command below:

casper-client get-deploy \
--node-address http://<HOST:PORT> \
b00E59f8aBA5c7aB9.....

Result:

This contains the header, payment, and session details along with the execution results.

  • If the execution result field appears as "execution_results":[], it means that the deploy hasn't been executed yet. The time to load the execution result may vary depending on the network.
Result from querying the deploy
{
{
"id": -870982079597140956,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.3",
"deploy": {
"approvals": [
{
"signature": "[130 hex chars]",
"signer": "017B8CE645c728......................."
}
],
"hash": "F9D4C649Fa78Da07E.......................",
"header": {
"account": "017B8CE645c7285.......................",
"body_hash": "8eAEd6B7bCBB493d75d.......................",
"chain_name": "casper-test",
"dependencies": [],
"gas_price": 1,
"timestamp": "2022-01-04T15:14:29.203Z",
"ttl": "30m"
},
"payment": {
"ModuleBytes": {
"args": [
[
"amount",
{
"bytes": "0500e8764817",
"cl_type": "U512",
"parsed": "100000000000"
}
]
],
"module_bytes": ""
}
},
"session": {
"ModuleBytes": {
"args": [],
"module_bytes": "[417800 hex chars]"
}
}
},
"execution_results": [
{
"block_hash": "d3644f0306F20fa6.......................",
"result": {
"Success": {
"cost": "45040980830",
"effect": {
"operations": [],
"transforms": [
{
"key": "hash-8cf5E4aCF51f54Eb5.......................",
"transform": "Identity"
},
{
"key": "hash-624dBE2395b9D9503FB.......................",
"transform": "Identity"
},
{
"key": "hash-010c3Fe81B7b862E50C77.......................",
"transform": "Identity"
},
{
"key": "hash-9824d60dC3A5c44A20b.......................",
"transform": "Identity"
},
{
"key": "balance-C051e7EC16e08De.......................",
"transform": "Identity"
},
{
"key": "balance-98d945f5324F865243.......................",
"transform": "Identity"
},
{
"key": "balance-C051e7EC16e08Def8b556",
"transform": {
"WriteCLValue": {
"bytes": "06E07f3abEa001",
"cl_type": "U512",
"parsed": "1789897900000"
}
}
},
{
"key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",
"transform": {
"AddUInt512": "100000000000"
}
},
{
"key": "uref-d29a34C29769D4BaC250CF9efD3c6372d8e6a89B62fAD122b3BF009990Ae61CD-000",
"transform": {
"WriteCLValue": {
"bytes": "",
"cl_type": "Unit",
"parsed": null
}
}
},
{
"key": "account-hash-7f4bf39A3...................................................",
"transform": {
"AddKeys": [
{
"key": "uref-d29a34C29769D4BaC250CF9efD3c6372d8e6a89B62fAD122b3BF009990Ae61CD-007",
"name": "balances"
}
]
}
},
{
"key": "uref-075874B98e3CF57Ea6326746336A0Aa908e770D3ADe0cf953f7E146f8B64F837-000",
"transform": {
"WriteCLValue": {
"bytes": "",
"cl_type": "Unit",
"parsed": null
}
}
},
{
"key": "account-hash-7f4bf39A311...................................................",
"transform": {
"AddKeys": [
{
"key": "uref-075874B98e3CF57Ea6326746336A0Aa908e770D3ADe0cf953f7E146f8B64F837-007",
"name": "allowances"
}
]
}
},
{
"key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",
"transform": {
"WriteCLValue": {
"bytes": "0400ca9A3B",
"cl_type": "U256",
"parsed": "1000000000"
}
}
},
{
"key": "uref-4EB0a2A42afBb1d3D5ae9BD4781dc96E528C7AD3f0eEC240Cf1DbDaDF4f3D486-000",
"transform": {
"WriteCLValue": {
"bytes": "0A00000043617370657254657374",
"cl_type": "String",
"parsed": "CasperTest"
}
}
},
{
"key": "uref-6e87fd661D5a65aF95f02baDfEb64f8E0F44C006661d4903A68E9dF8dEAa413d-000",
"transform": {
"WriteCLValue": {
"bytes": "050000004353505254",
"cl_type": "String",
"parsed": "CSPRT"
}
}
},
{
"key": "uref-aCA2425C80584391fB883603460578B1472d13a429Ebbd1a18a55cE19cE8F3C6-000",
"transform": {
"WriteCLValue": {
"bytes": "08",
"cl_type": "U8",
"parsed": 8
}
}
},
{
"key": "dictionary-baA61231F04B1c2Ee97025f425eaD2F70CAd9c1E8c24355246d159038AdCb2e9",
"transform": {
"WriteCLValue": {
"bytes": "[188 hex chars]",
"cl_type": "Any",
"parsed": null
}
}
},
{
"key": "account-hash-7f4bf39A311a7538d8C...................................................",
"transform": "Identity"
},
{
"key": "account-hash-7f4bf39A311a75...................................................",
"transform": {
"WriteAccount": "account-hash-7f4bf39A311a7538d8C91BB86C71DF774023e16bc4a70ab7e4e8AE77DbF2Ef53"
}
},
{
"key": "account-hash-7f4bf39A311a7538...................................................",
"transform": "Identity"
},
{
"key": "account-hash-7f4bf39A311a7538d8C...................................................",
"transform": {
"WriteAccount": "account-hash-7f4bf39A311a75..................................................."
}
},
{
"key": "uref-868c0e0BEB2EB3C10e893be96E6D6bE7FC6375f3f038e46c3262509245c117a0-000",
"transform": {
"WriteCLValue": {
"bytes": "",
"cl_type": "Unit",
"parsed": null
}
}
},
{
"key": "hash-28f982A396052b5068383E725ab48965AB941167f53DB36a0911ba0C98bc39F0",
"transform": "WriteContractPackage"
},
{
"key": "hash-28f982A396052b5068383E725ab48965AB941167f53DB36a0911ba0C98bc39F0",
"transform": "Identity"
},
{
"key": "hash-AdF81845d77907054ACb250c196392c7DAEE5481d4EabEB76c318A307c11E5cB",
"transform": "WriteContractWasm"
},
{
"key": "hash-Faa81ED758ecE1B99E2Ce48073D13D7f6185d9dc5233E39DE5c192Bebb9483D6",
"transform": "WriteContract"
},
{
"key": "hash-28f982A396052b5068383E725ab48965AB941167f53DB36a0911ba0C98bc39F0",
"transform": "WriteContractPackage"
},
{
"key": "account-hash-7f4bf39A311a7538d8...................................................",
"transform": {
"AddKeys": [
{
"key": "hash-Faa81ED758ecE1B99E2Ce48073D13D7f6185d9dc5233E39DE5c192Bebb9483D6",
"name": "test_contract"
}
]
}
},
{
"key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",
"transform": "Identity"
},
{
"key": "dictionary-04932d42aff9367579770E219ce1C4Da83D1Fd42Fa0FaA4Ae98AE07914c4c1E4",
"transform": {
"WriteCLValue": {
"bytes": "[186 hex chars]",
"cl_type": "Any",
"parsed": null
}
}
},
{
"key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",
"transform": {
"WriteCLValue": {
"bytes": "04400cAa3b",
"cl_type": "U256",
"parsed": "1001000000"
}
}
},
{
"key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",
"transform": "Identity"
},
{
"key": "dictionary-Ec3f20485A29255dd2c2D7b8c008207A0d139dFDCE89224DA8b63F21c157A97F",
"transform": {
"WriteCLValue": {
"bytes": "[186 hex chars]",
"cl_type": "Any",
"parsed": null
}
}
},
{
"key": "uref-66Bf928E1F6A28b174A48Fca4c002Bc8b77Dd851d7EFFb9Dc1A450cB211E484a-000",
"transform": {
"WriteCLValue": {
"bytes": "04C090c83b",
"cl_type": "U256",
"parsed": "1003000000"
}
}
},
{
"key": "deploy-F9D4C649Fa78Da...................................................",
"transform": {
"WriteDeployInfo": {
"deploy_hash": "F9D4C649Fa78Da07Ec6EFcFC615ff1Bd3B68347750FA0C81B6a74C3f9582d7E4",
"from": "account-hash-7f4bf39A311a...................................................",
"gas": "45040980830",
"source": "uref-C051e7EC16e08Def8b556F9...................................................",
"transfers": []
}
}
},
{
"key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",
"transform": "Identity"
},
{
"key": "hash-8cf5E4aCF51f54Eb59291599187838Dc3BC234089c46fc6cA8AD17e762aE4401",
"transform": "Identity"
},
{
"key": "hash-010c3Fe81B7b862E50C77EF9A958a05BfA98444F26f96f23d37A13c96244cFB7",
"transform": "Identity"
},
{
"key": "hash-9824d60dC3A5c44A20b9FD260a412437933835B52Fc683d8AE36e4ec2114843e",
"transform": "Identity"
},
{
"key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",
"transform": "Identity"
},
{
"key": "balance-c69d353A5a3b6433368A8FC2F6b308ce4Ec10291782f61BA15C96F260f91FFC0",
"transform": "Identity"
},
{
"key": "balance-98d945f5324F865243B7c02C0417AB6eaC361c5c56602FD42ced834a1Ba201B6",
"transform": {
"WriteCLValue": {
"bytes": "00",
"cl_type": "U512",
"parsed": "0"
}
}
},
{
"key": "balance-c69d353A5a3b6433368A8FC2F6b308ce4Ec10291782f61BA15C96F260f91FFC0",
"transform": {
"AddUInt512": "100000000000"
}
}
]
},
"transfers": []
}
}
}
]
}
}

Querying Contract Entry Points

We will query the argument 'name' in this example.

casper-client query-global-state --node-address http://95.216.24.237:7777 \
--state-root-hash D00dF8c35B0E9995c2911803F37A212d82c960D9bC5bA3C4F99a661e18D09411 \
--key account-hash-7f4bf39A311a7538d8C91BB86C71DF774023e16bc4a70ab7e4e8AE77DbF2Ef53 \
-q "test_contract/name"

Result:

You can see that the name is CasperTest in this example.

{
"id": -3650676146668320186,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.3",
"block_header": null,
"merkle_proof": "[80252 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "0A00000043617370657254657374",
"cl_type": "String",
"parsed": "CasperTest"
}
}
}
}

Exploring the CEP-18 Contracts

This document covers the necessary information that you will need to interact with your CEP-18 contract instance. Your setup should include the following two contracts:

  • The Casper fungible token contract

  • The CEP-18 utility contract, which should appear in the NamedKeys of the account that sent the Deploy as cep18_test_contract

Querying the Contract Package

We will need the contract package's contract_hash to interact with the recently installed instance of CEP-18. You can find the contract package hash within the installing account's NamedKeys, under the name given during the installation process.

casper-client query-global-state -n http://<HOST IP>:<PORT> \
// This is the contract package hash, which can be found within the `NamedKeys` of the account that sent the installing deploy.
--key hash-82bd86d2675b2dc44c19027fb7717a99db6fda5e0cad8d597f2495a9dbc9df7f \
// This is the most up to date state root hash, which can found by using the `get-state-root-hash` command in the Casper client.
--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933
Casper client command without comments
casper-client query-global-state -n http://<HOST IP>:<PORT> \
--key hash-82bd86d2675b2dc44c19027fb7717a99db6fda5e0cad8d597f2495a9dbc9df7f \
--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933

This will return the Contract Package object:

{
"id": -1489823435760214673,
"jsonrpc": "2.0",
"result": {
"api_version": "1.0.0",
"block_header": null,
"merkle_proof": "[2048 hex chars]",
"stored_value": {
"ContractPackage": {
"access_key": "uref-8dac847ce0ae20f0156cf37dd233cc1d166fde8269fc9a393b0ea04174be1167-007",
"disabled_versions": [],
"groups": [],
"versions": [
{
"contract_hash": "contract-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e",
"contract_version": 1,
"protocol_version_major": 1
}
]
}
}
}
}
  • Note - In the contract_hash field, the hash value represents the stored contract which we will invoke later.

Querying the Utility Contract

In addition, there is a utility contract that invokes the various balance and allowance entry points of the main fungible token contract. Upon receiving the returned value, the utility contract will write the value to a URef called result. You can find this URef in the NamedKeys of the utility contract.

First, you will need to query the cep18_test_contract hash found within the installing account's NamedKeys:

casper-client query-global-state -n http://<HOST IP>:<PORT> \
// This is the contract hash for the `cep18_test_contract` as found from the installing account's `NamedKeys`
--key hash-015b99020edb40e7e1e2b31a8e104bc226242f960a2d10dc1d91ae3eb6fa41b6 \
--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933
Casper client command without comments
casper-client query-global-state -n http://<HOST IP>:<PORT> \
--key hash-015b99020edb40e7e1e2b31a8e104bc226242f960a2d10dc1d91ae3eb6fa41b6 \
--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933

Which should return information similar to the following:


{
"id": 5359405942597097786,
"jsonrpc": "2.0",
"result": {
"api_version": "1.0.0",
"block_header": null,
"merkle_proof": "[2048 hex chars]",
"stored_value": {
"ContractPackage": {
"access_key": "uref-1b867a3751f505762c69c8d92ba7462818cd0c2a705bb5d4270bce479410ee55-007",
"disabled_versions": [],
"groups": [],
"versions": [
{
"contract_hash": "contract-a8fe057675930f0951d45816c55615228ac8af2b7b231788278dffcf1dd8c0ca",
"contract_version": 1,
"protocol_version_major": 1
}
]
}
}
}
}

You will need to take the contract_hash value and replace contract with hash to run another `query-global-state:

casper-client query-global-state -n http://<HOST IP>:<PORT> \
--key hash-a8fe057675930f0951d45816c55615228ac8af2b7b231788278dffcf1dd8c0ca \
--state-root-hash f9f73c3a4da5893b67c4cac94a5695d76cfefff61b050c98a7b19e2b8efd3933

Which will return the full cep18_test_contract information. The following snippet is condensed to show only the NamedKeys, but you should also see the entry_points when you run the command. You should see the URef result, which will be used to view the results of any checks run through the utility contract.

{
"id": -1426549275795832481,
"jsonrpc": "2.0",
"result": {
"api_version": "1.0.0",
"block_header": null,
"merkle_proof": "[3370 hex chars]",
"stored_value": {
"Contract": {
"contract_package_hash": "contract-package-015b99020edb40e7e1e2b31a8e104bc226242f960a2d10dc1d91ae3eb6fa41b6",
"contract_wasm_hash": "contract-wasm-7959083a4df983ddcd3a9ae46af092dbf126031181ab2619ddc64db09bde8c27",
"named_keys": [
{
"key": "uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007",
"name": "result"
}
],
"protocol_version": "1.0.0"
}
}
}
}

Next Steps

Installing and Interacting with a CEP-18 Contract

This quick start guide introduces you to the Casper client commands and Wasm files necessary to deploy a CEP-18 Casper Fungible Token contract to a Casper network.

The Ethereum Request for Comment (ERC-20) standard defines a set of rules that dictate the total supply of tokens, how the tokens are transferred, how transactions are approved, and how token data is accessed. These fungible tokens are blockchain-based assets that have value and can be transferred or recorded.

To execute transactions on a Casper network (involving fungible tokens), you will need some CSPR tokens to pay for the transactions.

For greater detail into the creation and mechanics of the Casper fungible token contract, see the full Casper Fungible Token Tutorial.

Prerequisites

Before using this guide, ensure you meet the following requirements:

  • Set up your machine as per the prerequisites
  • Use the [Casper command-line client]
  • Get a valid node-address
  • Know how to deploy a smart contract to a Casper network
  • Hold enough CSPR tokens to pay for transactions

Setup

Clone the fungible token (CEP-18) contract repository and run the make build-contract command. This will create the cep18.wasm and the cep18_test_contract.wasm. The token Wasm is the main contract. We will use the cep18_test_contract Wasm to query the balances and allowances of the fungible token balances throughout this workflow.

Install the Main Fungible Token Contract

The following command will create a deploy containing the CEP-18 contract instance using your supplied arguments as follows:

  • Name - The name of your CEP-18 token
  • Symbol - The symbol used to refer to your CEP-18 token
  • Total_supply - The total supply of the CEP-18 token to be minted
  • Decimals - The number of spaces after the decimal. (As an example, a total supply of 1000000 with a decimals setting of 3 would be 1,000.000 tokens)
casper-client put-deploy -n http://<NODE IP>:<PORT> \
--chain-name <CHAIN NAME> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-path ~/casper/demo/cep18.wasm \
--session-arg "name:string='CEP18'" \
--session-arg "symbol:string='gris'" \
--session-arg "total_supply:u256='100'" \
--session-arg "decimals:u8='1'" \
--payment-amount 150000000000

Install the cep18_test_contract Contract Package

The following command will install the CEP-18 helper contract that allows you to check balances and access approval features.

casper-client put-deploy -n http://<NODE IP>:<PORT> \
--chain-name <CHAIN NAME> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-path ~/casper/demo/cep18_test_contract.wasm \
--payment-amount 50000000000

At this point, the account that installed both the main contract and the helper contract will look like this.

{
"src": {
"Account": {
"_accountHash": "account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd",
"namedKeys": [
{
"name": "cep18_test_contract",
"key": "hash-999326ca8408dfd37da023eb6fd82f174151be64f83f9fb837632a0d69fd4c7e"
},
{
"name": "cep18_token_contract",
"key": "hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180"
},
],
"mainPurse": "uref-6c062525debdee18d5cad083ca530fcb65ef8741574fba4c97673f4ed00093f7-007",
"associatedKeys": [
{
"accountHash": "account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd",
"weight": 1
}
],
"actionThresholds": {
"deployment": 1,
"keyManagement": 1
}
}
}
}

Note:

  1. cep18_token_contract is the main contract, and is a stored contract, record its hash
  2. cep18_test_call is a contract package which contains the utility contract required to read the balances and allowances of users within the fungible token state.

Next Steps

In the following sections, the sample guide explains the querying of the contract package, token transfers, and approvals.

Testing Framework for CEP-18

The testing framework in this tutorial uses the Casper engine test support crate for testing the contract implementation against the Casper execution environment.

The following section reviews the GitHub testing folder, which creates a testing framework for the Casper Fungible Token project. You can find more details about testing Casper contracts here.

The following is an example of a complete test expecting a failed transfer:

#[should_panic(expected = "ApiError::User(65534) [131070]")]
#[test]
fn should_not_transfer_with_insufficient_balance() {
let mut fixture = TestFixture::install_contract();

let initial_ali_balance = fixture.balance_of(Key::from(fixture.ali)).unwrap();
assert_eq!(fixture.balance_of(Key::from(fixture.bob)), None);

fixture.transfer(
Key::from(fixture.bob),
initial_ali_balance + U256::one(),
fixture.ali,
);
}

To build and run the tests, issue the following command in the project folder, cep18:

make test

The project contains a Makefile, which is a custom build script that compiles the contract before running tests in release mode. Then, the script copies the contract.wasm file to the tests/wasm directory. In practice, you only need to run the make test command during development.

Configuring the Test Package

In this project, we define a tests package using the tests/Cargo.toml file.

[package]
name = "tests"
version = "1.0.0"
...

[dependencies]
casper-types = "2.0.0"
casper-engine-test-support = "4.0.0"
casper-execution-engine = "4.0.0"
once_cell = "1.16.0"

[lib]
name = "tests"
...

Testing Logic

In Github, you will find an example containing a Casper Fungible Token contract implementation with the corresponding tests. The tests follow this sequence:

  • Step 1 - Specify the starting state of the blockchain.
  • Step 2 - Deploy the compiled contract to the blockchain and query it.
  • Step 3 - Create additional deploys for calling each of the entrypoints in the contract.

The test fixture accomplishes these steps by simulating a real-world deploy that stores the contract on the blockchain and then invoking the contract's entrypoints.

Setting up the Testing Context

The code in the utility directory initializes the blockchain's global state with all the data and entrypoints the smart contract needs.

Expand the example below to see a subset of the required constants for this project. The testing framework defines constants via the constants.rs file within the utility directory. For the most up-to-date version of the code, visit GitHub.

Example of required constants
// File https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/utility/installer_request_builders.rs

use casper_engine_test_support::{
ExecuteRequestBuilder, InMemoryWasmTestBuilder, DEFAULT_ACCOUNT_ADDR,
MINIMUM_ACCOUNT_CREATION_BALANCE, PRODUCTION_RUN_GENESIS_REQUEST,
};
use casper_execution_engine::core::engine_state::ExecuteRequest;
use casper_types::{
account::AccountHash, bytesrepr::FromBytes, runtime_args, system::mint, CLTyped, ContractHash, ContractPackageHash, Key, RuntimeArgs, U256,
};

use crate::utility::constants::{
ALLOWANCE_AMOUNT_1, ALLOWANCE_AMOUNT_2, TOTAL_SUPPLY_KEY, TRANSFER_AMOUNT_1, TRANSFER_AMOUNT_2,
};

use super::constants::{
ACCOUNT_1_ADDR, ACCOUNT_2_ADDR, ARG_ADDRESS, ARG_AMOUNT, ARG_DECIMALS, ARG_NAME, ARG_OWNER, ARG_RECIPIENT, ARG_SPENDER, ARG_SYMBOL, ARG_TOKEN_CONTRACT, ARG_TOTAL_SUPPLY, CEP18_CONTRACT_WASM, CEP18_TEST_CONTRACT_KEY, CEP18_TEST_CONTRACT_WASM, CEP18_TOKEN_CONTRACT_KEY, CHECK_ALLOWANCE_OF_ENTRYPOINT, CHECK_BALANCE_OF_ENTRYPOINT,CHECK_TOTAL_SUPPLY_ENTRYPOINT, METHOD_APPROVE, METHOD_APPROVE_AS_STORED_CONTRACT,METHOD_TRANSFER, METHOD_TRANSFER_AS_STORED_CONTRACT, RESULT_KEY, TOKEN_DECIMALS, TOKEN_NAME, TOKEN_SYMBOL, TOKEN_TOTAL_SUPPLY,
};

Installing the Contract

The next step is to define a struct that has its own virtual machine (VM) instance and implements the Fungible Token entrypoints. This struct holds a TestContext of its own. The contract_hash and the session_code won’t change after the contract is deployed, so it is good to keep them handy.

This code snippet builds the context and includes the compiled contract .wasm binary being tested. The TestContext struct creates a new instance of the cep18_token with several test accounts.

Note: These accounts have a positive initial balance.

The full and most recent code implementation is available on GitHub.

Example of a CEP-18 token in a test
// File https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/utility/installer_request_builders.rs

// Creating the `TestContext` struct.

pub(crate) struct TestContext {
pub(crate) cep18_token: ContractHash,
pub(crate) cep18_test_contract_package: ContractPackageHash,
}

// Setting up the test instance of CEP-18.

pub(crate) fn setup() -> (InMemoryWasmTestBuilder, TestContext) {
setup_with_args(runtime_args! {
ARG_NAME => TOKEN_NAME,
ARG_SYMBOL => TOKEN_SYMBOL,
ARG_DECIMALS => TOKEN_DECIMALS,
ARG_TOTAL_SUPPLY => U256::from(TOKEN_TOTAL_SUPPLY),
})
}

// Establishing test accounts.

pub(crate) fn setup_with_args(install_args: RuntimeArgs) -> (InMemoryWasmTestBuilder, TestContext) {
let mut builder = InMemoryWasmTestBuilder::default();
builder.run_genesis(&PRODUCTION_RUN_GENESIS_REQUEST);

let id: Option<u64> = None;
let transfer_1_args = runtime_args! {
mint::ARG_TARGET => *ACCOUNT_1_ADDR,
mint::ARG_AMOUNT => MINIMUM_ACCOUNT_CREATION_BALANCE,
mint::ARG_ID => id,
};
let transfer_2_args = runtime_args! {
mint::ARG_TARGET => *ACCOUNT_2_ADDR,
mint::ARG_AMOUNT => MINIMUM_ACCOUNT_CREATION_BALANCE,
mint::ARG_ID => id,
};

let transfer_request_1 =
ExecuteRequestBuilder::transfer(*DEFAULT_ACCOUNT_ADDR, transfer_1_args).build();
let transfer_request_2 =
ExecuteRequestBuilder::transfer(*DEFAULT_ACCOUNT_ADDR, transfer_2_args).build();

// Installing the test version of CEP-18 with the default account.

let install_request_1 =
ExecuteRequestBuilder::standard(*DEFAULT_ACCOUNT_ADDR, CEP18_CONTRACT_WASM, install_args)
.build();

let install_request_2 = ExecuteRequestBuilder::standard(
*DEFAULT_ACCOUNT_ADDR,
CEP18_TEST_CONTRACT_WASM,
RuntimeArgs::default(),
)
.build();

builder.exec(transfer_request_1).expect_success().commit();
builder.exec(transfer_request_2).expect_success().commit();
builder.exec(install_request_1).expect_success().commit();
builder.exec(install_request_2).expect_success().commit();

let account = builder
.get_account(*DEFAULT_ACCOUNT_ADDR)
.expect("should have account");

let cep18_token = account
.named_keys()
.get(CEP18_TOKEN_CONTRACT_KEY)
.and_then(|key| key.into_hash())
.map(ContractHash::new)
.expect("should have contract hash");

let cep18_test_contract_package = account
.named_keys()
.get(CEP18_TEST_CONTRACT_KEY)
.and_then(|key| key.into_hash())
.map(ContractPackageHash::new)
.expect("should have contract package hash");

let test_context = TestContext {
cep18_token,
cep18_test_contract_package,
};

(builder, test_context)
}

Creating Helper Functions

The previous step has simulated sending a real deploy on the network. The next code snippet in installer_request_builders.rs defines helper functions that will be used throughout the testing framework:

  • cep18_check_total_supply - A function for testing the total supply of the CEP-18 contract instance.
  • cep18_check_balance_of - A function for checking an account's balance of CEP-18 tokens.
  • cep18_check_allowance_of - A function for checking an account's spending allowance from another account's balance.

These are followed by functions that check specific aspects of the CEP-18 contract. These include test_cep18_transfer, make_cep18_approve_request and test_approve_for.

The following code snippet is an example function that tests the ability to transfer CEP-18 tokens from the default address to the two other addresses established in contract installation:

Example helper function
// File https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/utility/installer_request_builders.rs

pub(crate) fn test_cep18_transfer(
builder: &mut InMemoryWasmTestBuilder,
test_context: &TestContext,
sender1: Key,
recipient1: Key,
sender2: Key,
recipient2: Key) {
let TestContext { cep18_token, .. } = test_context;

// Defining the amount to be transferred to each account.

let transfer_amount_1 = U256::from(TRANSFER_AMOUNT_1);
let transfer_amount_2 = U256::from(TRANSFER_AMOUNT_2);

// Checking the pre-existing balances of the default address and the two receiving addresses.

let sender_balance_before = cep18_check_balance_of(builder, cep18_token, sender1);
assert_ne!(sender_balance_before, U256::zero());

let account_1_balance_before = cep18_check_balance_of(builder, cep18_token, recipient1);
assert_eq!(account_1_balance_before, U256::zero());

let account_2_balance_before = cep18_check_balance_of(builder, cep18_token, recipient1);
assert_eq!(account_2_balance_before, U256::zero());

// Creating the first transfer request.

let token_transfer_request_1 =
make_cep18_transfer_request(sender1, cep18_token, recipient1, transfer_amount_1);

builder
.exec(token_transfer_request_1)
.expect_success()
.commit();

// Checking the prior balance against the new balance to ensure the transfer occurred correctly.

let account_1_balance_after = cep18_check_balance_of(builder, cep18_token, recipient1);
assert_eq!(account_1_balance_after, transfer_amount_1);
let account_1_balance_before = account_1_balance_after;

let sender_balance_after = cep18_check_balance_of(builder, cep18_token, sender1);
assert_eq!(
sender_balance_after,
sender_balance_before - transfer_amount_1
);
let sender_balance_before = sender_balance_after;

// Creating the second transfer request.

let token_transfer_request_2 =
make_cep18_transfer_request(sender2, cep18_token, recipient2, transfer_amount_2);

builder
.exec(token_transfer_request_2)
.expect_success()
.commit();

// Checking prior balances against new balances.

let sender_balance_after = cep18_check_balance_of(builder, cep18_token, sender1);
assert_eq!(sender_balance_after, sender_balance_before);

let account_1_balance_after = cep18_check_balance_of(builder, cep18_token, recipient1);
assert!(account_1_balance_after < account_1_balance_before);
assert_eq!(
account_1_balance_after,
transfer_amount_1 - transfer_amount_2
);

let account_2_balance_after = cep18_check_balance_of(builder, cep18_token, recipient2);
assert_eq!(account_2_balance_after, transfer_amount_2);
}

Creating Unit Tests

Within this testing context, the tests directory includes a variety of unit tests, which verify the contract code by invoking the functions defined in the installer_request_builders.rs file.

The example below shows one of the tests. Visit GitHub to find all the available tests.

Example test querying token properties
// File https://github.com/casper-ecosystem/cep18/blob/dev/tests/src/install.rs

use casper_engine_test_support::DEFAULT_ACCOUNT_ADDR;
use casper_types::{Key, U256};

use crate::utility::{
constants::{
ALLOWANCES_KEY, BALANCES_KEY, DECIMALS_KEY, NAME_KEY, SYMBOL_KEY, TOKEN_DECIMALS,
TOKEN_NAME, TOKEN_SYMBOL, TOKEN_TOTAL_SUPPLY, TOTAL_SUPPLY_KEY,
},
installer_request_builders::{
cep18_check_balance_of, invert_cep18_address, setup, TestContext,
},
};

#[test]
fn should_have_queryable_properties() {
let (mut builder, TestContext { cep18_token, .. }) = setup();

let name: String = builder.get_value(cep18_token, NAME_KEY);
assert_eq!(name, TOKEN_NAME);

let symbol: String = builder.get_value(cep18_token, SYMBOL_KEY);
assert_eq!(symbol, TOKEN_SYMBOL);

let decimals: u8 = builder.get_value(cep18_token, DECIMALS_KEY);
assert_eq!(decimals, TOKEN_DECIMALS);

let total_supply: U256 = builder.get_value(cep18_token, TOTAL_SUPPLY_KEY);
assert_eq!(total_supply, U256::from(TOKEN_TOTAL_SUPPLY));

let owner_key = Key::Account(*DEFAULT_ACCOUNT_ADDR);

let owner_balance = cep18_check_balance_of(&mut builder, &cep18_token, owner_key);
assert_eq!(owner_balance, total_supply);

let contract_balance =
cep18_check_balance_of(&mut builder, &cep18_token, Key::Hash(cep18_token.value()));
assert_eq!(contract_balance, U256::zero());

// Ensures that Account and Contract ownership is respected and we're not keying ownership under
// the raw bytes regardless of variant.
let inverted_owner_key = invert_cep18_address(owner_key);
let inverted_owner_balance =
cep18_check_balance_of(&mut builder, &cep18_token, inverted_owner_key);
assert_eq!(inverted_owner_balance, U256::zero());
}

Running the Tests

The lib.rs file is configured to run the example integration tests via the make test command:

#[cfg(test)]
mod allowance;
#[cfg(test)]
mod install;
#[cfg(test)]
mod mint_and_burn;
#[cfg(test)]
mod transfer;
#[cfg(test)]
mod utility;

To run the tests, navigate to the parent cep18 directory and run the command:

make test

This example uses bash. If you are using a Rust IDE, you need to configure it to run the tests.

CEP-18 Token Transfers and Allowances

This document describes how to transfer CEP-18 tokens on a Casper network using the Casper client. The Exploring the CEP18 Contracts documentation contains more in depth explanations on how to find the various hashes and URefs referenced throughout this document.

Transferring CEP-18 Tokens to Another Account

The following command will invoke the transfer entry point on your instance of CEP-18, directing it to transfer 10 of the associated CEP-18 tokens to another account.

casper-client put-deploy -n http://<node IP>:<PORT> \
// The chain name of the Casper network on which your CEP-18 instance was installed.
--chain-name <CHAIN NAME>\
// The local path to your account's secret key.
--secret-key ~/casper/demo/user_a/secret_key.pem \
// The contract hash of your CEP-18 contract instance.
--session-hash hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180 \
// The name of the entry point you are invoking.
--session-entry-point "transfer" \
// The account hash of the account that you are sending CEP-18 tokens to.
--session-arg "recipient:key='account-hash-9f81014b9c7406c531ebf0477132283f4eb59143d7903a2fae54358b26cea44b" \
// The amount of CEP-18 tokens you are sending to the receiving account.
--session-arg "amount:u256='10'" \
// The gas payment you are allotting, in motes.
--payment-amount "10000000000"
Casper client command without comments
casper-client put-deploy -n http://<node IP>:<PORT> \
--chain-name <CHAIN NAME>\
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-hash hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180 \
--session-entry-point "transfer" \
--session-arg "recipient:key='account-hash-9f81014b9c7406c531ebf0477132283f4eb59143d7903a2fae54358b26cea44b" \
--session-arg "amount:u256='50'" \
--payment-amount "10000000000"

This command will return a deploy hash that you can query using casper-client get-deploy. Querying the Deploy allows you to verify execution success, but you will need to use the check_balance_of entry point on the utility contract to verify the account's balance.

Invoking the check_balance_of Entry Point

The following Casper client command invokes the check_balance_of entry point on the cep18_test_contract.

casper-client put-deploy -n http://<node IP>:<PORT>\
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_test_contract" \
--session-entry-point "check_balance_of" \
// This is the contract hash of your CEP-18 contract instance, passed in as an `account-hash-`.
--session-arg "token_contract:account_hash='account-hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180'" \
// This is the account hash of the account you are checking the balance of.
--session-arg "address:key='account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000
Casper client command without comments
casper-client put-deploy -n http://<node IP>:<PORT>\
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_test_contract" \
--session-entry-point "check_balance_of" \
--session-arg "token_contract:account_hash='account-hash-b568f50a64acc8bbe43462ffe243849a88111060b228dacb8f08d42e26985180'" \
--session-arg "address:key='account-hash-303c0f8208220fe9a4de40e1ada1d35fdd6c678877908f01fddb2a56502d67fd'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000

After sending this command, you will need to query the results URef within the NamedKeys of your cep18_test_contract utility contract instance. More information on finding this URef can be found in the Exploring the CEP18 Contracts document.

You can use the following command to query global state for the results URef.

casper-client query-global-state -n http://<NODE IP>:<PORT> \
// This is the `results` URef location from your `cep18_test_contract` `NamedKeys`
--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \
--state-root-hash 3aecd0e4b6ec29ee7c1eed701132eabfe6e66a1e0f1595c9c65bfed447e474f7
Casper client command without comments
casper-client query-global-state -n http://<NODE IP>:<PORT> \
--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \
--state-root-hash 3aecd0e4b6ec29ee7c1eed701132eabfe6e66a1e0f1595c9c65bfed447e474f7

This command should show something similar to the following in response, with parsed being the amount of CEP-18 tokens that the account holds.

{
"id": -8841145064950441692,
"jsonrpc": "2.0",
"result": {
"api_version": "1.0.0",
"block_header": null,
"merkle_proof": "[3796 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "010a",
"cl_type": "U256",
"parsed": "10"
}
}
}
}

Approving an Allowance for Another Account

The Casper fungible token contract features an allowance entry point that allows an account to delegate another account to spend a preset number of CEP-18 tokens from their balance.

Approving an Account to Spend Tokens on Another Account's Behalf

The following command approves a third-party account to spend an allowance of 15 CEP-18 tokens from the balance of the account that sent the CEP-18 instance.

casper-client put-deploy -n http://<node IP>:<PORT>\
--chain-name <CHAIN NAME> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
// This is the contract hash of the CEP-18 token contract.
--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \
--session-entry-point "approve" \
// This is the account hash of the account that will receive an allowance from the balance of the account that sent the Deploy.
--session-arg "spender:key='account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513'" \
// This is the number of CEP-18 tokens included in the allowance.
--session-arg "amount:u256='15'" \
--payment-amount "10000000000"
Casper client command without comments
casper-client put-deploy -n http://<node IP>:<PORT>\
--chain-name <CHAIN NAME> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \
--session-entry-point "approve" \
--session-arg "spender:key='account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513'" \
--session-arg "amount:u256='15'" \
--payment-amount "10000000000"

Verifying a Previously Issued Allowance

After approving an account to spend an allowance of tokens, we can verify the allotted allowance by using the utility contract. The following command will write the allowance of the spender's account to the result URef of in the utility contract's NamedKeys:

casper-client put-deploy -n http://<node IP>:<PORT>\
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_test_contract" \
--session-entry-point "check_allowance_of" \
// This is the contract hash for the CEP-18 token.
--session-arg "token_contract:account_hash='account-hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e'" \
// This is the account hash for the account that owns the CEP-18 tokens.
--session-arg "owner:key='account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2'" \
// This is the account hash for the account previously authorized to spend an allowance of the owning account's CEP-18 tokens.
--session-arg "spender:key='account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513'" \
--chain-name <CHAIN NAME> \
--payment-amount 10000000000
Casper client command without comments
casper-client put-deploy -n http://<node IP>:<PORT>\
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_test_contract" \
--session-entry-point "check_allowance_of" \
--session-arg "token_contract:account_hash='account-hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e'" \
--session-arg "owner:key='account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2'" \
--session-arg "spender:key='account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513'" \
--chain-name <CHAIN NAME> \
--payment-amount 10000000000

The following command queries global state to return the value stored under the result URef:

casper-client query-global-state -n http://<node IP>:<PORT> \
// This is the previously identified `result` URef from the utility contract's `NamedKeys`
--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \
--state-root-hash e64f877f65df26db74300bb175c244d589bd88a23b91abf9ceb73ac5e65e90f1
Casper client command without comments
casper-client query-global-state -n http://<node IP>:<PORT> \
--key uref-a46ad389b53715d9991a513c8ca48e1502facc4c563c0700a31e830c4cb8a7d4-007 \
--state-root-hash e64f877f65df26db74300bb175c244d589bd88a23b91abf9ceb73ac5e65e90f1

You should get a response similar to the following:

{
"id": -9142472925449984061,
"jsonrpc": "2.0",
"result": {
"api_version": "1.0.0",
"block_header": null,
"merkle_proof": "[3796 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "010f",
"cl_type": "U256",
"parsed": "15"
}
}
}
}

Transferring Tokens from an Allowance

The following command allows an account to transfer CEP-18 tokens held by another account up to their approved allowance.

casper-client put-deploy -n http://<NODE IP>:<PORT> \
--chain-name <CHAIN NAME> \
// This is the secret key for the account that is spending their `allowance` from another account's balance.
--secret-key ~/casper/demo/user_a/secret_key.pem \
// This is the CEP-18 token contract.
--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \
--session-entry-point "transfer_from" \
// This is the account hash of the account that holds the CEP-18 in their balance.
--session-arg "owner:key='account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2'" \
// This is the account hash of the account that will receive the transferred CEP-18 tokens.
--session-arg "recipient:key='account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513'" \
// This is the amount of tokens to be transferred. If this amount exceeds the `allowance` of the account sending the Deploy, it will fail.
--session-arg "amount:u256='10'" \
--payment-amount "10000000000"
Casper client command without comments
casper-client put-deploy -n http://<NODE IP>:<PORT> \
--chain-name <CHAIN NAME> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-hash hash-05d893e76c731729fc26339e5a970bd79fbf4a6adf743c8385431fb494bff45e \
--session-entry-point "transfer_from" \
--session-arg "owner:key='account-hash-39f15c23df9be1244572bb499fac62cbcad3cab2dc1438609842f602f943d7d2'" \
--session-arg "recipient:key='account-hash-17192017d32db5dc9f598bf8ac6ac35ee4b64748669b00572d88335941479513'" \
--session-arg "amount:u256='10'" \
--payment-amount "10000000000"

Increasing and Decreasing an Allowance

Increasing an Allowance

The following command increases the designated allowance for the provided account.

casper-client put-deploy -n http://<NODE IP>:<PORT> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_contract_package_CEP18" \
--session-entry-point "increase_allowance" \
// This is the account hash of the previously authorized allowance account.
--session-arg "spender:key='account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd'" \
// This is the additional number of CEP-18 tokens that the authorized account may spend.
--session-arg "amount:U256='10'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000
Casper client command without comments
casper-client put-deploy -n http://<NODE IP>:<PORT> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_contract_package_CEP18" \
--session-entry-point "increase_allowance" \
--session-arg "spender:key='account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd'" \
--session-arg "amount:U256='10'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000

Decreasing an Allowance

The following command decreases the designated allowance for the provided account.

casper-client put-deploy -n http://<NODE IP>:<PORT> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_contract_package_CEP18" \
--session-entry-point "decrease_allowance" \
// This is the account hash of the previously authorized allowance account.
--session-arg "spender:key='account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd'" \
// This is the additional number of CEP-18 tokens that the authorized account may spend.
--session-arg "amount:U256='10'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000
Casper client command without comments
casper-client put-deploy -n http://<NODE IP>:<PORT> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_contract_package_CEP18" \
--session-entry-point "decrease_allowance" \
--session-arg "spender:key='account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd'" \
--session-arg "amount:U256='10'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000

Minting and Burning Additional CEP-18 Tokens

Minting Additional Tokens

If the contract allows for minting, the following command will mint a number of CEP-18 tokens directly to the provided account. This increases the total supply of the token in question.

casper-client put-deploy -n http://<NODE IP>:<PORT> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_contract_package_CEP18" \
--session-entry-point "mint" \
// This is the account that will receive the newly minted CEP-18 tokens.
--session-arg "owner:key='account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd'" \
// This is the number of additional CEP-18 tokens to add to the total supply.
--session-arg "amount:U256='10'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000
Casper client command without comments
casper-client put-deploy -n http://<NODE IP>:<PORT> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_contract_package_CEP18" \
--session-entry-point "mint" \
--session-arg "owner:key='account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd'" \
--session-arg "amount:U256='10'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000

Burning Tokens

If the contract allows for burning, the following command will burn a number of CEP-18 tokens directly from the provided account. This decreases the total supply of the token in question.

casper-client put-deploy -n http://<NODE IP>:<PORT> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_contract_package_CEP18" \
--session-entry-point "burn" \
// This is the account that the tokens will be burned from.
--session-arg "owner:key='account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd'" \
// This is the number of CEP-18 tokens to remove from the total supply.
--session-arg "amount:U256='10'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000
Casper client command without comments
casper-client put-deploy -n http://<NODE IP>:<PORT> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_contract_package_CEP18" \
--session-entry-point "burn" \
// This is the account that the tokens will be burned from.
--session-arg "owner:key='account-hash-683f53f56926f54ef9584b07585b025c68415dc05f7b2e56749153574b83d5cd'" \
// This is the number of CEP-18 tokens to remove from the total supply.
--session-arg "amount:U256='10'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000

Changing Account Security Permissions

The change_security entrypoint can be used by an account with admin access to alter the security level of other accounts.

There are five security levels, with the strongest level taking precedence over any other assigned levels. In order of highest strength to lowest:

  1. None - None overrides other security levels and removes all admin, minting and burning access of an account.

  2. Admin - Allows the account full access and control over the CEP-18 contract.

  3. MintAndBurn - Allows the account to mint new tokens and burn existing tokens.

  4. Burner - The account can burn tokens.

  5. Minter - The account can mint new tokens.

Here is an example of a session-arg that provides a list of account hashes to be included on the mint_and_burn_list:

--session-arg "mint_and_burn_list:string='account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7,account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34,account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655'"

Be aware that removing all admin accounts will lock out all admin functionality.

The following command can be supplied with any of the optional arguments above:

casper-client put-deploy -n http://<NODE IP>:<PORT> \
--secret-key ~/casper/demo/user_a/secret_key.pem \
--session-package-name "cep18_contract_package_CEP18" \
--session-entry-point "change_security" \
/// The following arguments are all optional and each consists of a string of the account hashes to be added to the list specified, separated by commas.
--session-arg "none_list:string:'<List of account hashes>'" \
--session-arg "admin_list:string:'<List of account hashes>'" \
--session-arg "mint_and_burn_list:string:'<List of account hashes>'" \
--session-arg "burner_list:string:'<List of account hashes>'" \
--chain-name <CHAIN NAME> \
--payment-amount 1000000000

Next Steps

CEP-78 Enhanced NFT Standard Introduction

Usage

Building the Contract

The main.rs file within the contract provides the installer for the NFT contract. Users can compile the contract to Wasm using the make build-contract command from the Makefile provided.

The pre-built Wasm for the contract and all other utility session code can be found as part of the most current release. Users wishing to build the Wasm themselves can pull the code and use the make build-contract command provided in the Makefile. Please note, however, that you must install wasm-strip to build the contract.

The call method will install the contract with the necessary entrypoints and call the init() entrypoint, which allows the contract to self-initialize and set up the necessary state variables for operation.

Required Runtime Arguments

The following are the required runtime arguments that must be passed to the installer session code to correctly install the NFT contract. For more information on the modalities that these arguments set, please refer to the Modalities documentation.

  • "collection_name": The name of the NFT collection, passed in as a String. This parameter is required and cannot be changed post installation.
  • "collection_symbol": The symbol representing a given NFT collection, passed in as a String. This parameter is required and cannot be changed post installation.
  • "total_token_supply": The total number of NFTs that a specific instance of a contract will mint passed in as a U64 value. This parameter is required.
  • "ownership_mode": The OwnershipMode modality that dictates the ownership behavior of the NFT contract. This argument is passed in as a u8 value and is required at the time of installation.
  • "nft_kind": The NFTKind modality that specifies the off-chain items represented by the on-chain NFT data. This argument is passed in as a u8 value and is required at the time of installation.
  • "json_schema": The JSON schema for the NFT tokens that will be minted by the NFT contract passed in as a String. This parameter is required if the metadata kind is set to CustomValidated(3) and cannot be changed post installation.
  • "nft_metadata_kind": The base metadata schema for the NFTs to be minted by the NFT contract. This argument is passed in as a u8 value and is required at the time of installation.
  • "identifier_mode": The NFTIdentifierMode modality dictates the primary identifier for NFTs minted by the contract. This argument is passed in as a u8 value and is required at the time of installation.
  • "metadata_mutability": The MetadataMutability modality dictates whether the metadata of minted NFTs can be updated. This argument is passed in as a u8 value and is required at the time of installation.

The following are the optional parameters that can be passed in at the time of installation.

  • "minting_mode": The MintingMode modality that dictates the access to the mint() entry-point in the NFT contract. This is an optional parameter that will default to restricting access to the installer of the contract. This parameter cannot be changed once the contract has been installed.

  • "allow_minting": The "allow_minting" flag allows the installer of the contract to pause the minting of new NFTs. The allow_minting is a boolean toggle that allows minting when true. If not provided at install the toggle will default to true. This value can be changed by the installer by calling the set_variables() entrypoint.

  • "whitelist_mode": The WhitelistMode modality dictates whether the contract whitelist can be updated. This optional parameter will default to an unlocked whitelist that can be updated post installation. This parameter cannot be changed once the contract has been installed.

  • "holder_mode": The NFTHolderMode modality dictates which entities can hold NFTs. This is an optional parameter and will default to a mixed mode allowing either Accounts or Contracts to hold NFTs. This parameter cannot be changed once the contract has been installed.

  • "contract_whitelist": The contract whitelist is a list of contract hashes that specifies which contracts can call the mint() entrypoint to mint NFTs. This is an optional parameter which will default to an empty whitelist. This value can be changed via the set_variables post installation. If the whitelist mode is set to locked, a non-empty whitelist must be passed; else, installation of the contract will fail.

  • "burn_mode": The BurnMode modality dictates whether minted NFTs can be burnt. This is an optional parameter and will allow tokens to be burnt by default. This parameter cannot be changed once the contract has been installed.

  • "owner_reverse_lookup_mode": The OwnerReverseLookupMode modality dictates whether the lookup for owners to token identifiers is available. This is an optional parameter and will not provide the lookup by default. This parameter cannot be changed once the contract has been installed.

  • "events_mode": The EventsMode modality selects the event schema used to record any changes that occur to tokens issued by the contract instance.

  • "additional_required_metdata": An additional metadata schema that must be included. This argument is passed in as a u8 value.

  • "optional_metdata": An optional metadata schema that may be included. This argument is passed in as a u8 value.

Example deploy

The following is an example of installing the NFT contract via a deploy using the Rust CLI Casper client. You can find more examples here.

casper-client put-deploy -n http://65.108.0.148:7777/rpc --chain-name "casper-test" --payment-amount 500000000000 -k keys/secret_key.pem --session-path contract/target/wasm32-unknown-unknown/release/contract.wasm \
--session-arg "collection_name:string='enhanced-nft-1'" \
--session-arg "collection_symbol:string='ENFT-1'" \
--session-arg "total_token_supply:u64='10'" \
--session-arg "ownership_mode:u8='0'" \
--session-arg "nft_kind:u8='1'" \
--session-arg "json_schema:string='nft-schema'" \
--session-arg "allow_minting:bool='true'" \
--session-arg "owner_reverse_lookup_mode:u8='0'" \
--session-arg "nft_metadata_kind:u8='2'" \
--session-arg "identifier_mode:u8='0'" \
--session-arg "metadata_mutability:u8='1'"

Utility Session Code

Specific entrypoints in use by the current implementation of the NFT contract require session code to accept return values passed by the contract over the Wasm boundary. In order to help with the installation and use of the NFT contract, session code for such entrypoints has been provided. It is recommended that users and DApp developers attempting to engage with the NFT contract do so with the help of the provided utility session code. The session code can be found in the client folder within the project folder.

Entrypoint nameSession code
"mint"client/mint_session
"balance_of"client/balance_of_session
"get_approvedclient/get_approved_session
"owner_of"client/owner_of_session
"transfer"client/transfer_session

Checking Token Ownership

Learn to check token ownership starting with version v1.1.1. The OwnerReverseLookupMode modality must be set to Complete as described here.

Upgrading to Version 1.1.1

Upgrade to v1.1.1 using a Standard NamedKey Convention or a Custom NamedKey Convention.

Installing and Interacting with the Contract using the Rust Casper Client

You can find instructions on installing an instance of the CEP-78 contract using the Rust CLI Casper client here.

Test Suite and Specification

The expected behavior of the NFT contract implementation is asserted by its test suite found in the tests folder. The test suite and the corresponding unit tests comprise the specification around the contract and outline the expected behaviors of the NFT contract across the entire range of possible configurations (i.e modalities and toggles like allow minting). The test suite ensures that as new modalities are added, and current modalities are extended, no regressions and conflicting behaviors are introduced. The test suite also asserts the correct working behavior of the utility session code provided in the client folder. The tests can be run by using the provided Makefile and running the make test command.

Error Codes

CodeError
1InvalidAccount
2MissingInstaller
3InvalidInstaller
4UnexpectedKeyVariant
5MissingTokenOwner
6InvalidTokenOwner
7FailedToGetArgBytes
8FailedToCreateDictionary
9MissingStorageUref
10InvalidStorageUref
11MissingOwnerUref
12InvalidOwnersUref
13FailedToAccessStorageDictionary
14FailedToAccessOwnershipDictionary
15DuplicateMinted
16FailedToConvertCLValue
17MissingCollectionName
18InvalidCollectionName
19FailedToSerializeMetaData
20MissingAccount
21MissingMintingStatus
22InvalidMintingStatus
23MissingCollectionSymbol
24InvalidCollectionSymbol
25MissingTotalTokenSupply
26InvalidTotalTokenSupply
27MissingTokenID
28InvalidTokenIdentifier
29MissingTokenOwners
30MissingAccountHash
31InvalidAccountHash
32TokenSupplyDepleted
33MissingOwnedTokensDictionary
34TokenAlreadyBelongsToMinterFatal
35FatalTokenIdDuplication
36InvalidMinter
37MissingMintingMode
38InvalidMintingMode
39MissingInstallerKey
40FailedToConvertToAccountHash
41InvalidBurner
42PreviouslyBurntToken
43MissingAllowMinting
44InvalidAllowMinting
45MissingNumberOfMintedTokens
46InvalidNumberOfMintedTokens
47MissingTokenMetaData
48InvalidTokenMetaData
49MissingApprovedAccountHash
50InvalidApprovedAccountHash
51MissingApprovedTokensDictionary
52TokenAlreadyApproved
53MissingApproveAll
54InvalidApproveAll
55MissingOperator
56InvalidOperator
57Phantom
58ContractAlreadyInitialized
59MintingIsPaused
60FailureToParseAccountHash
61VacantValueInDictionary
62MissingOwnershipMode
63InvalidOwnershipMode
64InvalidTokenMinter
65MissingOwnedTokens
66InvalidAccountKeyInDictionary
67MissingJsonSchema
68InvalidJsonSchema
69InvalidKey
70InvalidOwnedTokens
71MissingTokenURI
72InvalidTokenURI
73MissingNftKind
74InvalidNftKind
75MissingHolderMode
76InvalidHolderMode
77MissingWhitelistMode
78InvalidWhitelistMode
79MissingContractWhiteList
80InvalidContractWhitelist
81UnlistedContractHash
82InvalidContract
83EmptyContractWhitelist
84MissingReceiptName
85InvalidReceiptName
86InvalidJsonMetadata
87InvalidJsonFormat
88FailedToParseCep78Metadata
89FailedToParse721Metadata
90FailedToParseCustomMetadata
91InvalidCEP78Metadata
92FailedToJsonifyCEP78Metadata
93InvalidNFT721Metadata
94FailedToJsonifyNFT721Metadata
95InvalidCustomMetadata
96MissingNFTMetadataKind
97InvalidNFTMetadataKind
98MissingIdentifierMode
99InvalidIdentifierMode
100FailedToParseTokenId
101MissingMetadataMutability
102InvalidMetadataMutability
103FailedToJsonifyCustomMetadata
104ForbiddenMetadataUpdate
105MissingBurnMode
106InvalidBurnMode
107MissingHashByIndex
108InvalidHashByIndex
109MissingIndexByHash
110InvalidIndexByHash
111MissingPageTableURef
112InvalidPageTableURef
113MissingPageLimit
114InvalidPageLimit
115InvalidPageNumber
116InvalidPageIndex
117MissingUnmatchedHashCount
118InvalidUnmatchedHashCount
119MissingPackageHashForUpgrade
120MissingPageUref
121InvalidPageUref
122CannotUpgradeWithZeroSupply
123CannotInstallWithZeroSupply
124MissingMigrationFlag
125InvalidMigrationFlag
126ContractAlreadyMigrated
127UnregisteredOwnerInMint
128UnregisteredOwnerInTransfer
129MissingReportingMode
130InvalidReportingMode
131MissingPage
132UnregisteredOwnerFromMigration
133ExceededMaxTotalSupply
134MissingCep78PackageHash
135InvalidCep78InvalidHash
136InvalidPackageHashName
137InvalidAccessKeyName
138InvalidCheckForUpgrade
139InvalidNamedKeyConvention
140OwnerReverseLookupModeNotTransferable
141InvalidAdditionalRequiredMetadata
142InvalidOptionalMetadata
143MissingOptionalNFTMetadataKind
144InvalidOptionalNFTMetadataKind
145MissingAdditionalNFTMetadataKind
146InvalidAdditionalNFTMetadataKind
147InvalidRequirement
148MissingEventsMode
149InvalidEventsMode
150CannotUpgradeToMoreSupply
151MissingOperatorDict
152MissingApprovedDict
153MissingSpenderAccountHash
154InvalidSpenderAccountHash
155MissingOwnerTokenIdentifierKey
156InvalidTransferFilterContract
157MissingTransferFilterContract
158TransferFilterContractNeedsTransferableMode
159TransferFilterContractDenied
160MissingACLWhiteList
161InvalidACLWhitelist
162EmptyACLWhitelist

CEP-78 JavaScript Client Tutorial

This tutorial outlines the usage of the JavaScript client available for the CEP-78 Enhanced NFT Standard.

Further information on the CEP-78 Enhanced NFT Standard can be found here.

The client is available in npm as casper-cep78-js-client.

Client Installation

The client can be installed in a project you have built using TypeScript / Javascript.

To install run:

npm install casper-cep78-js-client

Installing a CEP-78 Contract using the JavaScript Client

The install method crafts a Deploy using InstallArgs. As with every deploy created by the SDK, you can send it using the .send(rpcUrl) method providing the RPC URL that you want to use. It will return deployHash.


const cc = new CEP78Client(process.env.NODE_URL!, process.env.NETWORK_NAME!);

const installDeploy = await cc.install(
{
collectionName: "my-collection",
collectionSymbol: "MY-NFTS",
totalTokenSupply: "1000",
ownershipMode: NFTOwnershipMode.Transferable,
nftKind: NFTKind.Physical,
jsonSchema: {
properties: {
color: { name: "color", description: "", required: true },
size: { name: "size", description: "", required: true },
material: { name: "material", description: "", required: true },
condition: { name: "condition", description: "", required: false },
},
},
nftMetadataKind: NFTMetadataKind.CustomValidated,
identifierMode: NFTIdentifierMode.Ordinal,
metadataMutability: MetadataMutability.Immutable,
mintingMode: MintingMode.Installer,
ownerReverseLookupMode: OwnerReverseLookupMode.Complete
},
"250000000000",
FAUCET_KEYS.publicKey,
[FAUCET_KEYS]
);

const hash = await installDeploy.send(process.env.http://localhost:11101/rpc);

InstallArgs are specified as follows:

  • collectionName - The name of the NFT collection, passed in as a String. This parameter is required and cannot be changed post installation.

  • collectionSymbol - The symbol representing a given NFT collection, passed in as a String. This parameter is required and cannot be changed post installation.

  • totalTokenSupply - The total number of NFTs that a specific contract instance will mint passed in as a U64 value. This parameter is required and cannot be changed post installation.

  • ownershipMode - The OwnershipMode modality that dictates the ownership behavior of the NFT contract. This argument is passed in as a u8 value and is required at the time of installation.

  • nftKind - The NFTKind modality that specifies the off-chain items represented by the on-chain NFT data. This argument is passed in as a u8 value and is required at the time of installation.

  • jsonSchema - The JSON schema for the NFT tokens that will be minted by the NFT contract passed in as a String. More information on NFTMetadataKind can be found here. This parameter may be left empty if metadata kind is set to Raw(3). If the metadata kind is set to CustomValidated(4), it will require a specifically formatted custom schema. This parameter cannot be changed post installation.

  • nftMetadataKind - The metadata schema for the NFTs to be minted by the NFT contract. This argument is passed in as a u8 value and is required at the time of installation.

  • identifierMode - The NFTIdentifierMode modality dictates the primary identifier for NFTs minted by the contract. This argument is passed in as a u8 value and is required at the time of installation.

  • metadataMutability - The MetadataMutability modality dictates whether the metadata of minted NFTs can be updated. This argument is passed in as a u8 value and is required at the time of installation.

  • mintingmode - The MintingMode modality dictates the access to the mint() entry point in the NFT contract. This optional parameter will default to restricting access to the installer of the contract. This parameter cannot be changed once the contract has been installed.

  • holdermode - The NFTHolderMode modality dictates which entities can hold NFTs. This optional parameter will default to a mixed mode, allowing either Accounts or Contracts to hold NFTs. This parameter cannot be changed once the contract has been installed.

  • burnMode - The BurnMode modality dictates whether minted NFTs can be burned. This optional parameter will allow tokens to be burnt by default. This parameter cannot be changed once the contract has been installed.

  • ownerReverseLookupMode - The OwnerReverseLookupMode dictates whether the contract will index ownership of tokens as outlined here to allow lookup of owned tokens by account. This parameter cannot be changed once the contract has been installed.

Further information on CEP-78 modality options can be found here.

Minting a Token

The CEP-78 JS Client includes code to construct a deploy that will Mint a token, as follows:

const mintDeploy = cc.mint(
{
owner: FAUCET_KEYS.publicKey,
meta: {
color: "Blue",
size: "Medium",
material: "Aluminum",
condition: "Used",
},
},
{ useSessionCode: true },
"2000000000",
FAUCET_KEYS.publicKey,
[FAUCET_KEYS],
);

const mintDeployHash = await mintDeploy.send("http://localhost:11101/rpc");

The arguments adhere to those provided in the original installation, with the .send() pointing to a valid RPC URL on your target Casper network. In this instance, we are using an NCTL RPC URL.

In this example, the useSessionCode variable decides if the user will call mint using session code, or not. It will be set to true if the OwnerReverseLookupMode is set to Complete. It then registers the recipient with the contract and mints the token.

If OwnerReverseLookupMode is set to NoLookup, useSessionCode will be set to false and it will simply mint the token as it does not need to register the recipient.

Register Recipient

As we used ownerReverseLookupMode: OwnerReverseLookupMode.Complete in this contract installation, we must register the recipient. To do this, we construct a register deploy:

const registerDeploy = cc.register(
{
tokenOwner: USER1_KEYS.publicKey,
},
"1000000000",
USER1_KEYS.publicKey,
[USER1_KEYS],
);

const registerDeployHash = await registerDeploy.send("http://localhost:11101/rpc");

Transferring a Token

After minting one or more tokens, you can then use the following code to transfer the tokens between accounts:

const transferDeploy = cc.transfer(
{
tokenId: "0",
source: FAUCET_KEYS.publicKey,
target: USER1_KEYS.publicKey,
},
{ useSessionCode: true },
"13000000000",
FAUCET_KEYS.publicKey,
[FAUCET_KEYS],
);

const transferDeployHash = await transferDeploy.send("http://localhost:11101/rpc");

Transferring accepts the following arguments:

  • tokenId - The sequential ID assigned to a token in mint order.

  • source - The account sending the token in question.

  • target - The account receiving the transferred token.

As above, the useSessionCode variable determines if the user will call transfer using session code based on the setting of OwnerReverseLookupMode.

Burning a Token

The following code shows how to burn a minted NFT that you hold and have access rights to, requiring only the tokenId argument:

const burnDeploy = await contractClient.burn({ tokenId: "0" }, "13000000000", USER1_KEYS.publicKey, [USER1_KEYS]);

const burnDeployHash = await burnDeploy.send("http://localhost:11101/rpc");

Example Usages

Running an Install Example

This repository includes an example script for installing a CEP-78 contract instance.

You will need to define the following variables in the .env file:

  • NODE_URL - The address of a node. If you are testing using NCTL, this will be http://localhost:11101/rpc.

  • NETWORK_NAME - The name of the Casper network you are operating on, casper-net-1 when testing using a local network with NCTL.

  • MASTER_KEY_PAIR_PATH - The path to the key pair of the minting account.

  • USER1_KEY_PAIR_PATH - The path to an additional account's key pair for use in testing transfer features.

You may also need to install associated dependencies using:

npm i

This example can be run using the following command:

npm run example:install

The example will then return the installation's deployHash, and inform you when the installation is successful.

The example will then provide the installing account's information, which will include the CEP-78 NFT contract's hash and package hash.

Running a Usage Example

A usage example uses the same variables as the Install example above, but tests the basic functionality of the contract after installation.

The usage example can be run using the following command:

npm run example:usage

This example will acquire the contract's hash and package hash, prior to sending three separate deploys to perform several function tests as follows:

  • Mint - The example will attempt to mint an NFT using the installation account.

  • Transfer - The example will transfer the previously minted NFT to a second account (USER1 as defined in the variables.)

  • Burn - The example will burn the minted NFT.

The associated code for these deploys may be found in the client-js/examples directory.

CEP-78 Modalities

The enhanced NFT implementation supports various 'modalities' that dictate the behavior of a specific contract instance. Modalities represent the common expectations around contract usage and behavior.

Ownership

This modality specifies the behavior regarding ownership of NFTs and whether the owner of the NFT can change over the contract's lifetime. There are three modes:

  1. Minter: Minter mode is where the ownership of the newly minted NFT is attributed to the minter of the NFT and cannot be specified by the minter. In the Minter mode the owner of the NFT will not change and thus cannot be transferred to another entity.
  2. Assigned: Assigned mode is where the owner of the newly minted NFT must be specified by the minter of the NFT. In this mode, the assigned entity can be either minter themselves or a separate entity. However, similar to the Minter mode, the ownership in this mode cannot be changed, and NFTs minted in this mode cannot be transferred from one entity to another.
  3. Transferable: In the Transferable mode the owner of the newly minted NFT must be specified by the minter. However, in the Transferable mode, NFTs can be transferred from the owner to another entity.

In all the three mentioned modes, the owner entity is currently restricted to Accounts on the Casper network.

Note: In the Transferable mode, it is possible to transfer the NFT to an Account that does not exist.

This Ownership mode is a required installation parameter and cannot be changed once the contract has been installed. The mode is passed in as u8 value to the "ownership_mode" runtime argument.

Ownershipu8
Minter0
Assigned1
Transferable2

The ownership mode of a contract can be determined by querying the ownership_mode entry within the contract's NamedKeys.

NFTKind

The NFTKind modality specifies the commodity that NFTs minted by a particular contract will represent. Currently, the NFTKind modality does not alter or govern the behavior of the contract itself and only exists to specify the correlation between on-chain data and off-chain items. There are three different variations of the NFTKind mode.

  1. Physical: The NFT represents a real-world physical item e.g., a house.
  2. Digital: The NFT represents a digital item, e.g., a unique JPEG or digital art.
  3. Virtual: The NFT is the virtual representation of a physical notion, e.g., a patent or copyright.

The NFTKind mode is a required installation parameter and cannot be changed once the contract has been installed. The mode is passed in as a u8 value to nft_kind runtime argument.

NFTKindu8
Physical0
Digital1
Virtual2

NFTHolderMode

The NFTHolderMode dictates which entities on a Casper network can own and mint NFTs. There are three different options currently available:

  1. Accounts: In this mode, only Accounts can own and mint NFTs.
  2. Contracts: In this mode, only Contracts can own and mint NFTs.
  3. Mixed: In this mode both Accounts and Contracts can own and mint NFTs.

If the NFTHolderMode is set to Contracts a ContractHash whitelist must be provided. This whitelist dictates which Contracts are allowed to mint NFTs in the restricted Installer minting mode.

NFTHolderModeu8
Accounts0
Contracts1
Mixed2

This modality is an optional installation parameter and will default to the Mixed mode if not provided. However, this mode cannot be changed once the contract has been installed. The mode is passed in as a u8 value to nft_holder_mode runtime argument.

WhitelistMode

The WhitelistMode dictates if the ACL whitelist restricting access to the mint entry point can be updated. There are currently two options:

  1. Unlocked: The ACL whitelist is unlocked and can be updated via the set variables endpoint.
  2. Locked: The ACL whitelist is locked and cannot be updated further.

If the WhitelistMode is set to Locked an ACL whitelist of entity keys must be provided on installation. This whitelist dictates which entities can mint NFTs in the restricted ACL minting mode. These entities include Accounts and/or Contracts.

This WhitelistMode is an optional installation parameter and will be set to unlocked if not passed. However, the whitelist mode itself cannot be changed once the contract has been installed. The mode is passed in as a u8 value to whitelist_mode runtime argument.

WhitelistModeu8
Unlocked0
Locked1

Minting

The minting mode governs the behavior of contract when minting new tokens. The minting modality provides two options:

  1. Installer: This mode restricts the ability to mint new NFT tokens only to the installing account of the NFT contract.
  2. Public: This mode allows any account to mint NFT tokens.
  3. ACL: This mode allows whitelisted accounts or contracts to mint NFT tokens.

This modality is an optional installation parameter and will default to the Installer mode if not provided. However, this mode cannot be changed once the contract has been installed. The mode is set by passing a u8 value to the minting_mode runtime argument.

MintingModeu8
Installer0
Public1
ACL2

NFTMetadataKind

This modality dictates the schema for the metadata for NFTs minted by a given instance of an NFT contract. There are four supported modalities:

  1. CEP78: This mode specifies that NFTs minted must have valid metadata conforming to the CEP-78 schema.
  2. NFT721: This mode specifies that NFTs minted must have valid metadata conforming to the NFT-721 metadata schema.
  3. Raw: This mode specifies that metadata validation will not occur and raw strings can be passed to token_metadata runtime argument as part of the call to mint entrypoint.
  4. CustomValidated: This mode specifies that a custom schema provided at the time of install will be used when validating the metadata as part of the call to mint entrypoint.

During installation, one NFTMetadataKind must be chosen as the base metadata kind for the contract instance. Additional kinds may be included using either the additional_required_metadata or optional_metadata arguments.

CEP-78 metadata example

{
"name": "John Doe",
"token_uri": "https://www.barfoo.com",
"checksum": "940bffb3f2bba35f84313aa26da09ece3ad47045c6a1292c2bbd2df4ab1a55fb"
}

NFT-721 metadata example

{
"name": "John Doe",
"symbol": "abc",
"token_uri": "https://www.barfoo.com"
}

Custom Validated

The CEP-78 implementation allows installers of the contract to provide their custom schema at the time of installation. The schema is passed as a String value to json_schema runtime argument at the time of installation. Once provided, the schema for a given instance of the contract cannot be changed.

The custom JSON schema must contain a top-level properties field. An example of a valid JSON schema is provided. In this example, each property has a name, the description of the property itself, and whether the property is required to be present in the metadata. If the metadata kind is not set to custom validated, then the value passed to the json_schema runtime argument will be ignored.

Example Custom Validated schema

{
"properties": {
"deity_name": {
"name": "deity_name",
"description": "The name of deity from a particular pantheon.",
"required": true
},
"mythology": {
"name": "mythology",
"description": "The mythology the deity belongs to.",
"required": true
}
}
}

Example Custom Metadata

{
"deity_name": "Baldur",
"mythology": "Nordic"
}
NFTMetadataKindu8
CEP780
NFT7211
Raw2
CustomValidated3

NFTIdentifierMode

The identifier mode governs the primary identifier for NFTs minted for a given instance on an installed contract. This modality provides two options:

  1. Ordinal: NFTs minted in this modality are identified by a u64 value. This value is determined by the number of NFTs minted by the contract at the time the NFT is minted.
  2. Hash: NFTs minted in this modality are identified by a base16 encoded representation of the blake2b hash of the metadata provided at the time of mint.

Since the primary identifier in the Hash mode is derived by hashing over the metadata, making it a content-addressed identifier, the metadata for the minted NFT cannot be updated after the mint.

Attempting to install the contract with the MetadataMutability modality set to Mutable in the Hash identifier mode will raise an error.

This modality is a required installation parameter and cannot be changed once the contract has been installed.

It is passed in as a u8 value to the identifier_mode runtime argument.

NFTIdentifierModeu8
Ordinal0
Hash1

Metadata Mutability

The metadata mutability mode governs the behavior around updates to a given NFTs metadata. This modality provides two options:

  1. Immutable: Metadata for NFTs minted in this mode cannot be updated once the NFT has been minted.
  2. Mutable: Metadata for NFTs minted in this mode can update the metadata via the set_token_metadata entrypoint.

The Mutable option cannot be used in conjunction with the Hash modality for the NFT identifier; attempting to install the contract with this configuration raises InvalidMetadataMutability error. This modality is a required installation parameter and cannot be changed once the contract has been installed. It is passed in as a u8 value to the metadata_mutability runtime argument.

MetadataMutabilityu8
Immutable0
Mutable1

BurnMode

The BurnMode modality dictates whether tokens minted by a given instance of an NFT contract can be burnt. This modality provides two options:

  1. Burnable: Minted tokens can be burnt.
  2. NonBurnable: Minted tokens cannot be burnt.
BurnModeu8
Burnable0
NonBurnable1

This modality is an optional installation parameter and will default to the Burnable mode if not provided. However, this mode cannot be changed once the contract has been installed. The mode is set by passing a u8 value to the burn_mode runtime argument.

OwnerReverseLookupMode

The OwnerReverseLookupMode modality is set at install and determines if a given contract instance writes necessary data to allow reverse lookup by owner in addition to by ID.

This modality provides the following options:

  1. NoLookup: The reporting and receipt functionality is not supported. In this option, the contract instance does not maintain a reverse lookup database of ownership and therefore has more predictable gas costs and greater scaling.
  2. Complete: The reporting and receipt functionality is supported. Token ownership will be tracked by the contract instance using the system described here.
  3. TransfersOnly: The reporting and receipt functionality is supported like Complete. However, it does not begin tracking until the first transfer. This modality is for use cases where the majority of NFTs are owned by a private minter and only NFT's that have been transferred benefit from reverse lookup tracking. Token ownership will also be tracked by the contract instance using the system described here.

Additionally, when set to Complete, causes a receipt to be returned by the mint or transfer entrypoints, which the caller can store in their account or contract context for later reference.

Further, two special entrypoints are enabled in Complete mode. First, register_owner which when called will allocate the necessary tracking record for the imputed entity. This allows isolation of the one time gas cost to do this per owner, which is convenient for accounting purposes. Second, updated_receipts, which allows an owner of one or more NFTs held by the contract instance to attain up to date receipt information for the NFTs they currently own.

OwnerReverseLookupModeu8
NoLookup0
Complete1
TransfersOnly2

This modality is an optional installation parameter and will default to the NoLookup mode if not provided. The mode is set by passing a u8 value to the owner_reverse_lookup_mode runtime argument. This mode cannot be changed once the contract has been installed.

Note : if ownership_mode is set to Minter and the minting_mode is set to Installer only, OwnerReverseLookupMode will be set to NoLookup. This is because the minter, by definition, owns all of the tokens forever. Therefore, there is no reason to do a reverse lookup for that owner. This rule applies only to newly installed contract instances.

Note : if OwnerReverseLookupMode is set to TransfersOnly then ownership_mode has to be set to Transferable only. This is because other ownership modes do not allow transfer.

If you are upgrading a contract from CEP-78 version 1.0 to 1.1, OwnerReverseLookupMode will be set to Complete, as this was the standard behavior of CEP-78 1.0. In addition to being set to Complete, existing records will be migrated into the CEP-78 1.1 format, which will impose a one-time gas cost to cover the migration.

If you have an existing CEP-78 version 1.0 contract instance, and would prefer the newer functionality with no lookup, the only option is to install a separate, new contract instance and mint all of the NFTs anew in that instance and then burn the corresponding NFTs from the old instance. If you do not own all the NFTs held by the old contract instance, you do not have this option.

NamedKeyConventionMode

The NamedKeyConvention modality dictates whether the Wasm passed will attempt to install a version 1.1.1 instance of CEP-78 or attempt to migrate a version 1.0 CEP-78 instance to version 1.1.1.

This modality provides three options:

  1. DerivedFromCollectionName: This modality will signal the contract to attempt to install a new version 1.1.1 instance of the CEP-78 contract. The contract package hash and the access URef will be saved in the installing account's NamedKeys as cep78_contract_package_<collection_name> and cep78_contract_package_access_<collection_name>.
  2. V_1_0_standard: This modality will signal the contract to attempt to upgrade from version 1.0 to version 1.1.1. In this scenario, the contract will retrieve the package hash and the access URef from the NamedKey entries originally created during the 1.0 installation.
  3. V_1_0_custom: This modality will signal the contract to attempt to upgrade from version 1.0 to version 1.1.1. In this scenario, the calling account must provide the NamedKey entries under which the package hash and the access URef are saved. Additionally, this requires the passing of the runtime arguments access_key_name and hash_key_name for the access URef and package hash, respectively. In this modality, these arguments are required and must be passed in.
NamedKeyConventionu8
DerivedFromCollectionName0
V_1_0_standard1
V_1_0_custom2

EventsMode

The EventsMode modality determines how the installed instance of CEP-78 will handle the recording of events that occur from interacting with the contract.

The modality provides three options:

  1. NoEvents: This modality will signal the contract to not record events at all. This is the default mode.
  2. CEP47: This modality will signal the contract to record events using the CEP47 event schema. Further information can be found below.
  3. CES: This modality will signal the contract to record events using the Casper Event Standard.
EventsModeu8
NoEvents0
CEP471
CES2

Transfer Filter Hook

The transfer filter modality, if enabled, specifies a contract package hash pointing to a contract that will be called when the transfer method is invoked on the contract. CEP-78 will call the can_transfer method on the specified callback contract, which is expected to return a value of TransferFilterContractResult, represented as a u8.

  • TransferFilterContractResult::DenyTransfer will block the transfer regardless of the outcome of other checks
  • TransferFilterContractResult::ProceedTransfer will allow the transfer to proceed if other checks also pass

The transfer filter can be enabled by passing a ARG_TRANSFER_FILTER_CONTRACT argument to the install method, with a value of type Option<Key>

CEP47 Mode

The CEP47 EventsMode modality mimics the event schema previously used in the CEP47 NFT standard. Events are stored as a BTreeMap within a dictionary (EVENTS) in the contract's context. Entries consist of the PREFIX_HASH_KEY_NAME, followed by the EVENT_TYPE and then variable data as listed in the table below. The events can be retrieved directly via their dictionary entry using the JSON-RPC, with more information on this process available here.

Event nameIncluded values and type
Mintrecipient (Key), token_id (String)
Transferowner (Key), operator (Option<Key>), recipient (Key), token_id (String)
Burnowner (Key), token_id (String)
ApprovalGrantedowner (Key), spender (Key), token_id (String)
ApprovalRevokedowner (Key), token_id (String)
ApprovalForAllowner (Key), operator (Key)
RevokedForAllowner (Key), operator (Key)
MetadataUpdatetoken_id (String)
Migration-
VariablesSet-

Casper Event Standard

CES is an option within the EventsMode modality that determines how changes to tokens issued by the contract instance will be recorded. Any changes are recorded in the __events dictionary and can be observed via a node's Server Side Events stream. They may also be viewed by querying the dictionary at any time using the JSON-RPC interface.

The emitted events are encoded according to the Casper Event Standard, and the schema is visible to an observer reading the __events_schema contract named key.

For this CEP-78 reference implementation, the events schema is as follows:

Event nameIncluded values and type
Mintrecipient (Key), token_id (String), data (String)
Transferowner (Key), operator (Option<Key>), recipient (Key), token_id (String)
Burnowner (Key), token_id (String)
Approvalowner (Key), spender (Key), token_id (String)
ApprovalRevokedowner (Key), token_id (String)
ApprovalForAllowner (Key), operator (Key)
RevokedForAllowner (Key), operator (Key)
MetadataUpdatedtoken_id (String), data (String)
Migration-
VariablesSet-

Modality Conflicts

The MetadataMutability option set to Mutable cannot be used in conjunction with the NFTIdentifierMode modality set to Hash.

Owner Reverse Lookup Functionality

In version 1.0 of the CEP-78 Enhanced NFT Standard contract, tracking minted tokens consisted of a single, unbounded list that would grow in size with each additional token. As a result, gas costs would increase over time as the list must be overwritten with each new minting. The related tutorial can be found here.

In an effort to stabilize the gas costs of larger NFT collections, version 1.1 of CEP-78 includes the use of a pre-allocated page system to track ownership of NFTs within the contract.

This system stabilizes the cost for interacting with the contract, but not the mint price itself. The size of metadata for a collection, and any differences in that metadata, will still result in some fluctuation in the price for the NFT itself. However, the cost of engaging the system itself will remain stable. Users can expect to pay a higher upfront price for page allocation, but will not need to pay this cost again for any NFTs minted within that given page.

The CEP-78 Page System

Ownership of NFTs within a CEP-78 contract is now tracked with a series of pages, with each page tracking a range of 1,000 tokens each. When installing an instance of the CEP-78 contract, the user determines the total token supply. This, in turn, determines the maximum number of pages, i.e., for a 10,000 token collection, each account could have up to 10 pages numbering from 0-9 tracking ownership of NFTs.

A page_table tracks which pages within a range have been allocated and set for a certain user. The size of the page table directly correlates to the total token supply, i.e. for a CEP-78 instance tracking 10,000 tokens, the page table would be 10 bits wide. For a total of 20,000 it would be 20 bits wide. The cost of the initial page table allocation depends on the overall total size of a collection, with larger collections possessing correspondingly greater gas costs. To make initial minting costs more stable across contracts, the process of allocating a page table has been shifted to the register_owner entrypoint.

After registering as an owner, the contract creates an entry within the page_table dictionary for the minting account or contract. This dictionary entry consists of a series of boolean values amounting to the total number of pages in the collection. In our 10,000 token example, this would be 10 bits set to false.

Upon minting the token, the user will pay for a page allocation. This adds them to the page dictionary, in which each entry corresponds to a specific account or contract that owns tokens within that page. That account or contract's entry in the page dictionary will consist of 1,000 page_address bits set to False upon allocation, and the minting of any given token in that page will set the page_address bit to True.

In addition, that account or contract's page_table will be updated by marking the corresponding page number's bit as True.

As an example, consider a new user minting their first NFT with a given CEP-78 contract set to a maximum number of 10,000 tokens. They are minting the 2,350th token within that collection. The following sequence of events would occur:

  1. The contract registers their account as an owner.

  2. The contract creates a page_table dictionary for that account, with 10 boolean values. As the numbering system begins with 0, the third boolean value corresponding with page 2 is set to True.

  3. The account pays for allocation of page 2, creating an entry in the Page 2 dictionary for that account. Within that entry, there are 1,000 boolean values set to false. Minting the 2,350th token in the collection sets the corresponding page_address boolean for 350 as True.

  4. Any further tokens minted by this account prior to the 3,000th token being minted will not have to pay for additional page allocations. If the account mints a token at or beyond 3,000, they must pay for the corresponding page allocation. For example, if they decided to mint the 5,125th token in the collection, they would need to pay for page 5 to be allocated to them. They would then be added to the page 5 dictionary with the page_address boolean for 125 set as True.

This system binds the data writing costs to a maximum size of any given page dictionary.

Updated Receipts

If the contract enables OwnerReverseLookupMode, calling the updated_receipts entrypoint will return a list of receipt names alongside the dictionary for the relevant pages.

Updated receipts come in the format of "{<collection name>}\_m{modulo}\_p{<page number>}". Once again using the 2,350th token as an example, the receipt would read:

cep78_collection_m_350_p_2

You can determine the token number by multiplying the page_number by the page_size(1,000) and adding the modulo.

If the NFTIdentifierMode is set to Ordinal, this number corresponds directly to the token ID.

If it is set to Hash, you will need to reference the HASH_BY_INDEX dictionary to determine the mapping of token numbers to token hashes.

Casper Token Standards

CEP-18 Casper Fungible Token Standard

TitleDescription
A Casper Fungible Token TutorialA full tutorial for use of the CEP-18 Casper Fungible Token Standard.
Installing and Interacting with a CEP-18 ContractA quickstart guide for installing a CEP-18 contract with the Rust Casper Client.
Exploring the CEP-18 ContractsA guide to interacting with installed CEP-18 contracts.
CEP-18 Token Transfers and AllowancesA guide for transferring Casper Fungible Tokens.
Testing Framework for CEP-18A CEP-18 testing framework using the Casper engine test support crate.

CEP-78 Enhanced NFT Standard

TitleDescription
CEP-78 Enhanced NFT Standard IntroductionAn introduction to the CEP-78 Enhanced NFT Standard.
CEP-78 ModalitiesInformation on the features available when installing a CEP-78 contract instance.
Installing and Interacting with a CEP-78 ContractAn introduction to features present in the CEP-78 Enhanced NFT Standard.
Owner Reverse Lookup FunctionalityInformation on the Onwer Reverse Lookup feature of CEP-78 contracts.
A CEP-78 JavaScript Client TutorialA tutorial for using the JavaScript CEP-78 client.

Installing and Interacting with a CEP-78 Contract using the Rust Casper Client

This documentation will guide you through the process of installing and interacting with an instance of the CEP-78 enhanced NFT standard contract through Casper's Rust CLI client. The contract code installs an instance of CEP-78 as per session arguments provided at the time of installation. It requires a minimum Rust version of 1.63.0.

Information on the modalities used throughout this installation process can be found in the modalities documentation.

Installing the Contract

Installing the enhanced NFT contract to global state requires the use of a Deploy. In this case, the session code can be compiled to Wasm by running the make build-contract command provided in the Makefile at the top level. The Wasm will be found in the contract/target/wasm32-unknown-unknown/release directory as contract.wasm.

Below is an example of a casper-client command that provides all required session arguments to install a valid instance of the CEP-78 contract on global state.

  • casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" --payment-amount 500000000000 -k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem --session-path ~/casper/enhanced-nft/contract/target/wasm32-unknown-unknown/release/contract.wasm
  1. --session-arg "collection_name:string='CEP-78-collection'"

    The name of the NFT collection as a string. In this instance, "CEP-78-collection".

  2. --session-arg "collection_symbol:string='CEP78'"

    The symbol representing the NFT collection as a string. In this instance, "CEP78".

  3. --session-arg "total_token_supply:u64='100'"

    The total supply of tokens to be minted. In this instance, 100. If the contract owner is unsure of the total number of NFTs they will require, they should err on the side of caution.

  4. --session-arg "ownership_mode:u8='2'"

    The ownership mode for this contract. In this instance the 2 represents "Transferable" mode. Under these conditions, users can freely transfer their NFTs between one another.

  5. --session-arg "nft_kind:u8='1'"

    The type of commodity represented by these NFTs. In this instance, the 1 represents a digital collection.

  6. --session-arg "nft_metadata_kind:u8='0'"

    The type of metadata used by this contract. In this instance, the 0 represents CEP-78 standard for metadata.

  7. --session-arg "json_schema:string=''"

    An empty JSON string, as the contract has awareness of the CEP-78 JSON schema. Using the custom validated modality would require passing through a valid JSON schema for your custom metadata.

  8. --session-arg "identifier_mode:u8='0'"

    The mode used to identify individual NFTs. For 0, this means an ordinal identification sequence rather than by hash.

  9. --session-arg "metadata_mutability:u8='0'"

    A setting allowing for mutability of metadata. This is only available when using the ordinal identification mode, as the hash mode depends on immutability for identification. In this instance, despite ordinal identification, the 0 represents immutable metadata.

The session arguments match the available modalities as listed here.

Casper client command without comments
casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" --payment-amount 500000000000 -k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem --session-path ~/casper/enhanced-nft/contract/target/wasm32-unknown-unknown/release/contract.wasm \
--session-arg "collection_name:string='CEP-78-collection'" \
--session-arg "collection_symbol:string='CEP78'" \
--session-arg "total_token_supply:u64='100'" \
--session-arg "ownership_mode:u8='2'" \
--session-arg "nft_kind:u8='1'" \
--session-arg "nft_metadata_kind:u8='0'" \
--session-arg "json_schema:string=''" \
--session-arg "identifier_mode:u8='0'" \
--session-arg "metadata_mutability:u8='0'"

Directly Invoking Entrypoints

With the release of CEP-78 version 1.1, users that are interacting with a CEP-78 contract that does not use ReverseLookupMode should opt out of using the client Wasms provided as part of the release. Opting out in this situation is recommended, as directly invoking the entrypoints incurs a lower gas cost compared against using the provided client Wasm to invoke the entrypoint.

You may invoke the mint, transfer or burn entrypoints directly through either the contract package hash or the contract hash directly.

Specifically in the case of mint, there are fewer runtime arguments that must be provided, thereby reducing the total gas cost of minting an NFT.

Example Mint using StoredVersionByHash

casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" \ --payment-amount 7500000000 \ -k ~/secret_key.pem \
--session-package-hash hash-b3b7a74ae9ef2ea8afc06d6a0830961259605e417e95a53c0cb1ca9737bb0ec7 \
--session-entry-point "mint" \
--session-arg "token_owner:key='account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb'" \
--session-arg "token_meta_data:string='{\"name\": \"John Doe\",\"token_uri\": \"https:\/\/www.barfoo.com\",\"checksum\": \"940bffb3f2bba35f84313aa26da09ece3ad47045c6a1292c2bbd2df4ab1a55fb\"}'"

Example Transfer using StoredContractByHash

Based on the identifier mode for the given contract instance, either the token_id runtime argument must be passed in or in the case of the hash identifier mode, the token_hash runtime argument.


casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" \ --payment-amount 7500000000 \ -k ~/secret_key.pem \
--session-hash hash-b3b7a74ae9ef2ea8afc06d6a0830961259605e417e95a53c0cb1ca9737bb0ec7 \
--session-entry-point "transfer" \
--session-arg "source_key:key='account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb'" \
--session-arg "target_key:key='account-hash-b4782e7c47e4deca5bd90b7adb2d6e884f2d331825d5419d6cbfb59e17642aab'" \
--session-arg "token_id:u64='0'"

Minting an NFT

Below is an example of a casper-client command that uses the mint function of the contract to mint an NFT for the user associated with node-1 in an NCTL environment.

  • casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" --payment-amount 5000000000 -k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem --session-path ~/casper/enhanced-nft/client/mint_session/target/wasm32-unknown-unknown/release/mint_call.wasm
  1. --session-arg "nft_contract_hash:key='hash-206339c3deb8e6146974125bb271eb510795be6f250c21b1bd4b698956669f95'"

    The contract hash of the previously installed CEP-78 NFT contract from which we will be minting.

  2. --session-arg "collection_name:string='cep78_<collection_name>'"

    The collection name of the previously installed CEP-78 NFT contract from which we will be minting.

  3. --session-arg "token_owner:key='account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb'"

    The collection name of the NFT to be minted.

  4. --session-arg "token_meta_data:string='{\"name\": \"John Doe\",\"token_uri\": \"https:\/\/www.barfoo.com\",\"checksum\": \"940bffb3f2bba35f84313aa26da09ece3ad47045c6a1292c2bbd2df4ab1a55fb\"}'"

    Metadata describing the NFT to be minted, passed in as a string.

Casper client command without comments

casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" \
--payment-amount 5000000000 \
-k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem \
--session-path ~/casper/enhanced-nft/client/mint_session/target/wasm32-unknown-unknown/release/mint_call.wasm \
--session-arg "nft_contract_hash:key='hash-206339c3deb8e6146974125bb271eb510795be6f250c21b1bd4b698956669f95'" \
--session-arg "collection_name:string='cep78_<collection_name>'"` \
--session-arg "token_owner:key='account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb'" \
--session-arg "token_meta_data:string='{\"name\": \"John Doe\",\"token_uri\": \"https:\/\/www.barfoo.com\",\"checksum\": \"940bffb3f2bba35f84313aa26da09ece3ad47045c6a1292c2bbd2df4ab1a55fb\"}'"

Transferring NFTs Between Users

Below is an example of a casper-client command that uses the transfer function to transfer ownership of an NFT from one user to another. In this case, we are transferring the previously minted NFT from the user associated with node-2 to the user associated with node-3.

  • casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" --payment-amount 5000000000 -k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-2/keys/secret_key.pem --session-path ~/casper/enhanced-nft/client/transfer_session/target/wasm32-unknown-unknown/release/transfer_call.wasm
  1. --session-arg "nft_contract_hash:key='hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5'"

    The contract hash of the CEP-78 NFT Contract associated with the NFT to be transferred.

  2. --session-arg "source_key:key='account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb'"

    The account hash of the user that currently owns the NFT and wishes to transfer it.

  3. --session-arg "target_key:key='account-hash-b4772e7c47e4deca5bd90b7adb2d6e884f2d331825d5419d6cbfb59e17642aab'"

    The account hash of the user that will receive the NFT.

  4. --session-arg "is_hash_identifier_mode:bool='false'"

    Argument that the hash identifier mode is ordinal, thereby requiring a token_id rather than a token_hash.

  5. --session-arg "token_id:u64='0'"

    The token_id of the NFT to be transferred.

Casper client command without comments
casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" \
--payment-amount 5000000000 \
-k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-2/keys/secret_key.pem \
--session-path ~/casper/enhanced-nft/client/transfer_session/target/wasm32-unknown-unknown/release/transfer_call.wasm \
--session-arg "nft_contract_hash:key='hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5'" \
--session-arg "source_key:key='account-hash-e9ff87766a1d2bab2565bfd5799054946200b51b20c3ca7e54a9269e00fe7cfb'" \
--session-arg "target_key:key='account-hash-b4772e7c47e4deca5bd90b7adb2d6e884f2d331825d5419d6cbfb59e17642aab'" \
--session-arg "is_hash_identifier_mode:bool='false'" \
--session-arg "token_id:u64='0'"

Burning an NFT

Below is an example of a casper-client command that uses the burn function to burn an NFT within a CEP-78 collection. If this command is used, the NFT in question will no longer be accessible by anyone.

  • casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" --payment-amount 5000000000 -k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem
  1. --session-hash hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5

    The session hash corresponding to the NFT's contract hash.

  2. --session-entry-point "burn"

    The entrypoint corresponding to the burn function.

  3. --session-arg "token_id:u64='1'"

    The token ID for the NFT to be burned. If the identifier_mode is not set to Ordinal, you must provide the token_hash instead.

Casper client command without comments
casper-client put-deploy -n http://localhost:11101/rpc --chain-name "casper-net-1" \
--payment-amount 5000000000 \
-k ~/casper/casper-node/utils/nctl/assets/net-1/nodes/node-1/keys/secret_key.pem \
--session-hash hash-52e78ae3f6c485d036a74f65ebbb8c75fcc7c33fb42eb667fb32aeba72c63fb5 \
--session-entry-point "burn" \
--session-arg "token_id:u64='1'"

Cross-Contract Communication

This tutorial assumes that you have worked through the following examples. If you have not already done so, then we recommend that you do so now:

Tutorial Outline

This tutorial covers some variations of cross-contract communication. Most complex scenarios use cross-contract communication, so it is crucial to understand how this works. It is best explained using the uniswap v2 protocol.

Uniswap v2 protocol consists of multiple smart contracts which govern a unified blockchain application and each contract serves a different purpose. The contracts are as follows:

  • Factory
  • Pair
  • Pair (ERC20)
  • Library
  • Router01
  • Router02

The Factory contract is generally used to create a token pair. It throws an event that a pair has been created and allows the user to read the pair created. The most important to notice is that the generation of a token pair actually creates a contract of type Pair under a new address hash. The Pair smart contract is used to perform operations like mint or burn on a created pair of tokens.

Having this in mind we will be building two contracts which reference each other in some shape or form. We will look at how the keys are deployed in the contract's context and how we can pass the contract hash into a deployed contract so another contract can be called.

Creating the Project

In the appropriate folder, create the project for the contract using the following command:

cargo casper cross-contract

This will create the following structure under your desired smart contract folder:

cross-contract/
└── contract/
├── .cargo/
└── config.toml
├── src/
└── main.rs
└── Cargo.toml
└── tests/
├── src/
└── integration-tests.rs
└── Cargo.toml
└── .travis.yml
└── Makefile
└── rust-toolchain

After creating the project directory structure, use the following commands to go into the project folder and compile the files:

cd cross-contract
make prepare
make build-contract

This will also create a target folder under the contract folder where the .wasm of the contract can be found. Additionally you can check if the tests can be performed using the following command:

make test

This should produce the following outcome:

running 2 tests
test tests::should_error_on_missing_runtime_arg ... ok
test tests::should_store_hello_world ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s
tip

If this is not the case and you see the following error:

warning: `tests` (bin "integration-tests" test) generated 2 warnings
error: could not compile `tests` due to 3 previous errors; 2 warnings emitted
make: *** [test] Error 101

Then it is useful to check if the dependencies in Cargo.toml are still up to date.

CargoToml

If you see the red cross, it means the version is not up to date and has to be updated.

Changing the Standard Contract

The standard Casper contract from cargo-casper contains some methods that we will reuse. However, we will be getting rid of most auto-generated code.

We will be changing the main.rs file. Your code should look exactly as below:

#![no_std]
#![no_main]

#[cfg(not(target_arch = "wasm32"))]
compile_error!("target arch should be wasm32: compile with '--target wasm32-unknown-unknown'");

// We need to explicitly import the std alloc crate and `alloc::string::String` as we are in a
// `no_std` environment.
extern crate alloc;

// The elementary types
use alloc::string::String;
use alloc::vec::Vec;
use alloc::collections::BTreeMap;
use crate::alloc::string::ToString;


// Casper crates
use casper_types::{Key, CLType, Parameter, EntryPoint, EntryPoints, EntryPointType, EntryPointAccess};

use casper_contract::{
contract_api::{runtime, storage},
unwrap_or_revert::UnwrapOrRevert,
};


#[no_mangle]
pub extern "C" fn call() {

}

This will serve as a base for introducing the elements needed for cross-contract communication.

In a contract, you should first define the call entry point. It should be understood as a constructor for the contract. Everything included in the call entry point will be visible as metadata on a Casper network, in the contract's context. You should already be familiar with the call entry point from the Writing a Basic Smart Contract in Rust document. If this is not the case, be sure to familiarize yourself with it now.

The contract code, with changes to the call entry point, should look as shown below:

#![no_std]
#![no_main]

#[cfg(not(target_arch = "wasm32"))]
compile_error!("target arch should be wasm32: compile with '--target wasm32-unknown-unknown'");

// We need to explicitly import the std alloc crate and `alloc::string::String` as we are in a
// `no_std` environment.
extern crate alloc;

// The elementary types
use alloc::string::String;
use alloc::vec::Vec;
use alloc::collections::BTreeMap;
use crate::alloc::string::ToString;


// Casper crates
use casper_types::{Key, CLType, Parameter, EntryPoint, EntryPoints, EntryPointType, EntryPointAccess};

use casper_contract::{
contract_api::{runtime, storage},
unwrap_or_revert::UnwrapOrRevert,
};


#[no_mangle]
pub extern "C" fn call() {

// Get the value of the runtime argument named "message"
let value: String = runtime::get_named_arg("message");

// The value will be written under a URef
let value_ref = storage::new_uref(value);

// Creating the new set of named keys
// The keys are a Map of String/casper_types::Key
let mut named_keys: BTreeMap<String, Key> = BTreeMap::new();

// Insert the new value into the named keys
named_keys.insert(String::from("message"),value_ref.into()); // use into to wrap the Uref into a casper_types::Key
// Create a new vector
let mut params = Vec::new();
vec.push(Parameter::new("message", CLType::String));

// Create an Entry Point Object
let mut entry_points = EntryPoints::new();

// Describing the metadata for the entry point
entry_points.add_entry_point(EntryPoint::new(
"update_msg", // the name of the entry point
vec, // the arguments which can be passed into the entry point
CLType::Unit, // return type of the entry point
EntryPointAccess::Public, // access permissions - public can be accessed always
EntryPointType::Contract // in most cases it will be contract
));

// The contract is stored in the global state
let (stored_contract_hash, _contract_version) = storage::new_contract(
entry_points, // entry points
Some(named_keys), // named keys
Some("Hello_world_package_name".to_string()), // package name
Some("Hello_world_access_uref".to_string()) // access uref
);

// To access the contract hash from the accounts named keys
runtime::put_key("hello_world_contract", stored_contract_hash.into());

}
tip

runtime and storage appear frequently in our code. If these terms are unfamiliar to you, you should familiarize yourself with the Contract API Modules.

The metadata for each of the contract's entry points is defined in the call entry point. When installing the contract, the system will look for the name of the entry point as specified by the metadata for that entry point. Therefore, each of the entry points defined in the code must share the same name as the String value passed when defining the metadata for the entry point.

The #[no_mangle] flag ensures that the compiler does not modify the name of the entry point. The compiler will not enforce the condition that the name of the entry point is the same value present in its metadata definition, therefore the developer must be careful when defining their entry points.

In our case, we will define the entry point update_msg in the contract code just before call.

Your complete contract should match the following:

#![no_std]
#![no_main]

#[cfg(not(target_arch = "wasm32"))]
compile_error!("target arch should be wasm32: compile with '--target wasm32-unknown-unknown'");

// We need to explicitly import the std alloc crate and `alloc::string::String` as we are in a
// `no_std` environment.
extern crate alloc;

// The elementary types
use alloc::string::String;
use alloc::vec::Vec;
use alloc::collections::BTreeMap;
use crate::alloc::string::ToString;


// Casper crates
use casper_types::{Key, CLType, Parameter, EntryPoint, EntryPoints, EntryPointType, EntryPointAccess};

use casper_contract::{
contract_api::{runtime, storage},
unwrap_or_revert::UnwrapOrRevert,
};

#[no_mangle]
pub extern "C" fn update_msg() {

let value: String = runtime::get_named_arg("message");
// Get the uref of the message stored in global state
let uref = runtime::get_key("message").unwrap_or_revert().into_uref().unwrap_or_revert();
// Write the message to global state
storage::write(uref, String::from(value));
}


#[no_mangle]
pub extern "C" fn call() {
// Get the value of a passed parameter with the key "message"
let value: String = runtime::get_named_arg("message");
// The value will be wraped in a URef
let value_ref = storage::new_uref(value);
// Creating the new set of named keys
// The keys are a Map of Key/Value
let mut named_keys: BTreeMap<String, Key> = BTreeMap::new();
// Insert the new value into the named keys
named_keys.insert(String::from("message"),value_ref.into()); // use into to wrap the value to the key
// Create a new vector
let mut vec = Vec::new();
vec.push(Parameter::new("message", CLType::String));
// Create an Entry Point Object
let mut entry_points = EntryPoints::new();

// Define the metadata for the entry point `update_msg`
entry_points.add_entry_point(EntryPoint::new(
"update_msg",
vec,
CLType::Unit,
EntryPointAccess::Public,
EntryPointType::Contract
));

// The contract is stored in the global state
let (stored_contract_hash, _contract_version) = storage::new_contract(
entry_points, // entry points metadata
Some(named_keys), // named keys
Some("Hello_world_package_name".to_string()), // package name
Some("Hello_world_access_uref".to_string()) // access uref
);

// To access from the account - named keys of the account
runtime::put_key("hello_world_contract", stored_contract_hash.into());
}
info

There is a distinction between storing data in a contract’s NamedKeys and using a dictionary. Dictionaries can be used to store dApp-centric data, but they are not a SQL database and should only be used for data that needs to be stored in global state. Objects referenced in a contract should only be used as links within a bigger application.

Deploying the Contract

There are many tools available to send a deploy to a Casper network. The simplest method is to use the Rust CLI with the subcommand put_deploy.

Be sure to go through the prerequisites from the Installing Smart Contracts and Querying Global State documentation.

Make sure that after doing this you have:

  1. A valid private key for your account.
  2. Funded your account with 2000 CSPR on the Testnet, which you can use for testing your smart contract.

Create the keys folder in the main folder of your project and make sure that the private key which you put into the folder is called secret_key.pem.

Compile the contract in the contract directory so you obtain the contracts .wasm:

cd cross-contract
make prepare
make build-contract

This should produce the following outcome:

cd contract && cargo build --release --target wasm32-unknown-unknown
Finished release [optimized] target(s) in 0.13s
wasm-strip contract/target/wasm32-unknown-unknown/release/contract.wasm 2>/dev/null | true

With this step everything is in place to deploy the contract.

tip

When working with lengthy command strings, it may help to maintain a .txt file where you can edit the runtime arguments of the commands before sending them to the CLI. This will save you time and frustration when working with multiple contracts and commands.

Since we are using a default contract structure, the command called from the cross-contract folder should be the following:

casper-client put-deploy \
--node-address http://136.243.187.84:7777 \
--chain-name casper-test \
--secret-key ./keys/secret_key.pem \
--payment-amount 20000000000 \
--session-path ./contract/target/wasm32-unknown-unknown/release/contract.wasm \
--session-arg "message:string='hello world'"
tip

The parameters used in this command need to be adjusted based on your use case. For details, see querying a node and installing contracts. The payment amount may also need to be adjusted based on the latest Testnet chainspec.

The output of this command is:

{
"id": -9119604526598719721,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"deploy_hash": "af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832"
}
}

To verify that the contract was successfully deployed, use the get-deploy subcommand, providing as a parameter the deploy_hash received from the put-deploy above.

casper-client get-deploy \
--node-address http://136.243.187.84:7777 af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832

This should return a JSON output containing information such as header data, approvers and payments. You can also receive this information by using the verbose flag with the put-deploy subcommand. Take time to familiarize yourself with the structure of the output.

We can use the supplied deploy hash, af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832 to find this contract using a block explorer. When viewed through the explorer, the status of the Deploy should be marked as Success.

From your cspr.live account, you will find a tab called NamedKeys. This tab includes a list of all contracts deployed using the private key connected to your account.

By clicking the contract hash, you can see all entry points included in the contract, as well as the NamedKeys under which your contract’s name is stored. You should keep these named keys organized to avoid losing track while creating larger implementations.

An additional tab, Deploys, that is currently empty. If our contract included a cross-contract call that called an entry point from another contract, it would appear here. For now, we can note the hash of the contract, which is hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea.

Create Another Contract for the Cross-Contract Call

This section describes the process of writing an additional contract, which will use an entry point titled call_contract_2 to invoke the update_msg entry point on the previous contract.

In this tutorial we will be passing the contract hash, as an argument, into the call entry point and use this to perform the calls to the destination contract.

Prepare the call entry point as described below:


#[no_mangle]
pub extern "C" fn call() {

// Create the list of required runtime arguments for the given entry point.
let mut vec = Vec::new();
vec.push(Parameter::new("new_message", CLType::String));
vec.push(Parameter::new("hello_world_contract", CLType::Key));

// In the named keys of the contract, add a key for the count.
let mut named_keys = NamedKeys::new();

// Create an Entry Point Object
let mut entry_points = EntryPoints::new();

// Add the entry point metadata definition.
entry_points.add_entry_point(EntryPoint::new(
"call_contract_2",
vec,
CLType::Unit,
EntryPointAccess::Public,
EntryPointType::Contract
));

// The contract is stored in the global state
let (stored_contract_hash, _contract_version) = storage::new_contract(
entry_points, // entry points
Some(named_keys), // named keys
Some("contract2_package_name".to_string()), // package name
Some("contract2_access_uref".to_string()) // access uref
);

// To access from the account - named keys of the account
runtime::put_key("cross_contract_2", stored_contract_hash.into());
}

This would be the easiest implementation of the call entry point. There is only one entry point which accepts the key contract2 of type String and the key hello_world_contract of the type Key. There aren't any named keys which will be saved in the contract's context. The contract is then stored in global state and placed as an entry within the account's named keys.

Now that we have defined the metadata for the call_contract_2 entry point, we must now define the entry point itself. This entry point will take the second contract hash as an argument and call the entry point update_msg. It will then pass a message to the second contract as a parameter, which will be stored in that contract’s context.

#[no_mangle]
pub extern "C" fn call_contract_2() {

// Get the contract hash from the named arguments passed to the `call_contract_2` entry point.
let contract_hash: ContractHash = runtime::get_named_arg::<Key>(CONTRACT_HASH)
.into_hash()
.map(|hash| ContractHash::new(hash))
.unwrap();

// Get the value of the message from the second parameter
let new_value: String = runtime::get_named_arg("new_message");

// Call the update_msg entry point on the other contract with the parameter values
let _: () = runtime::call_contract(
contract_hash,
"update_msg",
runtime_args! {
"message" => new_value,
},
);

}

Your complete contract implementation should look as follows:


#![no_std]
#![no_main]

#[cfg(not(target_arch = "wasm32"))]
compile_error!("target arch should be wasm32: compile with '--target wasm32-unknown-unknown'");

// We need to explicitly import the std alloc crate and `alloc::string::String` as we are in a
// `no_std` environment.
extern crate alloc;

// The elementary types
use alloc::string::String;
use alloc::vec::Vec;
use crate::alloc::string::ToString;
use crate::runtime_args::RuntimeArgs;

// Casper crates
use casper_types::{
api_error::ApiError,
contracts::NamedKeys, runtime_args, CLType, Key, ContractHash, Parameter, EntryPoint, EntryPoints, EntryPointType, EntryPointAccess};

use casper_contract::{
unwrap_or_revert::UnwrapOrRevert,
contract_api::{runtime, storage},
};

// The contract key in the account named keys
const CONTRACT_HASH: &str = "hello_world_contract";

#[no_mangle]
pub extern "C" fn call_contract_2() {

let contract_hash: ContractHash = runtime::get_named_arg::<Key>(CONTRACT_HASH)
.into_hash()
.map(|hash| ContractHash::new(hash))
.unwrap();

let new_value: String = runtime::get_named_arg("new_message");

let _: () = runtime::call_contract(
contract_hash,
"update_msg",
runtime_args! {
// key => value
"message" => new_value,
},
);

}

#[no_mangle]
pub extern "C" fn call() {

// Create a new vector - this will be the signature of the entrypoint
let mut vec = Vec::new();
vec.push(Parameter::new("new_message", CLType::String));
vec.push(Parameter::new("hello_world_contract", CLType::Key));

// In the named keys of the contract, add a key for the count.
let named_keys = NamedKeys::new();

// Create an Entry Point Object
let mut entry_points = EntryPoints::new();

// Add the entry point to the entry points object
entry_points.add_entry_point(EntryPoint::new(
"call_contract_2",
vec,
CLType::Unit,
EntryPointAccess::Public,
EntryPointType::Contract
));

// The contract is stored in global state
let (stored_contract_hash, _contract_version) = storage::new_contract(
entry_points, // entry points
Some(named_keys), // named keys
Some("contract2_package_name".to_string()), // package name
Some("contract2_access_uref".to_string()) // access uref
);

// To access from the account - named keys of the account
runtime::put_key("cross_contract_2", stored_contract_hash.into());

}

After you run make build-contract in your second contract's directory, you should obtain the outcome:

cd contract && cargo build --release --target wasm32-unknown-unknown
Compiling contract v0.1.0 (/Users/karolmarter/Desktop/Rust_Projects/cross-contract-2/contract)
Finished release [optimized] target(s) in 0.69s
wasm-strip contract/target/wasm32-unknown-unknown/release/contract.wasm 2>/dev/null | true

Create the keys subfolder and copy the keys from the keys subfolder in the first contract into this subfolder. The call from the terminal will look as follows:

casper-client put-deploy \
--node-address http://136.243.187.84:7777 \
--chain-name casper-test \
--secret-key ./keys/secret_key.pem \
--payment-amount 20000000000 \
--session-path ./contract/target/wasm32-unknown-unknown/release/contract.wasm
tip

You may have noticed that the contract.wasm is always output to the same filename for each new cargo casper project. You can change this by editing the Makefile in the main directory. You can then observe the result by recompiling your contract with these commands;

make prepare
make build-contract

After the deploy we can check if it was successful and inspect the runtime arguments of the deployed entry points.

The result of invoking the put-deploy subcommand is:

{
"id": -7557689417621513622,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"deploy_hash": "faeb7e4f010c20c88d2dd126da545933c26fd8ce370282b8cd49f7f6fe7304b9"
}
}
tip

If the contract name doesn't change during concurrent deploys, the urefs/hashes will be overwritten in the account's named keys.

Observing the deploy, we can see that it succeeded:

casper-client get-deploy \
--node-address http://136.243.187.84:7777 af42bc6dbc58f677d138eb968d897f965f1ed118a40980bc16efbcc2a0c71832

In the execution_results JSON element we should see "Success".


"execution_results": [
{
"block_hash": "bc3040214e46fe0eaa9d98150a8a67a1033b931619dbc3e5f1a841d3a2d6f869",
"result": {
"Success": {
"cost": "16580565260",
"effect": { ...

}
}
}
}
]

Get the state root hash of the current network state:

casper-client get-state-root-hash --node-address http://136.243.187.84:7777

The result of invoking theget-state-root-hash command is:

{
"id": -3631326529646611302,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"state_root_hash": "2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb"
}
}

Query the state of Casper network using the account hash:

  casper-client query-global-state \
--node-address http://136.243.187.84:7777 \
--state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \
--key account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9

If we check the account's named keys, we can see all of the account's deployed contracts:

Account's named keys
{
"id": -6842818667609668962,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"block_header": null,
"merkle_proof": "[30424 hex chars]",
"stored_value": {
"Account": {
"account_hash": "account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9",
"action_thresholds": {
"deployment": 1,
"key_management": 1
},
"associated_keys": [
{
"account_hash": "account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9",
"weight": 1
}
],
"main_purse": "uref-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5-007",
"named_keys": [
{
"key": "uref-94c54f24273f1fb874eff33f3d4211a254622edfd1b980d5e758bd719b46fd0d-007",
"name": "Hello_world_access_uref"
},
{
"key": "hash-7a581d353665b74779dc8d446d33a5086bb367a29a558490d1e524f9c12002d3",
"name": "Hello_world_package_name"
},
{
"key": "uref-ae2f94bf959ec06a80b2035f31d7e4c65c01bf24bbbf794a473bc743c4b2f655-007",
"name": "contract2_access_uref"
},
{
"key": "hash-a7810282c275d525f083a756aba6912513a4a494ae317503cf6018c0fbaf9c4d",
"name": "contract2_package_name"
},
{
"key": "hash-32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92",
"name": "cross_contract_2"
},
{
"key": "hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea",
"name": "hello_world_contract"
}
]
}
}
}
}

As we have now managed to deploy two contracts, we can call the entry point of this contract, passing appropriate arguments to the function.

The Uref of the message variable is stored under the Named Keys in the contract.

casper-client query-global-state \
--node-address http://136.243.187.84:7777 \
--state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \
--key hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea
{
"id": 2434670480361972874,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"block_header": null,
"merkle_proof": "[25224 hex chars]",
"stored_value": {
"Contract": {
"contract_package_hash": "contract-package-wasm7a581d353665b74779dc8d446d33a5086bb367a29a558490d1e524f9c12002d3",
"contract_wasm_hash": "contract-wasm-c0384d4041950780bd3b167b4516a306e308e2d4729d08f6d2b10dfa1dbdaad6",
"entry_points": [
{
"access": "Public",
"args": [
{
"cl_type": "String",
"name": "message"
}
],
"entry_point_type": "Contract",
"name": "update_msg",
"ret": "Unit"
}
],
"named_keys": [
{
"key": "uref-aa758090d9bc1364754180f9f6bfc8821275038fd5d794a5dfb60bd2838a8670-007",
"name": "message"
}
],
"protocol_version": "1.4.13"
}
}
}
}

Checking the state of the message in the first contract, we observe the following:

casper-client query-global-state \
--node-address http://136.243.187.84:7777 \
--state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \
--key hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea -q "message"

This is a simple hello world string. After invoking the entry point using the command below this value should change.

info

--session-hash - is the contract hash, which is returned from the put-deploy.

--session-arg "hello world_contract:Key= ..." - the hash of the contract which we want to call from within the contract identified by the session-hash.

casper-client put-deploy \
--node-address http://136.243.187.84:7777 \
--chain-name casper-test \
--secret-key ./keys/secret_key.pem \
--payment-amount 20000000000 \
--session-hash hash-32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92 \
--session-entry-point "call_contract_2" \
--session-arg "new_message:string='Hello new message!'" \
--session-arg "hello_world_contract:Key='hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea'"
tip

The contract hash has to be of type ContractHash in the contract itself. We can pass the hash as a Key argument and change it to ContractHash in the smart contract.

The output of the above command is:

{
"id": -6419793201665396463,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"deploy_hash": "15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537"
}
}

Check the deploy with:

casper-client get-deploy \
--node-address http://136.243.187.84:7777 15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537

After the deploy finishes successfully, you should see a similar outcome to the following:

Deploy details
{
"id": 3968762702269106998,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"deploy": {
"approvals": [
{
"signature": "01319eee9bcfde6963e5b47164dd2c8044f0c20dd59f0c2993db55bec6bd3802fec2c9c6cae6ca8993c8aee0440be43f6c38bdc4bbdce501837ff5ca66fbd7c902",
"signer": "010e732fe2fbbcf62f2e46500d4cd8ff58a3bfd8dcb44c8b6f9a87dc5d573556af"
}
],
"hash": "15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537",
"header": {
"account": "010e732fe2fbbcf62f2e46500d4cd8ff58a3bfd8dcb44c8b6f9a87dc5d573556af",
"body_hash": "26282fa50b8e7c240025d683f197661ca846f2c1a3521a5dd604e6066d89d6d7",
"chain_name": "casper-test",
"dependencies": [],
"gas_price": 1,
"timestamp": "2023-03-09T14:39:24.974Z",
"ttl": "30m"
},
"payment": {
"ModuleBytes": {
"args": [
[
"amount",
{
"bytes": "0500c817a804",
"cl_type": "U512",
"parsed": "20000000000"
}
]
],
"module_bytes": ""
}
},
"session": {
"StoredContractByHash": {
"args": [
[
"new_message",
{
"bytes": "1200000048656c6c6f206e6577206d65737361676521",
"cl_type": "String",
"parsed": "Hello new message!"
}
],
[
"hello_world_contract",
{
"bytes": "01b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea",
"cl_type": "Key",
"parsed": {
"Hash": "hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea"
}
}
]
],
"entry_point": "call_contract_2",
"hash": "32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92"
}
}
},
"execution_results": [
{
"block_hash": "9c81259ac5ef7b953656a9327a479ae771a15c5ef131c91216e9e697dfdb09eb",
"result": {
"Success": {
"cost": "462273650",
"effect": {
"operations": [],
"transforms": [
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",
"transform": "Identity"
},
{
"key": "balance-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "balance-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5",
"transform": {
"WriteCLValue": {
"bytes": "0600876bf27301",
"cl_type": "U512",
"parsed": "1597500000000"
}
}
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": {
"AddUInt512": "20000000000"
}
},
{
"key": "hash-32ad0e54e874f68706708ebfd2c5aba7803eb64ccff71a50d3c4d4f29db15c92",
"transform": "Identity"
},
{
"key": "hash-a7810282c275d525f083a756aba6912513a4a494ae317503cf6018c0fbaf9c4d",
"transform": "Identity"
},
{
"key": "hash-b48ccc725ba948405d01205e64acff09ac24c899aed8d649f7bc1572216266c2",
"transform": "Identity"
},
{
"key": "hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea",
"transform": "Identity"
},
{
"key": "hash-7a581d353665b74779dc8d446d33a5086bb367a29a558490d1e524f9c12002d3",
"transform": "Identity"
},
{
"key": "hash-c0384d4041950780bd3b167b4516a306e308e2d4729d08f6d2b10dfa1dbdaad6",
"transform": "Identity"
},
{
"key": "uref-aa758090d9bc1364754180f9f6bfc8821275038fd5d794a5dfb60bd2838a8670-000",
"transform": {
"WriteCLValue": {
"bytes": "1200000048656c6c6f206e6577206d65737361676521",
"cl_type": "String",
"parsed": "Hello new message!"
}
}
},
{
"key": "deploy-15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537",
"transform": {
"WriteDeployInfo": {
"deploy_hash": "15e11340d92fc9e64deb38bd942f4efb69caad0851eec24fd577070309d18537",
"from": "account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9",
"gas": "462273650",
"source": "uref-453534c5c380862c2d814b5879f08fe6b5a3d4f031eaf20e08cf091d274035a5-007",
"transfers": []
}
}
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-624dbe2395b9d9503fbee82162f1714ebff6b639f96d2084d26d944c354ec4c5",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "hash-8cf5e4acf51f54eb59291599187838dc3bc234089c46fc6ca8ad17e762ae4401",
"transform": "Identity"
},
{
"key": "hash-010c3fe81b7b862e50c77ef9a958a05bfa98444f26f96f23d37a13c96244cfb7",
"transform": "Identity"
},
{
"key": "hash-9824d60dc3a5c44a20b9fd260a412437933835b52fc683d8ae36e4ec2114843e",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": "Identity"
},
{
"key": "balance-bb9f47c30ddbe192438fad10b7db8200247529d6592af7159d92c5f3aa7716a1",
"transform": "Identity"
},
{
"key": "balance-98d945f5324f865243b7c02c0417ab6eac361c5c56602fd42ced834a1ba201b6",
"transform": {
"WriteCLValue": {
"bytes": "00",
"cl_type": "U512",
"parsed": "0"
}
}
},
{
"key": "balance-bb9f47c30ddbe192438fad10b7db8200247529d6592af7159d92c5f3aa7716a1",
"transform": {
"AddUInt512": "20000000000"
}
}
]
},
"transfers": []
}
}
}
]
}
}

We would expect that the value of the message reference in the other contract would have changed, which we can check:

casper-client query-global-state \
--node-address http://136.243.187.84:7777 \
--state-root-hash 2f3e100324deb999107229dbec5c4b724653174328c99ea0836931248c3cc9cb \
--key hash-b7a06298cc71d4cac05929cc0713dfd5a541c68b71cb500cd04547b5cd0385ea -q "message"

The output of the above command is:

{
"id": -5477027327608594231,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"block_header": null,
"merkle_proof": "[61444 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "1200000048656c6c6f206e6577206d65737361676521",
"cl_type": "String",
"parsed": "Hello new message!"
}
}
}
}

With this we have succeeded in cross-contract communication between two contracts.

Summary

In this tutorial, we:

  • Developed two Rust contracts on a Casper network, where one smart contract is calling an entry point of the second smart contract
  • Called an entry point on one contract from the other contract, passing a value as an argument to this entry point.

Advanced Tutorials

TitleDescription
Two-Party Multi-Signature DeploysA trivial two-party multi-signature scheme for signing and sending deploys
Multi-Sig ManagementIntegrate key management on Casper accounts and sign deploys with multiple keys
Interacting with Runtime Return ValuesContract code returning a value to the immediate caller via runtime::ret()
Safely Transfer Tokens to a ContractTwo methods to handle tokens via a contract
Reading and Writing to Global State using RustMethods to read and write data to global state on a Casper network using Rust
Cross Contract CommunicationVariations of cross-contract communication for more complex scenarios
Working with Authorization KeysRetrieve and use the authorization keys associated with a deploy

Listing CSPR on an Exchange

This topic describes how to list the Casper token (CSPR) on a cryptocurrency exchange.

caution

The Casper Signer has been deprecated and replaced with the Casper Wallet. We are in the process of updating this page. Meanwhile, visit the guide on Building with the Casper Wallet.

Setting up a Node

While it is not necessary for an exchange to operate their own node on the Casper Mainnet, we recommend that they do so if they expect to handle moderate to high volumes of transaction activity. A node operated by an exchange does not have to be a validating node, it can be read-only. For setup instructions, see Basic Node Setup.

This setup enables you to have a self-administered gateway to the Casper Mainnet to get data and submit transactions.

Casper Account

You will need a Casper Account to handle the transactions on an exchange. Casper has an Account model and instructions on how to create an Account.

For your exchange, you need at least one Account. Each Casper network uses an Account model that holds onto general resources and purses with tokens and provides an on-chain identity. As an exchange, if you are dealing with high volumes of transaction activity, you might need a main account for the exchange platform and sub-accounts for other users.

Understanding Basic Transactions

We have a token and transaction model that features different levels of support that range from convenient to robust. Usually, when you are transferring Casper tokens between two parties, the native two-party transfer will suffice.

Casper supports native two-party transfers as well as bulk transfers using custom Wasm. The native transfer is ideal when you need to perform a one-to-one transfer between two purses. Whereas the batched Wasm transfer is better suited for making bulk transfers. A batched Wasm transfer allows you to do multiple transfers in a single deploy, making it more cost-effective when sending tokens from one purse to several others.

Native transfer

You can accomplish a native transfer by sending a native transfer deploy, without any Wasm. Included below is an example of this type of deploy. The included payment field describes how we are paying for the deploy, in this case a native transfer, while the session field describes the actual transfer.

Native Transfer Deploy

"id": 1,
"jsonrpc": "2.0",
"method": "account_put_deploy",
"params": {
"deploy": {
"approvals": [
{
"signature": "130 chars",
"signer": "010f50b0116f213ef65b99d1bd54483f92bf6131de2f8aceb7e3f825a838292150"
}
],
"hash": "ec2d477a532e00b08cfa9447b7841a645a27d34ee12ec55318263617e5740713",
"header": {
"account": "010f50b0116f213ef65b99d1bd54483f92bf6131de2f8aceb7e3f825a838292150",
"body_hash": "da35b095640a403324306c59ac6f18a446dfcc28faf753ce58b96b635587dd8e",
"chain_name": "casper-net-1",
"dependencies": [],
"gas_price": 1,
"timestamp": "2021-04-20T18:04:40.333Z",
"ttl": "1h"
},
"payment": {
"ModuleBytes": {
"args": [
[
"amount",
{
"bytes": "021027",
"cl_type": "U512",
"parsed": "10000"
}
]
],
"module_bytes": ""
}
},
"session": {
"Transfer": {
"args": [
[
"amount",
{
"bytes": "0400f90295",
"cl_type": "U512",
"parsed": "2500000000"
}
],
[
"target",
{
"bytes": "8ae68a6902ff3c029cea32bb67ae76b25d26329219e4c9ceb676745981fd3668",
"cl_type": {
"ByteArray": 32
},
"parsed": "8ae68a6902ff3c029cea32bb67ae76b25d26329219e4c9ceb676745981fd3668"
}
],
[
"id",
{
"bytes": "00",
"cl_type": {
"Option": "U64"
},
"parsed": null
}
]
]
}
}
}
}
}

Native transfers are the simplest method to transfer tokens between two purses. For details about the native transfer command, see Direct Token Transfer. The following command transfers 10 CSPR from account A's main purse to account B's main purse.

casper-client transfer \
--id 1 \
--transfer-id 123456 \
--node-address http://<node-ip-address>:7777 \
--amount 10000000000 \
--secret-key <accountA-secret-key>.pem \
--chain-name casper \
--target-account <accountB-hex-encoded-public-key> \
--payment-amount <payment-in-motes>

The payment amount varies based on the deploy and network chainspec. For node version 1.5.1, wasmless transfers cost 10^8 motes.

Bulk or batched Wasm transfer

Bulk or batched Wasm transfers allow you to apply some logic before or after the transfer. They also allow for conditional transfers. You may also use them if you are doing a series of transfers between multiple purses. Listed below are five methods for the Rust contract API, which can be used in session code to achieve batched Wasm transfer:

  • transfer_to_account: Transfers amount of motes from the main purse of the account to the purse of a target account. If the target purse does not exist, the transfer process will create one. Can be called from session code only and not a contract as a contract doesn't have a main purse.
  • transfer_to_public_key: Transfers amount of motes from the main purse of the caller’s account to the main purse of the target. If the account referenced by the target does not exist, the transfer will create a new account. Can be called from session code only and not from a contract as a contract doesn't have a main purse.
  • transfer_from_purse_to_purse: Transfers amount of motes from source purse to target purse. If the target does not exist, the transfer fails.
  • transfer_from_purse_to_public_key: Transfers amount of motes from source to the main purse of target. If the account referenced by the target does not exist, the transfer will create it.
  • transfer_from_purse_to_account: Transfers amount of motes from source purse to target account's purse. If the target account does not exist, the transfer creates a new account.

For more information on how to write session code, see Writing Session Code. There are equivalent assembly script methods available. Alternatively, you can program directly against the ext-FFI methods.

Integrating CSPR

You can integrate with the JSON-RPC API of a node on the Casper Mainnet. You can program directly against the RPC or if you prefer you can choose from the variety of SDK libraries that are available to use on a Casper network see SDK Libraries. Casper also provides a stream server that gives you real-time information about a variety of events occurring on a node. Use of the stream is optional. You might want to use this feature as it notifies you of events instead of requiring you to ask periodically. For more information about various events, see Monitoring and Consuming Events.

Testing the Integration

Our recommended testing mechanism is to have a test environment that points at the official Casper Testnet. Through this, you may run production like operations of your test exchange against the test environment. However, if you are not doing this and you just want to integrate with the Mainnet, then you can do so with your own test accounts.

If you are not going to do a Testnet integration, then we suggest you create some additional test accounts and test the transactions on the Mainnet through your software prior to moving to the general public.

The Casper Protocol

  • Casper is integrated with BitGo for enterprise grade custody. If your exchange uses BitGo, support for Casper is available already.
  • Casper has an execution after consensus model, which means that transactions are executed after they are finalized. Transactions are not orphaned or uncle’d on Casper and neither does chain reorganization happen on it. For more information on the execution process, see Execution Semantics.
  • Exchanges can check finality signatures. Validators send finality signatures after the finalized block is executed and global state is updated. The Casper node streams execution effects and finality signatures through an SSE architecture. For more information about various events, see Monitoring and Consuming Events.

Staking Integration for Exchanges

Exchanges seeking to integrate CSPR staking mechanisms will need to understand the processes of delegation, undelegation and redelegation through deploys on a Casper network. The following outlines the use of the JavaScript SDK to perform these actions, as well as parameters relating to staking. Further information about staking on a Casper network can be found here.

Deploy Structures and Parameters

Staking operations consists of two parts:

  1. Creating a deploy object
  2. Signing the deploy

The staking deploy requires the following information:

  • The delegator's public key
  • The validator's public key
  • The new validator's public key (For redelegation only)
  • The amount to be delegated
  • The gas cost
  • The auction manager contract's hash
  • The appropriate entry point

Casper provides a series of prebuilt Wasm files for use in these operations. They are provided for convenience, and you are free to create your own custom deploys. You can find them in our casper-node repository, in the following locations:

1. Creating a deploy object

To create a deploy using the JavaScript SDK, we will need deployParams, session and a payment.

Deploy params is a DeployUtil.DeployParams object created from the delegator's publicKey and the network name as shown in the following:

import { DeployUtil, CLPublicKey } from 'casper-js-sdk';

const deployParams = new DeployUtil.DeployParams(
CLPublicKey.fromHex(publicKeyHex),
network_name // 'testnet' | 'mainnet'
);

For creating a session object, which is DeployUtil.ExecutableDeployItem, we need

  • The delegator and validator's public keys
  • The amount of tokens to delegate/undelegate/redelgate
  • The auction manager contract's hash
  • The entry point

First, create a variable RuntimeArgs from the public keys and the amount. We will need to use it below in session:

import { RuntimeArgs, CLValueBuilder, CLPublicKey } from 'casper-js-sdk';

const args = RuntimeArgs.fromMap({
delegator: CLPublicKey.fromHex(delegatorPublicKeyHex),
validator: CLPublicKey.fromHex(validatorPublicKeyHex),
amount: CLValueBuilder.u512(amountMotes) // in motes
});

Second, create a session parameter. It is a Uint8Array consisting of the auction manager contract's hash, the entry points and runtime arguments, which we previously created.

The auction manager contract's hash will depend on the network you are using. For Casper's Mainnet and Testnet, the hashes are as follows:

  • Mainnet

    ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea

  • Testnet

    93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2

Your entry point will depend on which action you are performing, with the following three available:

  • delegate - Initial delegation to a validator
  • undelegate - Undelegating tokens from a validator back to the delegator
  • redelegate - Redelegating tokens to a new validator
import { decodeBase16, DeployUtil } from 'casper-js-sdk';

const session = DeployUtil.ExecutableDeployItem.newStoredContractByHash(
decodeBase16(auction_manager_contract_hash), // auction manager contract hash
contractEntryPoint, // auction manager entry point
args
);

To create the payment parameter for the deploy, we need a deploy cost. The actual costs can be pulled from the network chainspec. Here is the chainspec for version 1.4.8. You will need the chainspec for the network version you are using.

Use the DeployUtil.standardPayment method for creating payment.

import { DeployUtil } from 'casper-js-sdk';

const payment = DeployUtil.standardPayment(deployCost);

The last operation is creating the deploy:

import { DeployUtil } from 'casper-js-sdk';

DeployUtil.makeDeploy(deployParams, session, payment);

Redelegation, occurs the same way as delegation, but with the introduction of a third public_key.

import { RuntimeArgs, CLPublicKey, CLValueBuilder } from 'casper-js-sdk';

const args = RuntimeArgs.fromMap({
delegator: CLPublicKey.fromHex(delegatorPublicKeyHex),
validator: CLPublicKey.fromHex(validatorPublicKeyHex),
new_validator: CLPublicKey.fromHex(redelegateValidatorPublicKeyHex),
amount: CLValueBuilder.u512(amountMotes)
})

2a. Sign the deploy (Casper Signer)

To get the signature, you will need to use Signer.sign from the JavaScript SDK. It will return Promise<{ deploy }>, which is the signed object.

Use DeployUtil.deployFromJson to convert the result and sent it to network with:

import { Signer, CasperServiceByJsonRPC, DeployUtil } from 'casper-js-sdk';

const casperService = new CasperServiceByJsonRPC(GRPC_URL);
const deployJson = DeployUtil.deployToJson(deploy);
Signer.sign(
deployJson,
accountPublicKey,
recipientPublicKey
).then((signedDeployJson) => {
const signedDeploy = DeployUtil.deployFromJson(signedDeployJson);
if (signedDeploy.ok) {
casperService.deploy(signedDeploy.val! as DeployUtil.Deploy); // sent deploy
}
}

2b. Sign the deploy (Ledger)

You will need to connect with your Ledger first to get the signature.

import TransportWebUSB from '@ledgerhq/hw-transport-webusb';
import LedgerApp, { ResponseBase } from '@zondax/ledger-casper';
import { DeployUtil } from 'casper-js-sdk';

const getBipPath = (index: number) => {
const idx = index.toString();
return `m/44'/506'/0'/0/${idx}`;
};

const deployBytes = DeployUtil.deployToBytes(deploy) as Buffer;
const transport = await TransportWebUSB.create();
const ledgerApp = new LedgerApp(transport);
const res = await ledgerApp.sign(
getBipPath(selectedAccountIndex),
deployBytes
);

The Signature will be in a property called res.signatureRS.

After that, we can create a signed deploy,

import { DeployUtil, CLPublicKey } from 'casper-js-sdk';

const signedDeploy = DeployUtil.setSignature(
deploy,
signatureRS,
CLPublicKey.fromHex(accountPublicKey)
);

We can then send it to a network.

casperService.deploy(signedDeploy)

Costs and Minimums

The following are costs and minimum amounts for version 1.5.1, but up-to-date values should be pulled from the network chainspec.

Transfer Cost: 100,000,000 motes or 0.1 CSPR

Delegation Cost: 2,500,000,000 motes or 2.5 CSPR

Minimum transfer amount: 2,500,000,000 motes, or 2.5 CSPR

Minimum amount required for delegation: 500,000,000,000 motes, or 500 CSPR.

The Delegation Cap

Casper includes a delegator limit rule, which limits the number of delegators that a single validator may have at 953. This is a temporary solution to prevent complications with Casper’s fast sync mechanism - in which high bond counts could break fast sync.

Validators with a delegator count at or above 953 at the time of the 1.4.5 upgrade were grandfathered in, however new delegators will not be able to delegate to any validator until the delegator count for that validator falls below 953.

Existing delegators may continue to delegate additional CSPR, regardless of the current number of delegators staking their CSPR to that validator. However, no new delegators may join the validator until it drops below the 953 limit.

Interacting with Runtime Return Values

Users interacting with a Casper network must keep in mind the differences between session and contract code. Session code executes entirely within the context of the initiating account, while contract code executes within the context of its own state. Any action undertaken by a contract must initiate through an outside call, usually via session code.

Developers should note the difference between a caller and an immediate caller. The immediate caller represents the session or contract code that directly accessed the entry point. The caller is the original, initiating session code that started the entire process. There are many cases where contract code may call additional contract code. In this case, the immediate caller may be another instance of contract code. Even in this event, the overall caller will be the initiating session code, while there may be several layers of stacked contract code acting as immediate callers.

Contract code can optionally return a value to their immediate caller via runtime::ret(), whether that immediate caller is another contract code or session code. The returned value may be used within the context of the session or contract code, stored for later use, or discarded if not needed. Use of return values depends entirely on what the developer needs in that instance.

Session code initiates actions on behalf of an account which is considered to be the caller. Therefore, it cannot return anything.

Contract Code

For example, if we create a contract to accept and keep a record of donations, we would use runtime::ret() to define the results that should be passed to the caller as per the following:


#[no_mangle]
pub extern "C" fn donate() {
let donating_account_key: Key = runtime::get_named_arg(DONATING_ACCOUNT_KEY);
if let Key::Account(donating_account_hash) = donating_account_key {
update_ledger_record(donating_account_hash.to_string())
} else {
runtime::revert(FundRaisingError::InvalidKeyVariant)
}
let donation_purse = *runtime::get_key(FUNDRAISING_PURSE)
.unwrap_or_revert_with(FundRaisingError::MissingFundRaisingPurseURef)
.as_uref()
.unwrap_or_revert();
let value = CLValue::from_t(donation_purse.into_add()).unwrap_or_revert();
runtime::ret(value)
}

In this example, the return value is the URef corresponding to the purse used to raise funds, with add permission only. Using this information, the calling code will be able to then transfer funds into the purse, after calling the donate entry point.

Without the addition of the runtime::ret, the purse would not be returned to the caller.

Session Code

The following is an example of session code calling the specified entry point. Keep in mind that the immediate caller does not need to be session code, and the immediate caller could be another instance of contract code.


#[no_mangle]
pub extern "C" fn call() {
let fundraiser_contract_hash: ContractHash = runtime::get_named_arg(FUNDRAISER_CONTRACT_HASH);
let donating_account_key: Key = runtime::get_named_arg(DONATING_ACCOUNT_KEY);
let donation_amount: U512 = runtime::get_named_arg(DONATION_AMOUNT);

let donating_purse_uref: URef = runtime::call_contract(
fundraiser_contract_hash,
ENTRY_POINT_DONATE,
runtime_args! {
DONATING_ACCOUNT_KEY => donating_account_key
},
);
system::transfer_from_purse_to_purse(
account::get_main_purse(),
donating_purse_uref,
donation_amount,
None
)
.unwrap_or_revert()
}

This session code calls into a contract's entry point by using runtime::call_contract, supplying the contract_hash to identify the contract to be called, and the name of the entry point to be invoked, in this case donate. It supplies the donating_account_key, which in this case is the account key of the caller. The contract will then provide a return value, in this case donating_purse_uref. To call an entry point, you will need to know the CLType of the return value and identify it within the code.

You can determine the type of the return value by querying the contract object in global state. To query a contract rather than an account, replace the key parameter with the formatted string representation of the contract hash.

This example code takes that returned value and transfers a donation_amount from the calling account's main purse to the established donation purse. It is not necessary for the code to store, or even use, the returned value. Use of the returned value depends on the needs of the developer.

Reading and Writing to Global State using Rust

The following examples outline methods to read and write data to global state on a Casper network using the Rust programming language.

Essentially, there are three means of storage within the Casper ecosystem. These consist of runtime::put_key, storage::write(alongside storage::new_uref as explained below) and storage::dictionary_put. These stored values can be read using runtime::get_key, storage::read and storage::dictionary_get, respectively. Each method stores data in a specific way, and it's important to understand the differences.

Description of Functions

runtime::put_key / runtime::get_key

Both the put_key and get_key functions refer to Casper Key types as outlined in both the Understanding Hash Types and Serialization Standard. These keys are stored within a URef as a Key type.

storage::write / storage::read

storage::write writes a given value to a previously established URef (created using storage::new_uref). Unlike put_key, this value is not one of the Key types listed above, but rather any of the potential CLTypes as outlined. storage::read provides a method to retrieve these values from the associated URef.

storage:dictionary_put / storage::dictionary_get

For most data storage needs on a Casper network, dictionaries are more efficient and provide lower gas costs than NamedKeys. Each dictionary item exists independently, sharing a single dictionary seed URef for reference purposes.

More information on dictionaries can be found on the Reading and Writing to Dictionaries page.

Example Code

Example of put_key and storage::write

This sample code creates a new contract and stores the contract hash in global state using the runtime::put_key function.

Once the stored value has been initialized, the storage::write function overwrites the existing value with true. The URef is then stored in the current context as a NamedKey titled MY_STORED_VALUE_UREF.


// Store contract hash under a Named key CONTRACT_HASH
runtime::put_key(CONTRACT_HASH, contract_hash.into());

// Store !MY_STORED_VALUE (false) as init value/type into a new URef
let my_value_uref = storage::new_uref(!MY_STORED_VALUE);

// Store MY_STORED_VALUE (true) under the URef value
storage::write(my_value_uref, MY_STORED_VALUE);

// Store the Uref under a Named key MY_STORED_VALUE_UREF
let my_value_key: Key = my_value_uref.into();
runtime::put_key(MY_STORED_VALUE_UREF, my_value_key);
}

Example of get_key and storage::read

This example compliments the code sample above by retrieving the CONTRACT_HASH using the get_key function, before comparing a provided runtime argument ARG_MY_STORED_VALUE against the previously stored MY_STORED_VALUE_UREF using storage::read.


let my_stored_value_uref: URef = runtime::get_key(MY_STORED_VALUE_UREF)
.unwrap_or_revert()
.into_uref()
.map(|uref| URef::new(uref.addr(), AccessRights::default()))
.unwrap_or_revert()
.into_read();

let my_actual_stored_value: bool = storage::read(my_stored_value_uref).unwrap().unwrap();

// Compare my stored value with runtime arg
let my_expected_stored_value: bool = runtime::get_named_arg(ARG_MY_STORED_VALUE);
if my_actual_stored_value != my_expected_stored_value {
// We revert if my stored value is not what is expected from caller argument
runtime::revert(UserError::StoredValueError);
}

runtime::print(&my_actual_stored_value.to_string());
}

Example of dictionary_put and dictionary_get

Examples of dictionary usage for storage can be found in the Writing Entries into a Dictionary section of Reading and Writing to Dictionaries.

Additional Functions for Named Keys

The following functions might also be of interest for working with named keys:

  • list_named_keys - Returns the named keys of the current context
  • has_key - Returns true if the key exists in the current context’s named keys
  • remove_key - Removes the requested NamedKey from the current context

Safely Transfer Tokens to a Contract

This tutorial covers two methods to handle tokens via a contract. This is not a native process to a Casper network and will require the use of custom code. The following two scenarios provide a framework for developers and the pros and cons of each example. Developers should choose the option that best suits their individual needs.

For increased security, token transfers from a main purse must be handled via session code (WASM), as shown here. Therefore, transfer-* methods are unavailable in stored WASM for tokens originating from an account's main purse, even when the stored WASM runs in the account context.

Scenario 1 - Creating a Throw-Away Purse

The first scenario involves the use of a single-use, throw-away purse. The caller creates and funds a purse independent of their main purse, before passing the URef to the callee.

In this example, the smart contract retains full access to the purse, creating security concerns over its reuse by the caller. Further, it is also possible for the caller to retain full access to the disposable purse, although not demonstrated in the example. The contract should remove any tokens from the purse and transfer them to another purse under their control to avoid issues.

This scenario is less complex, but more wasteful than the second scenario. Any purses created in this fashion remain permanent, but unused after the initial operation.

Please note that the creation of a purse costs 2.5 CSPR on the Casper Mainnet.

#[no_mangle]
pub extern "C" fn call() {
let amount: U512 = runtime::get_named_arg("amount");
// This is demonstrating the most direct case, wherein you pass in the contract_hash and
// the entry_point_name of the target contract as args.
// With prior setup having been done, this can also be simplified.
let contract_hash = runtime::get_named_arg("contract_hash");
let entry_point_name = runtime::get_named_arg("entry_point_name");

// This creates a new empty purse that the caller will use just this one time.
let new_purse = system::create_purse();

// Transfer from the caller's main purse to the new purse that was just created.
// Note that transfer is done safely by the host logic.
system::transfer_from_purse_to_purse(account::get_main_purse(), new_purse, amount, None)
.unwrap_or_revert();

// Pass the newly created purse to the smart contract with full access rights;
// the called contract should receive the new purse, extract the token from it, and then do
// whatever else it is meant to do if a valid amount was transferred to it. Note that the
// caller's main purse is never exposed to the called contract; the newly created purse
// is provided instead.
runtime::call_contract(contract_hash, entry_point_name, runtime_args! {
// The arg names are defined by the contract that you are calling,
// there is no canonical name. The contract you are calling may have other
// runtime args that it requires.
"????" => new_purse
});
}

Scenario 1 - Advanced Variation

Advanced versions of this scenario can mitigate the wastefulness inherent in the example. If the caller creates a named purse independent of their main purse, they can integrate it with the contract in question. In this way, the same purse can be used to fund a contract repeatedly.

This example provides a framework for the idea, but will require modification to suit developer needs.

Scenario 2 - Maintaining a Reusable Purse within Contract Logic

The second scenario involves more complex internal logic to allow for a purse's reuse. The contract itself keeps track of a purse associated with the caller as internal bookkeeping.

In Scenario 1, the newly created purse is a pure means of transferring tokens from the caller to the callee. In contrast, Scenario 2 maintains an internal purse associated with the caller's address. This purse serves as token storage for actions the caller wishes the contract to undertake on their behalf. It differs from Scenario 1's Advanced Variation in that the purse in question is under the control of the contract rather than the caller.

Scenario 2 offers a less wasteful means of transferring tokens to a contract but comes with the added burden of internal complexity. When choosing between the two scenarios, you must evaluate the scope and needs of your project and choose accordingly.

// Scenario 2: with this style, the contract being called has some internal accounting
// to keep track of a reusable purse associated to the calling account; this avoids
// wasteful creation of one time purses but requires the smart contract being called
// to have more sophisticated internal logic.
#[no_mangle]
pub extern "C" fn call() {
let amount: U512 = runtime::get_named_arg("amount");

// This is demonstrating the most direct case, wherein you pass in the contract_hash and
// the entry_point_names of the target contract as args.
// With prior setup having been done, this can also be simplified.
let contract_hash = runtime::get_named_arg("contract_hash");
// the name of the entry point on the contract that returns a purse uref to receive token at
// the actual name of the entry point is up to the smart contract authors
let deposit_point_name = runtime::get_named_arg("deposit_point_name");
// whatever entry point on the smart contract does the actual work if token has been transferred
// the actual name of which is up to the smart contract authors.
let other_entry_point_name = runtime::get_named_arg("other_entry_point_name");

// The smart contract returns a purse URef of a deposit purse (with ADD access rights only)
// for the caller to transfer to.
let deposit_purse: URef = runtime::call_contract(contract_hash, deposit_point_name, runtime_args! {});

// transfer from the caller's purse to the purse provided by the contract; the transfer is handled
// safely by the host and the caller's purse is never exposed to the called smart contract.
system::transfer_from_purse_to_purse(account::get_main_purse(), deposit_purse, amount, None)
.unwrap_or_revert();

// The contract being interacted with looks up the associated purse, checks its balance, etc.
// within its logic. That side of it is entirely up to the smart contract authors to code; the caller
// merely calls the logic. Also, the entry point might require one or more runtime arguments.
// In all cases some discovery of the API of the contract you are calling is necessary.
runtime::call_contract(contract_hash, other_entry_point_name, runtime_args! {});
}

Scenario 2 - Advanced Variation

In Scenario 2, the contract in question maintains a purse for each associated caller. The advanced variation establishes an internal ledger that records the balance of each caller. The contract can record the information for each caller as a dictionary item and respond accordingly. In this fashion, a single purse can store the motes of all callers accessing the contract.

This design streamlines the internal accounting process of the contract but does require a greater degree of complexity during the initial setup.

Two-Party Multi-Signature Deploys

Accounts on a Casper network can associate other accounts to allow or require a multiple-signature scheme for deploys.

This workflow describes how a trivial two-party multi-signature scheme for signing and sending deploys can be enforced for an account on a Casper network. This workflow assumes:

  1. You meet the prerequisites, including having the Casper command-line client and a valid node address
  2. You have the main account's PublicKey hex (MA) and another PublicKey hex to associate (AA)
  3. You have previously sent deploys to a Casper network

Configuring the Main Account

caution

Incorrect account configurations could render accounts defunct and unusable. We highly recommend executing any changes to an account in a test environment like Testnet before performing them in a live environment like Mainnet.

Each Account has an associated_keys field, which is a list containing account hashes and their corresponding weights. Accounts can be associated by adding the account hash to the associated_keys field.

An Account on a Casper network assigns weights to keys associated with it. For a single key to sign a deploy, or edit the state of the account, its weight must be greater than or equal to a set threshold. The thresholds are labeled as the action_thresholds for the account.

Each account within a Casper network has two action thresholds that manage the permissions to send deploys or manage the account. Each threshold defines the minimum weight that a single key or a combination of keys must have to either:

  1. Send a deploy to the network; determined by the deployment threshold
  2. Edit the associated keys and the action_thresholds; determined by the key_management threshold

To enforce the multi-signature (multi-sig) feature for an account on a Casper network, the main key and associated key's combined weight must be greater than or equal to the deployment threshold. This can be achieved by having each key's weight equal to half of the deployment threshold.

Running session code to set up associated keys

To set up the associated keys for an Account, you must run session code that executes within the account's context. You will find an example of such session code on GitHub. Note that this session code is not a general-purpose program and needs to be modified for each use case.

git clone https://github.com/casper-ecosystem/two-party-multi-sig

The session code executes 3 crucial steps to enforce the multi-sig scheme for the main account:

  1. Adds an associated key to the account; we will refer to this key as AA
  2. Raises the action threshold to 2, because action thresholds for deploys cannot be greater than the action threshold for key management. By default, all action thresholds are set to 1
  3. Raises the deployment threshold to 2, such that the weight required to send a deploy is split equally between the keys associated with the account

The repository contains a Makefile with the build commands necessary to compile the contract and generate the necessary Wasm.

cd two-party-multi-sig
make build-contract

The compiled Wasm will be saved on this path: contract/target/wasm32-unknown-unknown/release/contract.wasm.

The Casper command-line client can be used to send the compiled Wasm to the network for execution.

casper-client put-deploy \
--node-address http://<peer-ip-address>:7777 \
--secret-key <secret-key-MA>.pem \
--chain-name casper-test \
--payment-amount 2500000000 \
--session-path <path-to-contract-wasm> \
--session-arg "deployment-account:account_hash='account-hash-<hash-AA>'"
  1. node-address - An IP address of a node on the network
  2. secret-key - The file name containing the secret key of the main account
  3. chain-name - The chain-name to the network where you wish to send the deploy (this example uses the Testnet)
  4. payment-amount - The cost of the deploy. This example uses 2.5 CSPR, which may need to be adjusted based on the network chainspec.
  5. session-path - The path to the contract Wasm
  6. session-arg - The contract takes the account hash of the associated account as an argument labeled deployment-account. You can pass this argument using the --session-arg flag in the command line client

Important response fields:

  • "result"."deploy_hash" - the address of the executed deploy, needed to look up additional information about the transfer

Note: Save the returned deploy_hash from the output to query information about execution status.

Confirming Processing and Account Status

Account configuration on a Casper blockchain is stored in a Merkle Tree and is a snapshot of the blockchain's Global State. The representation of global state for a given block can be computed by executing the deploys (including transfers) within the block and its ancestors. The root node of the Merkle Tree identifying a particular state is called the state-root-hash and is stored in every executed block.

To check that the account was configured correctly, you need the state-root-hash corresponding to the block that contains your deploy. To obtain the state-root-hash, you need to:

  1. Confirm the execution status of the deploy and obtain the hash of the block containing it
  2. Query the block containing the deploy to obtain the corresponding state_root_hash

Using the state_root_hash and the hex-encoded-public-key of the main account, query the network and check the account's configuration.

casper-client query-global-state \
--node-address http://<peer-ip-address>:7777 \
--state-root-hash <state-root-hash-from-block> \
--key <hex-encoded-public-key-MA>
Example output
{
"id": 1126043166167626077,
"jsonrpc": "2.0",
"result": {
"api_version": "1.0.0",
"merkle_proof": "2226 chars",
"stored_value": {
"Account": {
"account_hash": "account-hash-dc88a1819381c5ebbc3432e5c1d94df18cdcd7253b85259eeebe0ec8661bb84a",
"action_thresholds": {
"deployment": 2,
"key_management": 2
},
"associated_keys": [
{
"account_hash": "account-hash-12dee9fe535bfd8fd335fce1ba1f972f26bb60029a303b310d85419357d18f51",
"weight": 1
},
{
"account_hash": "account-hash-dc88a1819381c5ebbc3432e5c1d94df18cdcd7253b85259eeebe0ec8661bb84a",
"weight": 1
}
],
"main_purse": "uref-74b20e9722d3f087f9dc431e9f0fcc6a803c256e005fa45b64a101512001cb78-007",
"named_keys": []
}
}
}
}

In the example output, you can see the account hashes listed within the associated_keys section. Each key has weight 1; since the action threshold for deployment is 2, neither account can sign and send a deploy individually. Thus, the deploy needs to be signed by the secret keys of each account to reach the required threshold.

Launching a Casper Node with AWS Marketplace

The following tutorial outlines the process for launching a Casper Node through the Amazon AWS Marketplace.

Step 1 - Subscribing

You will first need to subscribe to the Casper node software through the AWS Marketplace. There is no associated cost with this subscription.

Step 01

If you are not currently signed in to an AWS account, you will need to either sign in or create an account to subscribe.

You need to accept the terms and conditions listed to continue with the subscription. You may also choose a different Amazon EC2 (Amazon Elastic Compute Cloud) instance type if you prefer.

After accepting the terms, it may take a few moments for AWS to process your request. In this event, you will see the Continue to Configuration button grayed out, as shown below:

Step 04

Once the system processes your request, the button will light orange, and you may continue to the configuration options.

Step 05

Step 2 - Initial Configuration

The Configuration page allows you to choose your fulfillment option, software version, and the region in which your node will be hosted. Unless you intend to run your Casper node with a specific legacy version of the software, we suggest using the most current release.

The window on the right will show an estimation of the infrastructure costs from AWS for operating the Casper node, given the EC2 instance type you previously chose.

Step 06

Step 3 - Launch Configuration

The Launch page will show your previously selected configuration details and a Usage instructions button that leads to the most recent instructions based on your chosen software version.

Below this, you will see a drop-down menu with the title "Choose Action":

Step 08

This drop-down menu includes the following options:

  • Launch through EC2 - This option launches your configuration through the Amazon EC2 Console

  • Launch from Website - This option will launch directly from the current page, using further configuration options outlined below.

  • Copy to Service Catalog - Copy your configuration of the software to the Service Catalog console, where you can manage your company's cloud resources.

Additional drop-down menus include:

  • EC2 Instance Type - This option determines the machine's specifications that will run your instance of the Casper node software.

  • VPC Settings - This option selects the Virtual Private Cloud you will use for your Casper node. This should be auto-populated, but you can create a new VPC through the EC2 console by clicking the option below the drop-down box.

  • Subnet Settings - This option selects the subnet for your node under the listed VPC above. Again, it should be auto-populated, but you can create a new subnet.

  • Security Group Settings - This option determines the flow of traffic connecting to your Casper node. By clicking on "Create New Based on Seller Settings", you can create a new security group using the suggested default Casper settings.

EC2 Key Pair Settings

Step 11

You will need an EC2 key pair to launch your Casper node. If you do not already have an EC2 key pair, you can create one directly from this page by clicking "Create a key pair in EC2". This will bring you to the EC2 console, where you can click "Create key pair". This will automatically download your keys in the selected file type, and you can choose the new key pair on the previous page.

Step 12

Launching Your Node

If you are satisfied with your configuration choices and all options are correctly filled out, you can hit the orange Launch button to launch your AWS-hosted Casper node.

Step 13

Fungible Tokens (CEP-18) Implementation and Usage

This tutorial assumes that you have worked through the following examples. If you have not already done so, then we recommend that you do so now:

Outline of the Tutorial

This tutorial explains the purpose of the ERC-20 standard and the Casper CEP-18 Fungible Token implementation, which serves the same purpose for Casper blockchains. It explains the implications of not adhering to the standard and why it is important to base dApps on one common standard implementation supported by the underlying blockchain protocol.

ERC-20 Standard

The ERC-20 (Ethereum Request for Comment 20) standard is a technical specification used for creating and implementing tokens on the Ethereum blockchain.

It outlines a set of rules and interfaces that tokens must adhere to in order to be compatible with the broader Ethereum ecosystem. ERC-20 tokens have become the most widely adopted and recognized token standard on Ethereum network and other Blockchain protocols like NEAR or Solana. Some key points of the ERC-20 standard include:

  • A set of functions and events that a token contract must implement to enable basic functionalities such as transferring tokens between addresses, checking token balances, and approving third-party spending of tokens. These functions include transfer(), balanceOf(), approve(), transferFrom(), and others. The tokens are not sent between wallet addresses. Instead, the token contract creates an owner list to track how many tokens are owned by which owner address.

  • Optional metadata functions like name(), symbol(), and decimals(), which provide additional information about the token. These functions allow for the retrieval of token name, ticker symbol, and decimal places for proper display and identification purposes.

  • A common set of rules for token developers to follow concerning security and consistency. This helps prevent potential vulnerabilities and ensures that tokens behave predictably across different platforms and wallets. By adhering to the ERC-20 standard, token developers can leverage the existing infrastructure, wallets, and exchanges that support ERC-20 tokens.

Each blockchain protocol should have one official supported implementation of the ERC-20 Standard as to allow the interoperability of the assets between the protocols.

Interaction of ERC-20 Based Tokens with the Uniswap Standard

By conforming to the ERC-20 specification it is possible to leverage the functionality of decentralized exchange (DEX) implementations like Uniswap V2.

Uniswap V2 uses ERC-20 tokens in the following scenarios:

  • Listing Tokens – Any ERC-20 token can be listed on Uniswap V2 if it complies with the ERC-20 standard.
  • Liquidity Pools – any two pairs of ERC-20 tokens can be used to create a liquidity pool.
  • Uniswap V2 uses the ERC-20 standard transfer() function to allow an exchange of tokens within the liquidity pools.

ERC-20 Implementations on Casper and Implications for Decentralized Exchanges

There exist at least two different implementations of the ERC-20 Standard on Casper networks.

While both implement the ERC-20 specification using a common set of rules devised from the original ERC-20 Ethereum standard, using different implementations of the standard can introduce complexities and potential risks.

The following considerations should be applied when trying to create an ERC-20 Token:

  • Interoperability – Different implementations of the ERC-20 standard can hinder seamless integration between tokens, dApps or wallets.

  • Project Security Audits – Well-established standards usually undergo a thorough security audit. This ensures a higher level of security and reduces the risk of vulnerabilities.

  • Ecosystem – The longer a blockchain network exists, the more widespread a standard implementation like ERC-20 becomes. Using a different implementation may limit availability of supported projects and require additional effort for integration.

The CEP-18 Casper Fungible Token Standard establishes a single implementation of the ERC-20 Standard for Casper networks to avoid disparities and incompatibilities.

The Casper CEP-18 Standard

The CEP-18 Token Standard is a Casper network compliant implementation of ERC-20 that provides the following contract methods to interact with the token contract:

  • allowance - Returns the amount of owner’s tokens allowed to be spent by the spender
  • approve - Allows a spender to transfer up to an amount of the direct caller’s tokens
  • balance_of - Returns the token balance of the owner
  • decimals - Returns the decimal places applied to the balance of the token
  • name - Returns the name of the token
  • symbol - Returns the symbol of the token
  • total_supply - Returns the total supply of the token
  • transfer - Transfers an amount of tokens from the direct caller to a recipient
  • transfer_from - Transfers an amount of tokens from the owner to a recipient, if the direct caller has been previously approved to spend the specified amount on behalf of the owner

For more detail on these methods, there is a reference implementation available on GitHub.

Creating a CEP-18 Token on the Testnet

Clone and Compile the CEP-18 Contract

Building on the construction of a CEP-18 token as explained above, we will be installing our own token contract in global state.

If you are unsure how to interact with Casper Contracts please refer to the following tutorial: Writing a Basic Smart Contract in Rust.

We will clone the token repository and prepare the token contract for sending in a Deploy.

  1. Clone the Fungible Token contract from the repository.
    git clone https://github.com/casper-ecosystem/cep18.git
  1. Make any necessary changes to the code for your customization requirements.

  2. Compile the contract to create the target .wasm file and build the Wasm.

    cd cep18
make prepare
make build-contract
tip

If the build-contract finishes with an error wasm-strip: command not found, make sure you install an additional package on MacOS:

    brew install wabt
  1. Build and verify the compiled contract.
    make test

Install the CEP-18 Contract

As it is important to understand the potential costs of your Deploy, you should send several on Testnet to familiarize yourself before sending a Deploy to Mainnet.

Use the following template to install the contract on the Testnet:


casper-client put-deploy \
--node-address http://<HOST:PORT> \
--chain-name [NETWORK_NAME]] \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [AMOUNT] \
--session-path [WASM_FILE_PATH]/[File_Name].wasm
--session-arg <"NAME:TYPE='VALUE'" OR "NAME:TYPE=null">

Check if the request to the Testnet can be made and get a snapshot of the network with the state root hash:


casper-client get-state-root-hash --node-address http://78.46.32.13:7777

You should obtain a response similar to:

{
"id": 3323991011802671610,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.15",
"state_root_hash": "9b43fd7388559c078f363403972cb079d69786259bf6c5cd9cd7adcc14029d74"
}
}

An exemplary deploy to the Casper Testnet is as follows:


casper-client put-deploy \
--node-address http://78.46.32.13:7777 \
--chain-name casper-test \
--secret-key "./keys/secret_key.pem" \
--payment-amount 150000000000 \
--session-path "./target/wasm32-unknown-unknown/release/cep18.wasm" \
--session-arg "name:string='CHF Coin'" \
--session-arg "symbol:string='CHFC'" \
--session-arg "decimals:u8='10'" \
--session-arg "total_supply:u256='1000'"

info

Always be mindful of the --secret-key and --session-path arguments. Path provided to the arguments should always be with regard to the current folder, where the command is executed.

The keys folder is not a part of the CEP18 folder structure. Optionally you should provide a folder where your keys are stored.

The response from the put-deploy command should look like this:


{
"id": 5066914343373494745,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.15",
"deploy_hash": "19853d1569fec2b0fa36e81f2f24bea77ccf039a399071cb7d4b377202a073d6"
}
}

Using the deploy_hash the state of the deploy can be checked:


casper-client get-deploy \
--node-address http://78.46.32.13:7777 19853d1569fec2b0fa36e81f2f24bea77ccf039a399071cb7d4b377202a073d6

In the execution results we can see, that the deploy was successful:


...
"execution_results": [
{
"block_hash": "426a8823c1018e75f8c3823d580116269fd272f20e60561dff0565375a95316d",
"result": {
"Success": {
"cost": "140416131900",
"effect": {
"operations": [],
...

Be always mindful of the payment amount during the deploy process. If the amount is too small, then the deploy will fail with Out of gas error.

Query the Entry Points in the CEP-18 contract

Get the state root hash from the network:

casper-client get-state-root-hash --node-address http://78.46.32.13:7777

Your response should look similar to:

{
"id": 2950480729544096556,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.15",
"state_root_hash": "7706d906fce25dcdadb2a9453f5243a6c72c4444e6c826cf2941157333a48705"
}
}

With the state root hash and the account hash which performed the deploy, you can query the contract arguments.

casper-client query-global-state --node-address http://78.46.32.13:7777 \
--state-root-hash 7706d906fce25dcdadb2a9453f5243a6c72c4444e6c826cf2941157333a48705 \
--key account-hash-ee57bb3b39eb66b74a1dcf12f3f0e7d8e906e34b11f85dc05497bf33fbf3a1f9 \
-q "cep18_contract_hash_CHF Coin/name"

The above command will query the contract for the name. The template for the query is contract_name/named_key.

You will obtain the following response:

{
"id": -7058786841478812744,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.15",
"block_header": null,
"merkle_proof": "[94526 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "0800000043484620436f696e",
"cl_type": "String",
"parsed": "CHF Coin"
}
}
}
}

Try to query the contract for other Named Keys and check how the contract behaves.

Summary

In this tutorial, we:

  • Explained the ERC20 standard and what the implications are for not using the standard implementations.
  • Developed a CEP-18 Rust contract on a Casper network and defined the proper arguments for the deploy.
  • Installed the contract on the Testnet
  • Called an entry point on the contract to get the value of the Named Key name.

Overview

Beginner Tutorials

TitleDescription
Getting Started VideoStep-by-step video tutorial for setting up the Casper development environment
A Counter on an NCTL NetworkAn example contract that maintains a counter variable on a local Casper Network with NCTL
A Counter on the TestnetAn example contract that maintains a counter variable on the Casper Testnet
Querying a Casper NetworkQueries for users and developers to obtain information stored on the blockchain
Smart Contract UpgradesLearn how to upgrade smart contracts
The Casper Fungible Token Standard (CEP-18)Fungible Token Standard (CEP-18) Implementation and Usage
Launching a Casper Node with AWS MarketplaceLearn how to launch a Casper Node through the AWS Marketplace

GitHub Tutorials

TitleDescription
NFTs on Casper with the CEP-78 NFT StandardImplementing the Casper CEP-78 NFT standard
Fungible Tokens on CasperImplement the Casper Fungible Token standard

Querying a Casper Node

The Casper node supports queries for users and developers to obtain information stored on the blockchain.

This document assumes:

  1. You have met the prerequisites
  2. You are familiar with the structure of the Global State and the Blockchain Design to query data from the network

When sending a query, it is important to note that the request will be routed to a single node in the network. You can request several types of data from a node:

  • Account details
  • Block information
  • Deploy information

Obtaining the Global State Root Hash

Since the system state changes with each block created, obtaining the latest global state hash is essential before querying information from a node.

All queries made to global state require the state-root-hash, which you can obtain with this command:

casper-client get-state-root-hash \
--id 1 \
--node-address http://<node-ip-address>:7777

Request fields:

  • id - (STRING OR INTEGER) Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned
  • node-address - An IP address of a node on the network
Explore the JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "chain_get_state_root_hash",
"params": null,
"id": 1
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"result": {
"api_version": "1.0.0",
"state_root_hash": "f97d8d36630a8f4acdb323223596f6fa01ee3b0d49ad70d84d715c156c5dbec6"
},
"id": 1
}

Querying an Account

Accounts are stored in the global state and can be queried using the query-global-state command:

casper-client query-global-state \
--id 4 \
--node-address http://<node-ip-address>:7777 \
--state-root-hash <state-root-hash> \
--key <hex-encoded-source-account-public-key>

Request fields:

  • id - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned
  • node-address - An IP address of a node on the network
  • state-root-hash - Hex-encoded hash of the state root
  • key - The base key for the query. This must be a properly formatted public key, account hash, contract address hash, URef, transfer hash or deploy-info hash.

Important response fields:

  • "result"."stored_value"."Account"."main_purse" - the address of the main purse containing the sender's tokens. This purse is the source of the tokens transferred in this example

Example Account Query with Verbose Output:

casper-client query-global-state -v \
--id 4 \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2 \
--key 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986
Explore the sample JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "query_global_state",
"params": {
"state_identifier": {
"StateRootHash": "a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2"
},
"key": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"path": []
},
"id": 4
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"id": 4,
"result": {
"api_version": "1.5.2",
"block_header": null,
"stored_value": {
"Account": {
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"named_keys": [
{
"name": "counter",
"key": "hash-4bf23564c8849a0a3193781f0a9df7d27c4bce2cc585d6e9bb161a7a1ce5cd7e"
},
{
"name": "counter_access_uref",
"key": "uref-76b6c7e7a87b752d34a8c3ccdc070dbfd1940960016c537525b2ab9076b61a3e-007"
},
{
"name": "counter_package_name",
"key": "hash-e4b2060f098fa763f9a68c5c98a2d98a4fa80815ec0fd6b93ac9efbb0c18f19b"
},
{
"name": "my-key-name",
"key": "uref-09376d4202d32457ceefa4d9cdf1db6ab2324981ade06ba6f495cdf14124c3b9-007"
},
{
"name": "version",
"key": "uref-244a270207dd13ef5ff190f75d84efe4ab54bd5787be0bbb175c3fb154b7f5ed-007"
}
],
"main_purse": "uref-8294864177c2c1ec887a11dae095e487b5256ce6bd2a1f2740d0e4f28bd3251c-007",
"associated_keys": [
{
"account_hash": "account-hash-0ea7998b2822afe5b62b08a21d54c941ad791279b089f3f7ede0d72b477eca34",
"weight": 1
},
{
"account_hash": "account-hash-1ed5a1c39bea93c105f2d22c965a84b205b36734a377d05dbb103b6bfaa595a7",
"weight": 3
},
{
"account_hash": "account-hash-77ea2e433c94c9cb8303942335da458672249d38c1fa5d1d7a7500b862ff52a4",
"weight": 1
},
{
"account_hash": "account-hash-d65d053f5017af101b752a9a12ba4c41fe3054b8632998a69193b891eab4caf5",
"weight": 1
},
{
"account_hash": "account-hash-e70dbca48c2d31bc2d754e51860ceaa8a1a49dc627b20320b0ecee1b6d9ce655",
"weight": 1
},
{
"account_hash": "account-hash-f1802d2dbd83e41f638eb9b046f762e481d56b27d4aa00817fec77fbb21f944a",
"weight": 1
}
],
"action_thresholds": {
"deployment": 2,
"key_management": 3
}
}
},
"merkle_proof": "[32054 hex chars]"
}
}

To query the account balance, use the query-balance command and the purse identifier, which can be a public key or account hash, implying the main purse of the given account should be used. Alternatively, the purse's URef can be used. The balance returned is in motes (the unit that makes up the Casper token). For full details, run the following help command:

casper-client query-balance --help
casper-client query-balance \
--id 6 \
--node-address http://<node-ip-address>:7777 \
--state-root-hash <state-root-hash> \
--purse-identifier <account>

Request fields:

  • id - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned
  • node-address - An IP address of a node on the network
  • state-root-hash - Hex-encoded hash of the state root
  • purse-identifier - A public key or account hash, implying the main purse of the given account should be used. Alternatively, the purse's URef.

The -v option generates verbose output, printing the RPC request and response generated. Let's explore an example below.

Example Balance Query with Verbose Output:

casper-client query-balance -v \
--id 6 \
--node-address https://rpc.testnet.casperlabs.io/ \
--state-root-hash a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2 \
--purse-identifier 01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986
Explore the JSON-RPC request and response generated.

JSON-RPC Request:

{
"jsonrpc": "2.0",
"method": "query_balance",
"params": {
"state_identifier": {
"StateRootHash": "a306a9cf869e52fe9eacdc28aade94215112cc04b6737b3669c35568a47a7dc2"
},
"purse_identifier": {
"main_purse_under_public_key": "01360af61b50cdcb7b92cffe2c99315d413d34ef77fadee0c105cc4f1d4120f986"
}
},
"id": 6
}

JSON-RPC Response:

{
"jsonrpc": "2.0",
"result": {
"api_version": "1.5.2",
"balance": "164000000000"
},
"id": 6
}

Querying Blocks

It is possible to obtain detailed block information from the system. To do this, obtain the hash of the block of interest and send this query to a node in the network. Here is an example:

casper-client get-block \
--id 3 \
--node-address http://<node-ip-address>:7777 \
--block-identifier <block-hash> \

Request fields:

  • id - Optional JSON-RPC identifier applied to the request and returned in the response. If not provided, a random integer will be assigned
  • node-address - An IP address of a node on the network
  • block-identifier - Hex-encoded block hash or height of the block. If not given, the last block added to the chain as known at the given node will be used

Important response fields:

  • "result"."block"."header"."state_root_hash" - contains the state-root-hash for this block
Explore the JSON-RPC request and response generated.

JSON-RPC Request:

{
"id": 3,
"jsonrpc": "2.0",
"method": "chain_get_block",
"params": {
"block_identifier": {
"Hash": "7c7e9b0f087bba5ce6fc4bd067b57f69ea3c8109157a3ad7f6d98b8da77d97f9"
}
}
}

JSON-RPC Response:

{
"id": 3,
"jsonrpc": "2.0",
"result": {
"api_version": "1.0.0",
"block": {
"body": {
"deploy_hashes": [],
"proposer": "012c6775c0e9e09f93b9450f1c5348c5f6b97895b0f52bb438f781f96ba2675a94",
"transfer_hashes": ["ec2d477a532e00b08cfa9447b7841a645a27d34ee12ec55318263617e5740713"]
},
"hash": "7c7e9b0f087bba5ce6fc4bd067b57f69ea3c8109157a3ad7f6d98b8da77d97f9",
"header": {
"accumulated_seed": "50b8ac019b7300cd1fdeec050310e61b900e9238aa879929745900a91bd0fc4f",
"body_hash": "224076b19c04279ae9b97f620801d5ff40ba64f431fe0d5089ef7cb84fdff45a",
"era_end": null,
"era_id": 0,
"height": 8,
"parent_hash": "416f339c4c2ff299c64a4b3271c5ef2ac2297bb40a477ceacce1483451a4db16",
"protocol_version": "1.0.0",
"random_bit": true,
"state_root_hash": "cfdbf775b6671de3787cfb1f62f0c5319605a7c1711d6ece4660b37e57e81aa3",
"timestamp": "2021-04-20T18:04:42.368Z"
},
"proofs": [
{
"public_key": "010f50b0116f213ef65b99d1bd54483f92bf6131de2f8aceb7e3f825a838292150",
"signature": "130 chars"
},
{
"public_key": "012c6775c0e9e09f93b9450f1c5348c5f6b97895b0f52bb438f781f96ba2675a94",
"signature": "130 chars"
},
{
"public_key": "018d5da83f22c9b65cdfdf9f9fdf9f7c98aa2b8c7bcf14bf855177bbb9c1ac7f0a",
"signature": "130 chars"
},
{
"public_key": "01b9088b92c8a8d592f6ec8c3e8153d7c55fc0c38b5999a214e37e73a2edd6fe0f",
"signature": "130 chars"
},
{
"public_key": "01b9e3484d96d5693e6c5fe789e7b28972aa392b054a76d175f079692967f604de",
"signature": "130 chars"
}
]
}
}
}

Querying Deploys

Once you submit a deploy to the network, you can check its execution status using get-deploy. If the execution_results in the output are null, the transaction has not run yet. Note that transactions are finalized upon execution.

casper-client get-deploy \
--id 2 \
--node-address http://<node-ip-address>:7777 \
<deploy-hash>

Request fields:

  • id - JSON-RPC identifier, applied to the request and returned in the response. If not provided, a random integer will be assigned
  • node-address - An IP address of a node on the network
  • deploy-hash - Hex-encoded hash of the deploy

Upgrading a Contract

This tutorial examines how to upgrade an existing contract, a process similar to upgrading any other software. You can change an unlocked contract package by adding a new contract and updating the default contract version that the contract package should use. You will need to know the contract package hash and use the add_contract_version API. You can also create a locked contract package that cannot be versioned and is therefore not upgradable.

Video Tutorial

Here is a video walkthrough of this tutorial.

Prerequisites

note

Installing the first version of the contract (contract-v1.wasm) as shown in the counter tutorial is a prerequisite before installing the second version of the contract (contract-v2.wasm).

If you explore the code, you will observe the different versions of the contract:

  • contract-v1 is the counter contract you can see in the A Counter on the Testnet tutorial.
  • contract-v2 is the contract with the new counter_decrement entry point.

Contract Versioning Flow

The following is an example workflow for creating a versioned contract package. Your workflow may differ if you have already created the contract package and have a handle on its hash.

  1. Create a contract in the most common way, using new_contract.
  2. Add a new version of the contract using add_contract_version.
  3. Build the new contract and generate the corresponding .wasm file.
  4. Install the contract on the network via a deploy.
  5. Verify that your new contract version works as desired.

In this tutorial, you will use the second version of the counter contract to perform the upgrade.

Step 1. Create a new unlocked contract

Create a new contract using the new_contract function and store the ContractHash returned under a key in global state for later access. Under the hood, the execution engine will create a contract package (a container for the contract) that can be versioned.

When creating the contract, you can specify the package name and access URef for further modifications. Without the access key URef, you cannot add new contract versions for security reasons. Optionally, you can also save the latest version of the contract package under a named key.

    // Create a new contract and specify a package name and access URef for further modifications
let (stored_contract_hash, contract_version) = storage::new_contract(
contract_entry_points,
Some(contract_named_keys),
Some("contract_package_name".to_string()),
Some("contract_access_uref".to_string()),
);

// The hash of the installed contract will be reachable through a named key
runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());

// The current version of the contract will be reachable through a named key
let version_uref = storage::new_uref(contract_version);
runtime::put_key(CONTRACT_VERSION_KEY, version_uref.into());

The first version of the counter shows you a contract package that can be versioned. This step is covered in the tutorial for A Counter on the Testnet.

Additional details:

  1. We are versioning the contract package, not the contract. The contract is always at a set version, and the package specifies the contract version to be used.
  2. The Wasm file name of the new contract could differ from the old contract; after sending the deploy to the network, the contract package hash connects the different contract versions.

Step 2. Add a new contract to the package

There are many changes you could make to a Casper contract, like adding new entry points, modifying the behavior of an existing entry point, or completely re-writing the contract.

To add a new contract version in the package, invoke the add_contract_version function and pass in the ContractPackageHash, EntryPoints, and NamedKeys. In the counter example, you will find the add_contract_version call here.

    let (contract_hash, contract_version) =
storage::add_contract_version(contract_package_hash,
entry_points,
named_keys);

Explanation of arguments:

  • contract_package_hash - This hash directs you to the contract package. See Hash and Key Explanations.
  • entry_points - Entry points of the contract, which can be modified or newly added.
  • named_keys - Named key pairs of the contract.

The new contract version carries on named keys from the previous version. If you specify a new set of named keys, they will be combined with the old named keys in the new contract version. If the old and new contract versions use the same named keys, then the new values would be present in the new version of the contract.

You will need to manage contract versioning, considering clients that may use older versions. Here are a few options:

  1. Pin your client contract to the contract hash of a specific version.
  2. Use call_versioned_contract with a version number to pin your client contract to that version.
  3. Call a contract using call_versioned_contract and version "None", which uses the newest version of the contract.

Step 3. Build the contract Wasm

Use these commands to prepare and build the newly added contract:

make prepare

make build-contract

Step 4. Install the contract

Install the contract on the network via a deploy and verify the deploy status. You can also monitor the event stream to see when your deploy is accepted.

To observe the upgrade workflow, you can install the second contract version on the chain. This version contains the counter_decrement entry point.

note

Installing the first version of the contract, as shown in the Counter tutorial, is a prerequisite before installing the second version.

casper-client put-deploy \
--node-address http://[NODE_IP]:7777 \
--chain-name [CHAIN_NAME] \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-path [PATH]/contract-v2/target/wasm32-unknown-unknown/release/counter-v2.wasm

Step 5. Verify your changes

You can write unit tests to verify the behavior of the new contract version with call_contract or call_versioned_contract. When you add a new contract to the package (which increments the highest enabled version), you will obtain a new contract hash, the primary identifier of the contract. You can use the contract hash with call_contract. Alternatively, you can use call_versioned_contract and specify the contract_package_hash and the newly added version.

For the simple example counter above, here are the corresponding tests. Notice how the tests store and verify the contract's version and entry points.

You could store the latest version of the contract package under a NamedKey, as shown here. Then, you can query the NamedKey to check the latest version of the contract package.

Example test function
    // Verify the contract version is now 2.
let account = builder
.get_account(*DEFAULT_ACCOUNT_ADDR)
.expect("should have account");

let version_key = *account
.named_keys()
.get(CONTRACT_VERSION_KEY)
.expect("version uref should exist");

let version = builder
.query(None, version_key, &[])
.expect("should be stored value.")
.as_cl_value()
.expect("should be cl value.")
.clone()
.into_t::<u32>()
.expect("should be u32.");

assert_eq!(version, 2);

You can also test the new entry point by using the Rust command-line client.

Get the NEW state-root-hash:

casper-client get-state-root-hash --node-address http://[NODE_IP]:7777

Check the new contract entry points. You should see the counter_decrement entry point now.

casper-client query-global-state \
--node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] -q "counter"
Example output
 {
"id": 5602352547578277096,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"block_header": null,
"merkle_proof": "[54054 hex chars]",
"stored_value": {
"Contract": {
"contract_package_hash": "contract-package-wasmc014187ccf3366cca70317d6d567cd56a05ecf1ee50ed3bd02727c2864e3d3a8",
"contract_wasm_hash": "contract-wasm-64d252f1ab72c7295a85d15c3f456f8bdda586580b0b7106e203fa4fd83f05d7",
"entry_points": [
{
"access": "Public",
"args": [],
"entry_point_type": "Contract",
"name": "counter_decrement",
"ret": "Unit"
},
{
"access": "Public",
"args": [],
"entry_point_type": "Contract",
"name": "counter_get",
"ret": "I32"
},
{
"access": "Public",
"args": [],
"entry_point_type": "Contract",
"name": "counter_inc",
"ret": "Unit"
}
],
"named_keys": [
{
"key": "uref-ca980a2e4c08dc3f233b728b22b909cd4e894295155a7902bf88a59eac1531d1-007",
"name": "count"
}
],
"protocol_version": "1.4.13"
}
}
}
}

Check the version and package details with the latest state root hash:

casper-client query-global-state \
--node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] -q "version"
Example output
{
"id": 9084525900533244372,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"block_header": null,
"merkle_proof": "[64874 hex chars]",
"stored_value": {
"CLValue": {
"bytes": "02000000",
"cl_type": "U32",
"parsed": 2
}
}
}

casper-client query-global-state \
--node-address http://[NODE_IP]:7777 \
--state-root-hash [STATE_ROOT_HASH] \
--key [ACCOUNT_HASH] -q "counter_package_name"
Example output
{
"id": 6933525663267881367,
"jsonrpc": "2.0",
"result": {
"api_version": "1.4.13",
"block_header": null,
"merkle_proof": "[52174 hex chars]",
"stored_value": {
"ContractPackage": {
"access_key": "uref-101817ffd5aa47b08ca710649dbdc41edf0a20d7802c736d34053656c0a99eaf-007",
"disabled_versions": [],
"groups": [],
"versions": [
{
"contract_hash": "contract-4ee8a4cfbc0a183d189611b6a14c0f7b57e7635fa17a8acfc5c645fec4c36316",
"contract_version": 1,
"protocol_version_major": 1
},
{
"contract_hash": "contract-2cd9f6485423ba846fae83729016b03df26d9babb939466906c8f1d168b40949",
"contract_version": 2,
"protocol_version_major": 1
}
]
}
}
}
}


Call the new entry point, counter_decrement, using the package name and check the results.

casper-client put-deploy \
--node-address http://[NODE_IP]:7777 \
--chain-name [CHAIN_NAME] \
--secret-key [PATH_TO_YOUR_KEY]/secret_key.pem \
--payment-amount [PAYMENT_AMOUNT_IN_MOTES] \
--session-package-name "counter_package_name" \
--session-entry-point "counter_decrement"
note

There are two ways to call versioned contracts:

  1. Calling Contracts by Package Hash
  2. Calling Contracts by Package Name

After calling the entry point, the count value should be decremented. You can verify it by querying the network again using the new state root hash.

Disabling and Enabling Contract Versions

You can disable a contract version within a contract package by using the disable_contract_version function.

Disabled contract versions can no longer be executed. As such, if there is only a single contract version within the package, you will no longer be able to use the contract.

Enable_contract_version allows you to re-enable a previously disabled contract version.

::note

Be aware that calling a contract package will use the most recent contract version. It is not necessary to disable a previous contract version, unless you have a specific need to do so.

:::

Creating a Locked Contract Package

You can create a locked contract package with the new_locked_contract function. This contract can never be upgraded.

let (stored_contract_hash, _) = storage::new_locked_contract(
contract_entry_points,
Some(contract_named_keys),
Some("contract_package_name".to_string()),
Some("contract_access_uref".to_string()),
);

Apply the contract entry points and named keys when you call the function. You can also specify a hash_name and uref_name that will be put in the context's named keys. You do not need to save the version number returned since the version of this contract package would always be equal to 1.

note

Creating a locked contract package is an irreversible decision. To upgrade a contract, use new_contract as Step 1 explains.

Runtime Economics

The economics of the runtime layer should incentivize efficient allocation of computational resources, primarily CPU time, to users. Pending state pruning implementation, disk space use is treated as CPU time usage and charged, irreversibly, per byte written. Currently, gas is allocated according to a first-in, first-out model for deploys, with a fixed price of 1 mote (1/109 part of a CSPR token) per 1 unit of gas.

Gas allocation

Any finite resource on a publicly accessible computer network must be rate-limited, as, otherwise, overuse of this resource is an attack vector -- a minimal requirement for platform security. However, rate-limiting, implemented on our platform as a simple block gas limit with several lanes, leaves the platform with the problem of fairly and efficiently allocating the gas. We are researching the optimal structure for spot and futures gas markets, and interested readers should consult the relevant CEPs. In the meantime, this section outlines some basic features of the platform that would underpin any allocation scheme.

Consensus before execution & basics of payment

The Highway protocol in its Mainnet implementation reaches consensus on a block before the block is executed, introducing a subtle difference from platforms like Ethereum. In addition, deploys sent to a Casper network can only be selected based on claimed, rather than used, gas. Consequently, to incentivize user-side optimization and prevent block space exhaustion by poorly optimized deploys, the platform provides no refunds for unused gas.

Additionally, a minimal amount of CSPR must be present in the user account's main purse to ensure that the payment computation is covered. The community may introduce additional balance checks in the future.

Costs and limits

Gas cost is a measure of relative time used by different primitive operations of the execution engine, which is also assumed to be additive. By additivity, we mean that the time to execute a program is approximately proportional to the sum of gas expended by the opcodes and functions called within the program. Casper assigns gas costs to primitive execution engine opcodes and specific more complex host-side functions that are callable from within the execution engine context. Gas costs for opcodes and host-side functions are specified in the chainspec and may vary according to arguments.

We expect to refine the current gas cost table to reflect time use more closely, with updates introduced in future upgrades. We also anticipate that, with the introduction of state pruning, storage costs will be calculated separately from computing time.

Lanes

The block gas limit is split into two lanes, one for native transfers and one for general deploys. The number of transfers, which cost a fixed amount of gas, is governed directly by the block_max_transfer_count chainspec parameter, set to 2500 when Mainnet launched.

Gas fees

Currently, the price of gas is fixed at 1 mote per 1 unit of gas.

Fee allocation

All fees from a particular block accrue to its proposer, incentivizing non-empty block production and allowing major dApps to execute deploys for free, provided they operate a validator node and are comfortable with the latency introduced by validator scheduling.

Spot pricing

Please see CEP #22 for one potential design of a gas spot market.

Futures pricing

Please see CEP #17 for our draft proposal of a gas futures market.

SDK Client Libraries

This section covers the software development kits (SDKs) published by third parties available for interacting with the Casper blockchain. These SDKs are client-side libraries providing functions or methods (depending on the language) to interact with a Casper network. You can use them as a model to develop your application and accomplish tasks such as generating account keys, sending transfers, or other blockchain transactions.

Each of these SDKs can be used to build dApps. For browser interaction, you can use the JavaScript SDK; for desktop applications, there are C# and Java SDKs. Click the link on your preferred SDK to learn how to use it in dApp development. To delve into the source code, you may visit the SDKs' Github repositories.

Each such third party is solely responsible for the SDK it provides, any warranties (to the extent that such warranties have not been disclaimed), and for any claims you may have relating to your access or use thereof. We do not approve or endorse any such SDKs by providing a link thereto, and assume no responsibility for your access or use thereof. The SDKs may be subject to additional licenses and disclaimers as set out in the relevant GitHub repositories.

Serialization Standard

The Casper platform uses a custom serialization format. To this end, we've established a Serialization Standard, which must be followed when building a Casper SDK.

JSON-RPC API

Developers can interact directly with the Casper JSON-RPC API instead of using an SDK.

Table of Contents

SDK DocumentationGitHub LocationOrganization
JavaScript/TypeScriptcasper-js-sdkCasper Ecosystem
Java SDKcasper-java-sdkCasper Association
C# SDKcasper-net-sdkMAKE
Go SDKcasper-go-sdkMAKE
Python SDKcasper-python-sdkCasper Association
PHP SDKcasper-php-sdkMAKE
Scala SDKcasper-scala-sdkM. Abahmane
- + \ No newline at end of file diff --git a/staking/index.html b/staking/index.html index 28aac64779..3b0da1709f 100644 --- a/staking/index.html +++ b/staking/index.html @@ -17,7 +17,7 @@ - + @@ -74,7 +74,7 @@

Staking vs. Delegating

A feature of Proof-of-Stake protocols is that token holders can actively participate in the protocol through a mechanism known as staking or delegation. They can stake their tokens with any validator on a Casper network. Alternatively, it is possible to stake tokens via an exchange or custody provider.

Here are a few common topics related to staking, but we also encourage you to do your own research.

Node operators stake their tokens to earn eligibility to propose and approve blocks on the network. They also run and maintain servers connected to the network. If they win a validator slot, they become validators and help enable the Proof-of-Stake aspect of the network, a process different from mining tokens. Validators thus earn rewards for participating and for securing the network.

Anyone can participate in the protocol to earn rewards without maintaining a Casper node (a server that stores a copy of the blockchain). One can delegate or allocate CSPR tokens to a chosen validator on the network. Validators retain a percentage of the rewards generated from staked tokens. Participating in the protocol this way, the community can help improve the network's decentralization and security and earn rewards in return. Block explorers connected to the network usually post the base annual reward rate.

Casper does not treat validator stake differently than delegator stake for security reasons.

Slashing

Presently Casper does not slash if a validator equivocates or misbehaves. If a node equivocates, other validators will ignore its messages, and the node will become inactive. The node will terminate once it detects that it has equivocated.

Delegation Rate

Validators define a delegation rate that they take in exchange for providing staking services. This rate is a percentage of the rewards that the validator retains for their services.

Delegation Fees

It is important to know that the cost of the delegation process is approximately 3 CSPR. Ensure you have extra CSPR in your account's main purse apart from the amount you are delegating; otherwise, the transaction will fail. For example, if you want to delegate 1000 CSPR, you need to have at least 1003 CSPR in your account's main purse.

Rewards

Validators receive rewards proportional to their stake for securing the network and participating in consensus (by voting and finalizing blocks). Delegators receive a portion of the validator's rewards, proportional to what they delegated, minus the validator's delegation rate. The rewards earned are reduced if a validator is offline or cannot vote on many blocks.

There is no precise reward per block. Rewards are split proportionally among stakes within an era and are distributed at the end of each era.

Selecting a Node for Delegating

As a prospective delegator, it is essential to select a validating node that you can trust. Block explorers such as cspr.live provide validator performance statistics, including a performance score, total stake, number of delegators, and fees. Please do your due diligence before staking tokens with a validator.

4.3

Monitoring Rewards

It's recommended that you check in on how your stake is performing from time to time. If the validator you staked with decides to unbond, your stake will also be unbonded and you will not earn rewards. Ensure that the validator you selected performs as per your expectations.

Validators have to win a staking auction by competing for a validator slot with prospective and current validators. This process is permissionless, meaning validators can join and leave the auction without restrictions, except for the unbonding wait period, which lasts 14 hours.

Unbonding Period

For security purposes, whenever tokens are un-delegated, the protocol will continue to keep the token locked for 14 hours.

Tutorials

Navigate to these pages for step-by-step tutorials on creating an account and delegating and undelegating tokens.

Block Explorers

The Casper blockchain is available as the Mainnet and Testnet. The Mainnet is the Casper blockchain that utilizes Casper tokens (CSPR). The Testnet is an alternate Casper blockchain used to test applications without spending CSPR tokens on the Casper Mainnet.

You can use block explorers to explore the Casper blockchain such as :

What is a Block Explorer

A block explorer is a search engine for the blockchain. It allows you to find information such as the transactions executed on the blockchain, the transaction statistics, the validators on the network, and similar blockchain activity. A block explorer gives you information on your account and all the transactions carried out using the account. You can use it to find a specific transaction or view the blockchain's transaction history.

Using a Block Explorer

You can use a block explorer to view the blockchain statistics, list of validators, list of blocks executed on the blockchain, list of deploys, and the nodes operating on the blockchain. You can also transfer CSPR tokens, delegate tokens to a validator to earn rewards or undelegate tokens from a validator.

The following topics link you to detailed instructions on using the cspr.live block explorer to access and work with your CSPR tokens.

note

To perform actions using the cspr.live block explorer, you must sign in to your Casper account using one of the wallets provided.

Delegating Tokens with a Block Explorer

Introduction

This tutorial covers how to delegate Casper tokens to a validator on the network.

Casper and other Proof-of-Stake protocols allow token holders to earn rewards and participate in the protocol through a mechanism called delegation or staking. We will use these terms interchangeably in this guide. See the Staking Key Concepts page for more details about the differences.

Prerequisites

  1. To stake tokens with a validator, you must create an account with CSPR tokens in its main purse. One option is to use the Casper Wallet by following the Getting Started user guide.
  2. You need to fund the account's main purse to delegate tokens.
  3. Connect to a block explorer to set up the delegation. This guide uses cspr.live and the Casper Wallet.
  4. Review your account before starting the process.
  5. Review the current delegation fees and ensure you have extra CSPR in your account's main purse apart from the amount you are delegating. Otherwise, the delegation might fail.

Reviewing your Account

Once connected to the Casper blockchain, we recommend reviewing the active account you wish to use for delegating tokens, especially these fields:

  • The Liquid Account Balance, representing the tokens you have for immediate use
  • The Delegated Account Balance, representing the delegated tokens already staked with validators on the network
  • The Delegations tab, listing the validators to whom you have delegated tokens
Account and delegations details
  • The Staking Rewards tab, showing the rewards received in each era
Account and rewards

Accessing the Delegation Feature

You can access the delegation functionality in two ways.

Option 1: Click Wallet from the top navigation menu and then click Delegate. In the next screen, you will need to specify the validator's public key or search for a validator.

Delegate from the Wallet

Option 2: Click Validators from the top navigation menu. From the validators table, click on any validator to access their details. Once you find the validator to whom you want to delegate tokens, click the Delegate button. The next screen will have the validator's public key pre-populated.

Delegate from a Validator

Stepping through the Delegation Process

The following instructions will take you through the delegation process, starting with the "Delegation details" screen.

Step 1 - Delegation details

  1. Specify the validator's public key if you have reached this screen using the Wallet drop-down menu. Otherwise, verify the pre-populated key in the Validator field.
  2. Enter the amount of CSPR you wish to delegate. Remember to account for the delegation fee.
  3. Click Next.
Delegation details

Step 2 - Confirm the delegation

  1. Review the delegation details.
  2. If everything is correct, click Confirm and delegate stake. If you wish to make changes, return to the previous screen.
Confirm delegation details

Step 3 - Sign the delegation

  1. Sign the delegation by clicking Sign with Casper Wallet.
Sign delegation
  1. Once the Casper Wallet opens, check the deploy hash. Ensure the deploy hash in the "Signature Request" window matches the deploy hash in the "Sign delegation" window before continuing.
Signature Request window
  1. Click Sign in the Signature Request window to finalize the delegation.
Completed delegation

The delegation initiates as soon as the corresponding deploy is signed. You can review the details and status of the deploy by clicking the Deploy Details highlighted above.

Remember to Monitor your Stake. Staking rewards are delivered to your account's main purse after each era, which is currently set to 2 hours. Note that it may take up to 2 eras (4 hours) for the first reward to appear after delegation. The rewards are automatically added to your current stake on the corresponding validator. You may view them under the Rewards tab on your account page on https://cspr.live/.

If you want to undelegate your tokens, you can do so at any time. See the Undelegation Guide for details.

Video Tutorial

This video guide covers the process at a high level, but we recommend following the written tutorial to go through the process step by step.

Funding Mainnet Accounts from an Exchange

To send CSPR tokens from an exchange to a Mainnet account, you need the Mainnet account's public key. Then, you can set up a withdrawal request from the exchange using this public key. The transfer will take a few minutes.

This guide demonstrates a withdrawal from Coinlist to the Casper Mainnet using the cspr.live block explorer. You need to contact the exchange for instructions if you are working with a different exchange.

Prerequisites

Before starting, copy the public key where you wish to transfer funds. The screenshot below shows the account page on https://cspr.live/ and the field you need to specify in the withdrawal request from Coinlist.

Account public key from CSPR.live

Transfers from Coinlist to Casper Mainnet

Try these steps with a small amount of CSPR first. After one successful transfer, you will be more comfortable transferring larger amounts.

  1. Log into your https://coinlist.co/ account.
  2. Go to the "Wallet" tab.
Coinlist Wallet tab
  1. Click on the "CSPR" section.
CSPR on Coinlist
  1. Click on the "Withdraw" button.
Withdraw on Coinlist
  1. Enter the public key of the Mainnet account in the "Recipient Address" field of the withdrawal request.
Withdrawal fields on Coinlist
  1. Enter 0 in the "Transfer ID" field or another value that is meaningful to you. You MUST enter a value, or the transfer will fail!

  2. Enter the CSPR amount you wish to transfer.

  3. Click "Review".

  4. Submit the transfer request. Wait approximately 5 minutes, and then go to the https://cspr.live/ site to verify your account details. On the account page, you should see that the "Liquid Account Balance" reflects the amount you have transferred.

Users Overview

General Topics

TopicDescription
Block ExplorersA guide to understanding block explorers
Funding Mainnet AccountsFunding Mainnet accounts from an exchange

Using CSPR.live

Interact with the Casper blockchain using the cspr.live block explorer.

TopicDescription
Funding Testnet AccountsFunding your Testnet account using the Faucet
Delegating TokensStaking your Casper tokens with cspr.live
Undelegating TokensUn-staking your Casper tokens
Transferring TokensTransferring your Casper tokens using cspr.live

Using Ledger Devices

Interact with the Casper blockchain using a Ledger device.

TopicDescription
Ledger SetupA guide to setting up your Ledger device
Delegating with Ledger DevicesDelegating tokens using your Ledger device

Using Ledger and CSPR.live

This guide will help you connect your Ledger device to a Casper account using the cspr.live block explorer to send and receive CSPR tokens.

Prerequisites

  1. Install a Chromium-based browser, such as Chrome or Brave, for use with cspr.live for the Casper Mainnet.

Signing In

To use the Ledger device with the cspr.live block explorer, follow these steps:

  1. Connect the Ledger device to your computer and unlock it by entering your device PIN.
  2. Open the Casper app on the Ledger device as shown above.
  3. While keeping the Casper app open, navigate to cspr.live/sign-in.

Sign into cspr.live

  1. Click on the Connect button in the Ledger section.

Choose to connect with Ledger

  1. Click the Connect to Ledger wallet button next.

Connect to Ledger Wallet in CSPR Live

  1. Select an account you want to use.

Choose an account to connect

  1. Your Ledger device is now connected to the block explorer, displaying your account details.

Account connected

Viewing Account Details

  1. Open cspr.live.
  2. Click on the account in the upper-right corner of the page.
3-view-account
  1. Click on the View Account button.
6-view-account-button
  1. You are presented with a page displaying details about your account. Check your account's main purse balance in the Liquid row under Total Balance.
4-account-details

Receiving Tokens

To receive tokens, you need to provide the sender with your account's public key. To find it, follow these steps:

  1. Open the account details page as described here and copy the public key in the Public Key row.
  2. Alternatively, click on the drop-down menu on your account address.
View account
  1. Click on the Copy Public Key button and share it with the sender.
Copy public key

Sending Tokens

  1. Open cspr.live.
  2. Sign in with your Ledger device.
  3. Click on Wallet and then Transfer CSPR.
5-transfer-wallet
  1. Fill in the details for the transfer.

1-transfer-details

  1. Click on the Next button.
  2. On the next page, click Confirm and transfer.

2-transfer-confirm

  1. On the Sign transaction page, click on the Sign with Ledger button.

3-transfer-sign

  1. Your Ledger hardware wallet will present you with transfer details. Verify the transfer details (txn hash, chain ID, source account, fee, target, and amount). Meanwhile, the block explorer will show this message:

3-transfer-sign

Verify the transaction on your Ledger device

Press the right button on your Ledger Device to review the transaction details (Amount and Address) until you see "Approve".

  1. Verify the Txn hash - ensure it matches the value displayed on cspr.live.

3-txn-1

The Txn hash value continues on a second screen.

4-txn-2

  1. The next page displays transaction Type - for CSPR transfers, that will be Token transfer.

5-type

  1. Verify the Chain ID, which identifies the network to which you want to send the transaction.

7-chain

  1. Verify the Account, the account's public key initiating the transaction.

8-account-1

The Account value continues on a second screen.

9-account-2

  1. Verify the Fee. For CSPR token transfers, that value should be constant and equal to 100,000,000 motes = 0.1 CSPR.

10-fee

  1. Verify the Target, the recipient's public key. Compare this value with the one in the block explorer.

11-target-1

The Target value continues on a second screen.

12-target-2

  1. Verify the Amount you want to transfer.

13-amount

  1. If you want to approve the transaction, click both buttons on the Ledger device while on the APPROVE screen.

15-approve

After approving the transaction with your Ledger hardware wallet, the cspr.live block explorer will display a "Transfer completed" page.

4-transfer-completed

You can now check your account to see a list of all the completed transfers.

Using Ledger and Ledger Live

This guide will help you connect accounts from the Ledger device to the Ledger Live application to send and receive CSPR tokens.

info

From Ledger Live version 2.73.1, Casper accounts can be added from the Ledger hardware wallet to Ledger Live.

Prerequisites

  1. Configure your Ledger and the Ledger Live application as described in the Getting Started with Ledger Live article.
  2. Install the Casper app as described here.

Connecting to Ledger Live

This section describes using the Ledger device with the Ledger Live application and your Casper accounts.

  1. Connect the Ledger device to your computer and unlock it by entering your device PIN.

Connect the Ledger to your computer

  1. Allow Ledger Manager to connect by clicking the two buttons on the Ledger device.

Unlock the Ledger

  1. Ledger Live will verify your Ledger device and display the following confirmation:

Confirmation that the Ledger is genuine

  1. Click My Ledger in the left-side navigation bar, and search for Casper or CSPR in the App catalog.

Confirmation that the Ledger is genuine

  1. To import a Casper account from the Ledger device into the Ledger Live application, click on the Add account link.

Click the Add account link

  1. Open the Casper app on your Ledger device.

Open the Casper app

  1. Ledger Live will import the first account listed on your Ledger device. Choose a name for the account.

Name the account

  1. After synchronizing the account, Ledger Live will confirm that the account was successfully added.

Synchronizing the account

Confirmation that the account was added

  1. Click on the account summary, to view more details.

Account summary

Account details

  1. To add another account, open the Account option in the left-side navigation bar. Then, click on the Add account button.

Add a second account

Receiving Tokens

To receive tokens, you need to provide the sender with your account's public key.

caution

Casper accounts only support CSPR tokens. Sending other tokens to a Casper account may result in the permanent loss of funds.

  1. Click on the Receive option in the left-side navigation bar.

Click on Receive

  1. Choose an account from the drop-down list.

Choose an account

  1. Copy the address displayed, or use the corresponding QR code.

Choose an account

  1. Verify that the address displayed in Ledger Live matches the address on your Ledger screen. If it does, click APPROVE.

Verify address part 1

Verify address part 2

Click APPROVE

Confirmation displayed

Sending Tokens

Ledger Live supports sending CSPR tokens from one Casper account to another.

  1. Start by clicking on the Send option in the left-side navigation bar. Choose the account to debit:

Choose the account to debit

  1. Enter the recipient's address and click Continue.

Enter recipient

  1. Enter the amount and an optional transfer ID. Click Continue.

Enter amount and transfer ID

  1. Review the summary, and if everything is correct, click Continue. Otherwise, click the Back link in the top-left corner.

Review the transfer

  1. Your Ledger hardware wallet will present you with the transfer details. Verify the transaction hash, chain ID, source account, fee, target, and amount. Meanwhile, Ledger Live will display this message:

Review the transaction in the Ledger

Verify the transaction on your Ledger device

Press the right button on your Ledger Device to review the transaction details until you see "APPROVE".

  1. Review the Txn hash.

3-txn-1

The Txn hash value continues on a second screen.

4-txn-2

  1. The next screen displays the transaction Type, which will be Token transfer.

5-type

  1. Verify the chain ID, which for Mainnet should be casper.

7-chain

  1. Verify the Account initiating the token transfer.

8-account-1

The Account value continues on a second screen.

9-account-2

  1. Verify the Fee. For CSPR token transfers, that value should be constant and equal to 100,000,000 motes = 0.1 CSPR.

10-fee

  1. Verify the Target, which is the recipient's public key.

11-target-1

The Target value continues on a second screen.

12-target-2

  1. Verify the Amount you want to transfer.

13-amount

  1. If you want to approve the transaction, click both buttons on the Ledger device while on the APPROVE screen.

15-approve

  1. After approving the transaction with your Ledger hardware wallet, Ledger Live will display the following windows:

Broadcasting transaction

Transaction sent

  1. To view the transaction details, click on the View details button. The following screen will appear:

Transaction details

  1. You can view the transaction in the CSPR.live block explorer by clicking on the View in explorer link.

Explorer showing transaction

Delegating with Ledger Devices

Ledger Initialization

Before getting started, you need to complete two prerequisite steps:

  1. Set up your Ledger device using the official documentation.
  2. Connect the Ledger to your cspr.live account by following the Ledger Setup guide.

Important Notes

  1. CRITICAL: Write down and hide your recovery codes! These are necessary to be able to restore your account if you lose or damage the hardware key.
  2. When logging in to cspr.live, the UI will offer numerous public keys. Choose any of them. They are all derived from the Master Seed that is secured in the Ledger key (more info here). Make sure you write down whichever public key(s) you end up using so that you have no confusion when trying to log in.

Staking with a Validator

Connect and Login with Ledger

  1. Connect your Ledger to your computer via USB and enter your PIN to unlock it.

  2. Open the Casper app on the Ledger (you will see the message "Casper Ready").

    Casper Ready
  3. Sign in to cspr.live with your Ledger by clicking "Connect" under the Ledger option, as shown in the screenshot below.

    Casper Ready
  4. Select the public key connected to your Ledger account.

    Casper Ready
  5. View your account by clicking on your public key at the top right corner.

    Casper Ready

Receive Tokens from an External Source

This portion will vary slightly depending on where your funds are currently stored. However, the process will require that you send tokens to your public key as described in the documentation.

Staking Tokens

Once you have tokens in your account, staking (delegating) with a validator is easy.

  1. Go back to your account, but this time open the "delegate" tab located at: https://cspr.live/delegate-stake (alternatively, click on Wallet ⇒ Delegate Stake to go there).

  2. From the validator list, choose any validator you like. You will notice that validators charge different fees and have different amounts staked to them. This may inform your decision to choose the right validator for you.

  3. Specify the amount you wish to stake or click "Delegate max" as shown below. Notes:

    1. Remember that the total delegation amount to one validator cannot be less than 500 CSPR.
    2. Both delegation and undelegation have an associated fee, so you need to leave some funds in your account to cover transaction fees. Otherwise, you may need to deposit additional funds to undelegate later.
  4. Click "Next" to continue, as shown below.

    Casper Ready
  5. The page will update with a confirmation page asking you to verify all the details. If everything looks correct, click the "Confirm and delegate stake" button.

  6. You will be presented with a final page asking you to sign the transaction with Ledger. Click the "Sign with Ledger" button at the bottom.

    Note: If you get an error showing a "Transaction rejected" message, make sure your Ledger device is active and connected to your computer. You may also need to re-enter your PIN if it locked itself due to inactivity.

    Casper Ready
  7. On the Ledger, you will see a message saying, "Please review". Click through the fields and verify everything matches what is being shown to you on cspr.live.

    Casper Ready
  8. Once you click "Approve", you will see the Delegation Completed screen verifying that your staking successfully was submitted to the blockchain.

    Casper Ready Casper Ready
  9. At this point, you can return to your account and wait until the completion of the era when the block gets included in the chain. Once the era completes, you will see that your liquid balance has decreased by your staked amount and is reflected in the "Staked As Delegator" row.

    Note: If you staked your full balance, don't panic if you see a 0 CSPR balance whenever you log in! This is because it shows your liquid assets, not your total balance. You can go to your account details page, as shown below, to see your full balance and asset breakdown between liquid, staked, and undelegated tokens.

    Casper Ready

Unstaking with a Validator

Initiate the Undelegation

Now that you have funds delegated, you can liquidate them by undelegating them first. As demonstrated below, on your account's profile page, click "Undelegate" to get started.

Casper Ready

The next page, "Undelegation details", will ask you how much you wish to undelegate. If you select "Undelegate max", it will attempt to liquidate all of your staked assets (minus the transaction fee). Once you enter a valid amount, the "Next" button will become clickable. Below you can see that I entered 313.02931 CSPR to be able to proceed.

Casper Ready

You will next be shown a confirmation screen. If everything looks good, then click "Confirm and undelegate stake" to proceed.

Sign the Undelegation

You will have to sign the transaction to verify your account is initiating this action.

  1. Connect your Ledger device to your computer.

  2. Unlock your Ledger by entering your PIN.

  3. Open the "Casper" app and ensure you see "Casper Ready".

  4. Then back on cspr.live click the "Sign with Ledger" button shown below.

    Casper Ready

On your Ledger, you will see the transaction details. Verify all the information with what is being presented on the screen. If it looks good, then approve the transaction. If all goes according to plan, you will be presented with an "Undelegation completed!" screen.

Casper Ready

Note: There is a 7 era delay to undelegate. Era duration is approximately 120 minutes. While the funds go through undelegation, the balance will appear in the "Undelegation" row on your account profile page, as you can see below.

Casper Ready

After the undelegation period completes, your funds will be liquid and available for you to re-stake, withdraw, or use however you wish.

Funding Testnet Accounts

The Casper Testnet is an alternate Casper blockchain that enables testing applications without spending CSPR on the Mainnet. The Testnet is deployed independently from the Mainnet for users to experiment with network features such as transferring, delegating, and undelegating tokens. One way to access the Casper Testnet is to use the cspr.live block explorer.

Testnet tokens are independent of the Casper token (CSPR). While test tokens do not have any monetary value, they possess the same functionality as the CSPR token within the confines of the Testnet. Users can fund Testnet accounts as outlined below.

Requesting Testnet Tokens

To request test tokens, follow these steps:

  1. Log into the Casper Testnet with the Casper Wallet. See the Getting Started user guide for detailed instructions.

  2. Click Tools on the top menu bar and select Faucet from the drop-down menu. Or, navigate to the Faucet using this link: https://testnet.cspr.live/tools/faucet.

  3. Click Request tokens on the Faucet page:

caution

Tokens can be requested only once per account. Otherwise, the deploy will fail with status User error: 1.

If you have already exhausted your test funds, you can always create a new account.

  1. The Testnet will credit your account with test tokens.

Transferring Tokens

You can transfer Casper tokens (CSPR) using any block explorer built to explore the Casper blockchain. The Wallet feature on these block explorers enables transfers to another user's purse, delegate stake, or undelegate stake. In this section, we will discuss the steps to transfer CSPR tokens.

Transferring Tokens

To transfer tokens, follow these steps:

  1. Sign in to your account with the Casper Wallet. See the Getting Started user guide for detailed instructions.
  2. Click Wallet on the top menu bar and select Transfer CSPR from the drop-down menu.
  3. Enter the recipient's public key, the amount you wish to transfer, and an optional Transfer ID for reference. If you do not provide an ID, the system will auto-generate one.
  4. Click Next to proceed.
Transfer details
  1. A confirmation window appears to verify the details entered. Click Confirm and transfer to proceed to the next step.
Confirm transfer
  1. Review the following important fields:
  • The Deploy hash, which uniquely identifies your transfer
  • The Recipient public key of the person receiving your transfer
  • The Recipient account hash used by the system to track the transaction
  • The Transfer Amount containing the value of the transfer

Sign the transaction by selecting the Sign with Casper Wallet button to proceed to the next step.

Sign the transfer
  1. Once the Casper Wallet opens, check the deploy hash. Ensure the deploy hash in the "Signature Request" window matches the deploy hash in the "Sign transaction" window before continuing. Click Sign in the Signature Request window to complete the transaction.
Review the transaction
  1. You completed the transaction and successfully transferred tokens.
Transfer completed window
  1. View the updated CSPR balance in the account's main purse next.

Undelegating Tokens

If you want to undelegate tokens from a validator, you can do so at any time. Note that undelegation costs approximately 0.5 CSPR.

Prerequisites

This guide assumes that you have previously delegated tokens to a validator using a block explorer or the Casper client.

Accessing the Undelegation Feature

You can access the undelegation functionality in three ways.

Option 1: Click Wallet from the top navigation menu and then click Undelegate Stake.

Undelegate from Wallet

Option 2: Click Validators from the top navigation menu. Using the validators table, find the validator you wish to undelegate from, and click the Undelegate Stake button.

Undelegate from Validator

Option 3: Open your account details and select the Delegations tab. Click the Undelegate button next to the validator from whom you wish to undelegate.

Undelegate from Account View

Stepping through the Undelegation Process

The following instructions will take you through the undelegation process, starting with the "Undelegation details" screen.

Step 1 - Undelegation details

  1. Specify the validator from whom you want to undelegate your tokens if you have reached this screen using the Wallet drop-down menu. The search box will automatically show you the validators with whom you have staked. Otherwise, verify the pre-populated key in the Validator field.
  2. Enter the amount of Casper tokens you want to undelegate.
  3. Click Next.
Undelegation details

Step 2 - Confirm the undelegation

  1. Review the undelegation details.
  2. If everything looks correct, click Confirm and undelegate stake. If you wish to make changes, return to the previous screen.
Confirm undelegation

Step 3 - Sign the undelegation

  1. Click Sign with Casper Wallet to sign the undelegation.
Sign the undelegation
  1. Once the Casper Wallet opens, check the deploy hash. Ensure the deploy hash in the "Signature Request" window matches the deploy hash in the "Sign undelegation" window before continuing.
Confirm deploy hash
  1. Click Sign in the Signature Request window to finalize the undelegation. The stake undelegation initiates as soon as the corresponding deploy is signed. Here is the expected output:
Undelegation confirmed

It may take 1-2 minutes for the undelegation details to become available. Click "Deploy Details" for more information.

Note that your undelegated tokens will appear in your account automatically after a 7-era delay of approximately 14 hours.

Ledger Setup with Casper

A Ledger device is a hardware wallet considered one of the most secure ways to store your digital assets. Ledger uses an offline, or cold storage, method of generating private keys, making it a preferred method for many crypto users.

Prerequisites

  1. Configure your Ledger and the Ledger Live application as described in the Getting Started with Ledger Live article.
  2. CRITICAL: Write down and hide your recovery codes! These are necessary to be able to restore your account if you lose or damage the hardware key.
  3. Make sure the Ledger Live application version is at least at 2.73.1, which is the version that includes Casper accounts.
note

If you need help, contact us on Twitter, Discord, or Telegram.

Installing the Casper App on a Ledger Device

Install the Casper app on the Ledger device by following the steps below. You can find similar instructions on the official Ledger support site.

  1. In Ledger Live, open My Ledger at the bottom of the left-hand menu.

Open My Ledger

  1. Connect the Ledger device to your computer and unlock it by entering your device PIN.

Unlock your Ledger device

  1. If asked, allow Ledger manager on your device.

Allow Ledger

  1. Find Casper in the app catalog.

Find the Casper app

info

Having trouble finding the Casper app? Please search "Casper," not "CSPR" when searching for the app in the "My Ledger" tab in Ledger Live.

  1. Click the Install button of the app.
  • An installation window appears.
  • Your device will display "Processing..."
  • The app installation is confirmed.

Casper installation confirmed

  1. Open the Casper App on your Ledger device by clicking both buttons on the device, and keep it open while doing the next steps.

Select Casper on Ledger

Casper app is ready

Sending and Receiving Tokens

To send and receive CSPR tokens using the accounts on your Ledger device, you have two options:

  1. Manage Casper Accounts using Ledger and Ledger Live
  2. Manage Casper Accounts using Ledger and CSPR.live

To stake CSPR tokens with a validator on the Casper Mainnet, you need to use the CSPR.live block explorer, as described in Delegating with Ledger Devices.

Buying, selling, or swapping CSPR are not currently supported in Ledger Live. For these operations, you need to visit an exchange.

Writing On-Chain Code

This section shows you how to write session code and smart contracts in Rust and WebAssembly (Wasm) for a Casper network. When referring to session code, these documents outline logic that executes in the context of an account. In contrast, smart contracts consist of logic installed on-chain, for use by multiple parties. There is a large overlap between the processes of writing session code versus contract code, with some semantic differences outlined in their respective documentation. The Video Series for Writing On-Chain Code accompanies the topics below.

TitleDescription
Getting Started with RustAn introduction to using Rust with the Casper Platform
Getting Started with AssemblyScriptAn introduction to using AssemblyScript with the Casper Platform
Writing a Basic Smart Contract in RustAn example of a smart contract built in Rust
Unit Testing Smart ContractsSteps to test contract code using the unit testing framework
Upgrading and Maintaining Smart ContractsAn introduction to versioning smart contracts
Calling Contracts
Smart Contracts and Session CodeUnderstand what session code is and when you would use it over contract code
Writing Session CodeAn introduction to writing session code
Unit Testing Session CodeSteps to test session code using the unit testing framework
Using Contract Hash vs. Package HashAdvantages and disadvantages of using contract_hash vs. contract_package_hash when calling a contract
Best Practices for Casper Smart Contract AuthorsAn outline of best practices when developing smart contracts on a Casper network

Interacting with Contracts on the Blockchain

Additionally, the section on Interacting with the Blockchain covers installing and calling contracts using the Casper command-line client written in Rust.

TitleDescription
Installing Smart Contracts and Querying Global StateA guide on installing smart contracts and querying global state
Calling Smart Contracts with the Rust ClientSteps to call a smart contract with the Rust command-line client
Reading and Writing to DictionariesInformation on Dictionaries and how to read and write to them on the Casper Platform.
Execution Error CodesPossible error codes when writing smart contracts.

Tutorials

The following tutorials outline some aspects of writing smart contracts on a Casper network.

TitleDescription
Getting Started VideoStep-by-step video tutorial for setting up the Casper development environment
A Counter on the TestnetAn example contract that maintains a counter variable on the Casper Testnet
Smart Contract UpgradesLearn how to upgrade smart contracts
NFTs on Casper with the CEP-78 NFT StandardImplementing the Casper CEP-78 NFT standard
Fungible Tokens on CasperImplement the Casper Fungible Token standard
Interacting with Runtime Return ValuesLearning how to return a value using contract code
Working with Authorization KeysRetrieving and using the authorization keys associated with a deploy
Safely Transfer Tokens to a ContractHow to handle tokens via a contract