mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-23 23:01:33 +00:00
docs/coding-guidelines: Add document (#2780)
Add document outlining a set of coding guidelines followed and to be followed across the rust-libp2p code base. Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
This commit is contained in:
39
docs/architecture.svg
Normal file
39
docs/architecture.svg
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="326px" preserveAspectRatio="none" style="width:651px;height:326px;background:#FFFFFF;" version="1.1" viewBox="0 0 651 326" width="651px" zoomAndPan="magnify"><defs/><g><!--MD5=[82a8024e11f0bc254006762718306828]
|
||||||
|
class Swarm--><g id="elem_Swarm"><rect fill="#F1F1F1" height="64.2969" id="Swarm" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="80" x="393" y="7"/><ellipse cx="408" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M410.3438,18.6719 C409.4063,18.2344 408.8125,18.0938 407.9375,18.0938 C405.3125,18.0938 403.3125,20.1719 403.3125,22.8906 L403.3125,24.0156 C403.3125,26.5938 405.4219,28.4844 408.3125,28.4844 C409.5313,28.4844 410.6875,28.1875 411.4375,27.6406 C412.0156,27.2344 412.3438,26.7813 412.3438,26.3906 C412.3438,25.9375 411.9531,25.5469 411.4844,25.5469 C411.2656,25.5469 411.0625,25.625 410.875,25.8125 C410.4219,26.2969 410.4219,26.2969 410.2344,26.3906 C409.8125,26.6563 409.125,26.7813 408.3594,26.7813 C406.3125,26.7813 405.0156,25.6875 405.0156,23.9844 L405.0156,22.8906 C405.0156,21.1094 406.2656,19.7969 408,19.7969 C408.5781,19.7969 409.1875,19.9531 409.6563,20.2031 C410.1406,20.4844 410.3125,20.7031 410.4063,21.1094 C410.4688,21.5156 410.5,21.6406 410.6406,21.7656 C410.7813,21.9063 411.0156,22.0156 411.2344,22.0156 C411.5,22.0156 411.7656,21.875 411.9375,21.6563 C412.0469,21.5 412.0781,21.3125 412.0781,20.8906 L412.0781,19.4688 C412.0781,19.0313 412.0625,18.9063 411.9688,18.75 C411.8125,18.4844 411.5313,18.3438 411.2344,18.3438 C410.9375,18.3438 410.7344,18.4375 410.5156,18.75 L410.3438,18.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="48" x="422" y="27.8467">Swarm</text><line style="stroke:#181818;stroke-width:0.5;" x1="394" x2="472" y1="39" y2="39"/><line style="stroke:#181818;stroke-width:0.5;" x1="394" x2="472" y1="47" y2="47"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="37" x="399" y="63.9951">poll()</text></g><!--MD5=[8ae7a888e4418fcc4e43df307d553e3c]
|
||||||
|
class RootBehaviour--><g id="elem_RootBehaviour"><rect fill="#F1F1F1" height="64.2969" id="RootBehaviour" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="138" x="187" y="131"/><ellipse cx="202" cy="147" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M204.3438,142.6719 C203.4063,142.2344 202.8125,142.0938 201.9375,142.0938 C199.3125,142.0938 197.3125,144.1719 197.3125,146.8906 L197.3125,148.0156 C197.3125,150.5938 199.4219,152.4844 202.3125,152.4844 C203.5313,152.4844 204.6875,152.1875 205.4375,151.6406 C206.0156,151.2344 206.3438,150.7813 206.3438,150.3906 C206.3438,149.9375 205.9531,149.5469 205.4844,149.5469 C205.2656,149.5469 205.0625,149.625 204.875,149.8125 C204.4219,150.2969 204.4219,150.2969 204.2344,150.3906 C203.8125,150.6563 203.125,150.7813 202.3594,150.7813 C200.3125,150.7813 199.0156,149.6875 199.0156,147.9844 L199.0156,146.8906 C199.0156,145.1094 200.2656,143.7969 202,143.7969 C202.5781,143.7969 203.1875,143.9531 203.6563,144.2031 C204.1406,144.4844 204.3125,144.7031 204.4063,145.1094 C204.4688,145.5156 204.5,145.6406 204.6406,145.7656 C204.7813,145.9063 205.0156,146.0156 205.2344,146.0156 C205.5,146.0156 205.7656,145.875 205.9375,145.6563 C206.0469,145.5 206.0781,145.3125 206.0781,144.8906 L206.0781,143.4688 C206.0781,143.0313 206.0625,142.9063 205.9688,142.75 C205.8125,142.4844 205.5313,142.3438 205.2344,142.3438 C204.9375,142.3438 204.7344,142.4375 204.5156,142.75 L204.3438,142.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="106" x="216" y="151.8467">RootBehaviour</text><line style="stroke:#181818;stroke-width:0.5;" x1="188" x2="324" y1="163" y2="163"/><line style="stroke:#181818;stroke-width:0.5;" x1="188" x2="324" y1="171" y2="171"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="37" x="193" y="187.9951">poll()</text></g><!--MD5=[3b2f882b07ec8d0f9d7b5edac19dedb3]
|
||||||
|
class ConnectionPool--><g id="elem_ConnectionPool"><rect fill="#F1F1F1" height="64.2969" id="ConnectionPool" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="146" x="360" y="131"/><ellipse cx="375" cy="147" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M377.3438,142.6719 C376.4063,142.2344 375.8125,142.0938 374.9375,142.0938 C372.3125,142.0938 370.3125,144.1719 370.3125,146.8906 L370.3125,148.0156 C370.3125,150.5938 372.4219,152.4844 375.3125,152.4844 C376.5313,152.4844 377.6875,152.1875 378.4375,151.6406 C379.0156,151.2344 379.3438,150.7813 379.3438,150.3906 C379.3438,149.9375 378.9531,149.5469 378.4844,149.5469 C378.2656,149.5469 378.0625,149.625 377.875,149.8125 C377.4219,150.2969 377.4219,150.2969 377.2344,150.3906 C376.8125,150.6563 376.125,150.7813 375.3594,150.7813 C373.3125,150.7813 372.0156,149.6875 372.0156,147.9844 L372.0156,146.8906 C372.0156,145.1094 373.2656,143.7969 375,143.7969 C375.5781,143.7969 376.1875,143.9531 376.6563,144.2031 C377.1406,144.4844 377.3125,144.7031 377.4063,145.1094 C377.4688,145.5156 377.5,145.6406 377.6406,145.7656 C377.7813,145.9063 378.0156,146.0156 378.2344,146.0156 C378.5,146.0156 378.7656,145.875 378.9375,145.6563 C379.0469,145.5 379.0781,145.3125 379.0781,144.8906 L379.0781,143.4688 C379.0781,143.0313 379.0625,142.9063 378.9688,142.75 C378.8125,142.4844 378.5313,142.3438 378.2344,142.3438 C377.9375,142.3438 377.7344,142.4375 377.5156,142.75 L377.3438,142.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="114" x="389" y="151.8467">ConnectionPool</text><line style="stroke:#181818;stroke-width:0.5;" x1="361" x2="505" y1="163" y2="163"/><line style="stroke:#181818;stroke-width:0.5;" x1="361" x2="505" y1="171" y2="171"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="37" x="366" y="187.9951">poll()</text></g><!--MD5=[ea193e58bf01a8bb640ee5c4ebd1a9a0]
|
||||||
|
class Transport--><g id="elem_Transport"><rect fill="#F1F1F1" height="64.2969" id="Transport" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="103" x="541.5" y="131"/><ellipse cx="556.5" cy="147" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M558.8438,142.6719 C557.9063,142.2344 557.3125,142.0938 556.4375,142.0938 C553.8125,142.0938 551.8125,144.1719 551.8125,146.8906 L551.8125,148.0156 C551.8125,150.5938 553.9219,152.4844 556.8125,152.4844 C558.0313,152.4844 559.1875,152.1875 559.9375,151.6406 C560.5156,151.2344 560.8438,150.7813 560.8438,150.3906 C560.8438,149.9375 560.4531,149.5469 559.9844,149.5469 C559.7656,149.5469 559.5625,149.625 559.375,149.8125 C558.9219,150.2969 558.9219,150.2969 558.7344,150.3906 C558.3125,150.6563 557.625,150.7813 556.8594,150.7813 C554.8125,150.7813 553.5156,149.6875 553.5156,147.9844 L553.5156,146.8906 C553.5156,145.1094 554.7656,143.7969 556.5,143.7969 C557.0781,143.7969 557.6875,143.9531 558.1563,144.2031 C558.6406,144.4844 558.8125,144.7031 558.9063,145.1094 C558.9688,145.5156 559,145.6406 559.1406,145.7656 C559.2813,145.9063 559.5156,146.0156 559.7344,146.0156 C560,146.0156 560.2656,145.875 560.4375,145.6563 C560.5469,145.5 560.5781,145.3125 560.5781,144.8906 L560.5781,143.4688 C560.5781,143.0313 560.5625,142.9063 560.4688,142.75 C560.3125,142.4844 560.0313,142.3438 559.7344,142.3438 C559.4375,142.3438 559.2344,142.4375 559.0156,142.75 L558.8438,142.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="71" x="570.5" y="151.8467">Transport</text><line style="stroke:#181818;stroke-width:0.5;" x1="542.5" x2="643.5" y1="163" y2="163"/><line style="stroke:#181818;stroke-width:0.5;" x1="542.5" x2="643.5" y1="171" y2="171"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="37" x="547.5" y="187.9951">poll()</text></g><!--MD5=[36a618e552b4a111d62bd2e8e5713411]
|
||||||
|
class PingBehaviour--><g id="elem_PingBehaviour"><rect fill="#F1F1F1" height="64.2969" id="PingBehaviour" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="134" x="7" y="255"/><ellipse cx="22" cy="271" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M24.3438,266.6719 C23.4063,266.2344 22.8125,266.0938 21.9375,266.0938 C19.3125,266.0938 17.3125,268.1719 17.3125,270.8906 L17.3125,272.0156 C17.3125,274.5938 19.4219,276.4844 22.3125,276.4844 C23.5313,276.4844 24.6875,276.1875 25.4375,275.6406 C26.0156,275.2344 26.3438,274.7813 26.3438,274.3906 C26.3438,273.9375 25.9531,273.5469 25.4844,273.5469 C25.2656,273.5469 25.0625,273.625 24.875,273.8125 C24.4219,274.2969 24.4219,274.2969 24.2344,274.3906 C23.8125,274.6563 23.125,274.7813 22.3594,274.7813 C20.3125,274.7813 19.0156,273.6875 19.0156,271.9844 L19.0156,270.8906 C19.0156,269.1094 20.2656,267.7969 22,267.7969 C22.5781,267.7969 23.1875,267.9531 23.6563,268.2031 C24.1406,268.4844 24.3125,268.7031 24.4063,269.1094 C24.4688,269.5156 24.5,269.6406 24.6406,269.7656 C24.7813,269.9063 25.0156,270.0156 25.2344,270.0156 C25.5,270.0156 25.7656,269.875 25.9375,269.6563 C26.0469,269.5 26.0781,269.3125 26.0781,268.8906 L26.0781,267.4688 C26.0781,267.0313 26.0625,266.9063 25.9688,266.75 C25.8125,266.4844 25.5313,266.3438 25.2344,266.3438 C24.9375,266.3438 24.7344,266.4375 24.5156,266.75 L24.3438,266.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="102" x="36" y="275.8467">PingBehaviour</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="140" y1="287" y2="287"/><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="140" y1="295" y2="295"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="37" x="13" y="311.9951">poll()</text></g><!--MD5=[8cda839a2161fdcdc77d772a45eee7be]
|
||||||
|
class IdentifyBehaviour--><g id="elem_IdentifyBehaviour"><rect fill="#F1F1F1" height="64.2969" id="IdentifyBehaviour" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="159" x="176.5" y="255"/><ellipse cx="191.5" cy="271" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M193.8438,266.6719 C192.9063,266.2344 192.3125,266.0938 191.4375,266.0938 C188.8125,266.0938 186.8125,268.1719 186.8125,270.8906 L186.8125,272.0156 C186.8125,274.5938 188.9219,276.4844 191.8125,276.4844 C193.0313,276.4844 194.1875,276.1875 194.9375,275.6406 C195.5156,275.2344 195.8438,274.7813 195.8438,274.3906 C195.8438,273.9375 195.4531,273.5469 194.9844,273.5469 C194.7656,273.5469 194.5625,273.625 194.375,273.8125 C193.9219,274.2969 193.9219,274.2969 193.7344,274.3906 C193.3125,274.6563 192.625,274.7813 191.8594,274.7813 C189.8125,274.7813 188.5156,273.6875 188.5156,271.9844 L188.5156,270.8906 C188.5156,269.1094 189.7656,267.7969 191.5,267.7969 C192.0781,267.7969 192.6875,267.9531 193.1563,268.2031 C193.6406,268.4844 193.8125,268.7031 193.9063,269.1094 C193.9688,269.5156 194,269.6406 194.1406,269.7656 C194.2813,269.9063 194.5156,270.0156 194.7344,270.0156 C195,270.0156 195.2656,269.875 195.4375,269.6563 C195.5469,269.5 195.5781,269.3125 195.5781,268.8906 L195.5781,267.4688 C195.5781,267.0313 195.5625,266.9063 195.4688,266.75 C195.3125,266.4844 195.0313,266.3438 194.7344,266.3438 C194.4375,266.3438 194.2344,266.4375 194.0156,266.75 L193.8438,266.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="127" x="205.5" y="275.8467">IdentifyBehaviour</text><line style="stroke:#181818;stroke-width:0.5;" x1="177.5" x2="334.5" y1="287" y2="287"/><line style="stroke:#181818;stroke-width:0.5;" x1="177.5" x2="334.5" y1="295" y2="295"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="37" x="182.5" y="311.9951">poll()</text></g><!--MD5=[ce977af12e7578d8152683fbf6bdca71]
|
||||||
|
class KademliaBehaviour--><g id="elem_KademliaBehaviour"><rect fill="#F1F1F1" height="64.2969" id="KademliaBehaviour" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="169" x="370.5" y="255"/><ellipse cx="385.5" cy="271" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M387.8438,266.6719 C386.9063,266.2344 386.3125,266.0938 385.4375,266.0938 C382.8125,266.0938 380.8125,268.1719 380.8125,270.8906 L380.8125,272.0156 C380.8125,274.5938 382.9219,276.4844 385.8125,276.4844 C387.0313,276.4844 388.1875,276.1875 388.9375,275.6406 C389.5156,275.2344 389.8438,274.7813 389.8438,274.3906 C389.8438,273.9375 389.4531,273.5469 388.9844,273.5469 C388.7656,273.5469 388.5625,273.625 388.375,273.8125 C387.9219,274.2969 387.9219,274.2969 387.7344,274.3906 C387.3125,274.6563 386.625,274.7813 385.8594,274.7813 C383.8125,274.7813 382.5156,273.6875 382.5156,271.9844 L382.5156,270.8906 C382.5156,269.1094 383.7656,267.7969 385.5,267.7969 C386.0781,267.7969 386.6875,267.9531 387.1563,268.2031 C387.6406,268.4844 387.8125,268.7031 387.9063,269.1094 C387.9688,269.5156 388,269.6406 388.1406,269.7656 C388.2813,269.9063 388.5156,270.0156 388.7344,270.0156 C389,270.0156 389.2656,269.875 389.4375,269.6563 C389.5469,269.5 389.5781,269.3125 389.5781,268.8906 L389.5781,267.4688 C389.5781,267.0313 389.5625,266.9063 389.4688,266.75 C389.3125,266.4844 389.0313,266.3438 388.7344,266.3438 C388.4375,266.3438 388.2344,266.4375 388.0156,266.75 L387.8438,266.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="137" x="399.5" y="275.8467">KademliaBehaviour</text><line style="stroke:#181818;stroke-width:0.5;" x1="371.5" x2="538.5" y1="287" y2="287"/><line style="stroke:#181818;stroke-width:0.5;" x1="371.5" x2="538.5" y1="295" y2="295"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="37" x="376.5" y="311.9951">poll()</text></g><!--MD5=[d0be09c99c53035c18497598e4f42028]
|
||||||
|
reverse link Swarm to RootBehaviour--><g id="link_Swarm_RootBehaviour"><path codeLine="1" d="M376.282,79.094 C351.929,95.88 323.873,115.217 300.986,130.992 " fill="none" id="Swarm-backto-RootBehaviour" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="372.396,73.27,392.836,67.684,380.341,84.798,372.396,73.27" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[9fd2a4dbd83fba718d7bd5c8cd6d854a]
|
||||||
|
reverse link Swarm to ConnectionPool--><g id="link_Swarm_ConnectionPool"><path codeLine="2" d="M433,91.341 C433,104.806 433,118.916 433,130.955 " fill="none" id="Swarm-backto-ConnectionPool" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="426,91.101,433,71.101,440,91.101,426,91.101" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[42120d8655174db4310b94cc0c231b7d]
|
||||||
|
reverse link Swarm to Transport--><g id="link_Swarm_Transport"><path codeLine="3" d="M489.342,82.961 C510.019,98.727 533.014,116.261 552.082,130.8 " fill="none" id="Swarm-backto-Transport" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="485.034,88.479,473.375,70.786,493.523,77.346,485.034,88.479" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[332af27f56b7b2b29f50a091a146b37a]
|
||||||
|
reverse link RootBehaviour to PingBehaviour--><g id="link_RootBehaviour_PingBehaviour"><path codeLine="4" d="M192.846,206.334 C169.002,222.3175 142.335,240.1932 120.312,254.9554 " fill="none" id="RootBehaviour-backto-PingBehaviour" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="189.092,200.423,209.603,195.101,196.888,212.052,189.092,200.423" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[d3fe83cb864e7625e8bf13d063167fbd]
|
||||||
|
reverse link RootBehaviour to IdentifyBehaviour--><g id="link_RootBehaviour_IdentifyBehaviour"><path codeLine="5" d="M256,215.341 C256,228.8065 256,242.9163 256,254.9554 " fill="none" id="RootBehaviour-backto-IdentifyBehaviour" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="249,215.101,256,195.101,263,215.101,249,215.101" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[94eabc804f9d348e2a27a48eae887d9f]
|
||||||
|
reverse link RootBehaviour to KademliaBehaviour--><g id="link_RootBehaviour_KademliaBehaviour"><path codeLine="6" d="M323.916,205.637 C350.274,221.7962 379.932,239.9782 404.362,254.9554 " fill="none" id="RootBehaviour-backto-KademliaBehaviour" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="none" points="320.123,211.522,306.731,195.101,327.44,199.587,320.123,211.522" style="stroke:#181818;stroke-width:1.0;"/></g><!--MD5=[b8fae327631bdb77e15ae691037ae60b]
|
||||||
|
@startuml
|
||||||
|
Swarm <|- - RootBehaviour
|
||||||
|
Swarm <|- - ConnectionPool
|
||||||
|
Swarm <|- - Transport
|
||||||
|
RootBehaviour <|- - PingBehaviour
|
||||||
|
RootBehaviour <|- - IdentifyBehaviour
|
||||||
|
RootBehaviour <|- - KademliaBehaviour
|
||||||
|
|
||||||
|
Swarm : poll()
|
||||||
|
RootBehaviour : poll()
|
||||||
|
ConnectionPool : poll()
|
||||||
|
Transport : poll()
|
||||||
|
PingBehaviour : poll()
|
||||||
|
IdentifyBehaviour : poll()
|
||||||
|
KademliaBehaviour : poll()
|
||||||
|
@enduml
|
||||||
|
|
||||||
|
PlantUML version 1.2022.7beta2(Unknown compile time)
|
||||||
|
(GPL source distribution)
|
||||||
|
Java Runtime: Java(TM) SE Runtime Environment
|
||||||
|
JVM: Java HotSpot(TM) 64-Bit Server VM
|
||||||
|
Default Encoding: UTF-8
|
||||||
|
Language: en
|
||||||
|
Country: US
|
||||||
|
--></g></svg>
|
After Width: | Height: | Size: 17 KiB |
287
docs/coding-guidelines.md
Normal file
287
docs/coding-guidelines.md
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
# Coding Guidelines
|
||||||
|
|
||||||
|
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
|
||||||
|
**Table of Contents**
|
||||||
|
|
||||||
|
- [Coding Guidelines](#coding-guidelines)
|
||||||
|
- [Hierarchical State Machines](#hierarchical-state-machines)
|
||||||
|
- [Conventions for `poll` implementations](#conventions-for-poll-implementations)
|
||||||
|
- [Prioritize local work over new work from a remote](#prioritize-local-work-over-new-work-from-a-remote)
|
||||||
|
- [Bound everything](#bound-everything)
|
||||||
|
- [Channels](#channels)
|
||||||
|
- [Local queues](#local-queues)
|
||||||
|
- [Further reading](#further-reading)
|
||||||
|
- [No premature optimizations](#no-premature-optimizations)
|
||||||
|
- [Keep things sequential unless proven to be slow](#keep-things-sequential-unless-proven-to-be-slow)
|
||||||
|
- [Use `async/await` for sequential execution only](#use-asyncawait-for-sequential-execution-only)
|
||||||
|
- [Don't communicate by sharing memory; share memory by communicating.](#dont-communicate-by-sharing-memory-share-memory-by-communicating)
|
||||||
|
- [Further Reading](#further-reading)
|
||||||
|
- [Use iteration not recursion](#use-iteration-not-recursion)
|
||||||
|
- [Further Reading](#further-reading-1)
|
||||||
|
|
||||||
|
<!-- markdown-toc end -->
|
||||||
|
|
||||||
|
|
||||||
|
Below is a set of coding guidelines followed across the rust-libp2p code base.
|
||||||
|
|
||||||
|
## Hierarchical State Machines
|
||||||
|
|
||||||
|
If you sqint, rust-libp2p is just a big hierarchy of [state
|
||||||
|
machines](https://en.wikipedia.org/wiki/Finite-state_machine) where parents pass
|
||||||
|
events down to their children and children pass events up to their parents.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Reproduce diagram</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
@startuml
|
||||||
|
Swarm <|-- RootBehaviour
|
||||||
|
Swarm <|-- ConnectionPool
|
||||||
|
Swarm <|-- Transport
|
||||||
|
RootBehaviour <|-- PingBehaviour
|
||||||
|
RootBehaviour <|-- IdentifyBehaviour
|
||||||
|
RootBehaviour <|-- KademliaBehaviour
|
||||||
|
|
||||||
|
Swarm : poll()
|
||||||
|
RootBehaviour : poll()
|
||||||
|
ConnectionPool : poll()
|
||||||
|
Transport : poll()
|
||||||
|
PingBehaviour : poll()
|
||||||
|
IdentifyBehaviour : poll()
|
||||||
|
KademliaBehaviour : poll()
|
||||||
|
@enduml
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Using hierarchical state machines is a deliberate choice throughout the
|
||||||
|
rust-libp2p code base. It makes reasoning about control and data flow simple. It
|
||||||
|
works well with Rust's `Future` model. It allows fine-grain control e.g. on the
|
||||||
|
order child state machines are polled.
|
||||||
|
|
||||||
|
The above comes with downsides. It feels more verbose. The mix of control flow (`loop`, `return`,
|
||||||
|
`break`, `continue`) in `poll` functions together with the asynchronous and thus decoupled
|
||||||
|
communication via events can be very hard to understand. Both are a form of complexity that we are
|
||||||
|
trading for correctness and performance which aligns with Rust's and rust-libp2p's goals.
|
||||||
|
|
||||||
|
The architecture pattern of hierarchical state machines should be used wherever possible.
|
||||||
|
|
||||||
|
### Conventions for `poll` implementations
|
||||||
|
|
||||||
|
The `poll` method of a single state machine can be complex especially when that
|
||||||
|
state machine itself `poll`s many child state machines. The patterns shown below
|
||||||
|
have proven useful and should be followed across the code base.
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>{
|
||||||
|
loop {
|
||||||
|
match self.child_1.poll(cx) {
|
||||||
|
// The child made progress.
|
||||||
|
Poll::Ready(_) => {
|
||||||
|
// Either return an event to the parent:
|
||||||
|
return Poll::Ready(todo!());
|
||||||
|
// or `continue`, thus polling `child_1` again. `child_1` can potentially make more progress. Try to exhaust
|
||||||
|
// it before moving on to the next child.
|
||||||
|
continue
|
||||||
|
// but NEVER move to the next child if the current child made progress. Given
|
||||||
|
// that the current child might be able to make more progress, it did not yet
|
||||||
|
// register the waker in order for the root task to be woken up later on. Moving
|
||||||
|
// on to the next child might result in the larger `Future` task to stall as it
|
||||||
|
// assumes that there is no more progress to be made.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The child did not make progress. It has registered the waker for a
|
||||||
|
// later wake up. Proceed with the other children.
|
||||||
|
Poll::Pending(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.child_2.poll(cx) {
|
||||||
|
Poll::Ready(child_2_event) => {
|
||||||
|
// Events can be dispatched from one child to the other.
|
||||||
|
self.child_1.handle_event(child_2_event);
|
||||||
|
|
||||||
|
// Either `continue` thus polling `child_1` again, or `return Poll::Ready` with a result to the parent.
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
Poll::Pending(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.child_3.poll(cx) {
|
||||||
|
Poll::Ready(__) => {
|
||||||
|
// Either `continue` thus polling `child_1` again, or `return Poll::Ready` with a result to the parent.
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
Poll::Pending(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// None of the child state machines can make any more progress. Each registered
|
||||||
|
// the waker in order for the root `Future` task to be woken up again.
|
||||||
|
return Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Prioritize local work over new work from a remote
|
||||||
|
|
||||||
|
When handling multiple work streams, prioritize local work items over
|
||||||
|
accepting new work items from a remote. Take the following state machine as an
|
||||||
|
example, reading and writing from a socket, returning result to its parent:
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
struct SomeStateMachine {
|
||||||
|
socket: Socket,
|
||||||
|
events_to_return_to_parent: VecDeque<Event>,
|
||||||
|
messages_to_send_on_socket: VecDeque<Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stream for SomeStateMachine {
|
||||||
|
type Item = Event;
|
||||||
|
|
||||||
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
loop {
|
||||||
|
// First priority is returning local finished work.
|
||||||
|
if let Some(event) = events_to_return_to_parent.pop_front() {
|
||||||
|
return Poll::Ready(Some(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second priority is finishing local work, i.e. sending on the socket.
|
||||||
|
if let Poll::Ready(()) = socket.poll_ready(cx) {
|
||||||
|
todo!("Send messages")
|
||||||
|
continue // Go back to the top. One might be able to send more.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last priority is accepting new work, i.e. reading from the socket.
|
||||||
|
if let Poll::Ready(work_item) = socket.poll_next(cx) {
|
||||||
|
todo!("Start work on new item")
|
||||||
|
continue // Go back to the top. There might be more progress to be made.
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point in time, there is no more progress to be made. Return
|
||||||
|
// `Pending` and be woken up later.
|
||||||
|
return Poll::Pending;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This priotization provides:
|
||||||
|
- Low memory footprint as local queues (here `events_to_return_to_parent`) stay small.
|
||||||
|
- Low latency as accepted local work is not stuck in queues.
|
||||||
|
- DOS defense as a remote does not control the size of the local queue, nor starves local work with its remote work.
|
||||||
|
|
||||||
|
## Bound everything
|
||||||
|
|
||||||
|
The concept of unboundedness is an illusion. Use bounded mechanisms to prevent
|
||||||
|
unbounded memory growth and high latencies.
|
||||||
|
|
||||||
|
### Channels
|
||||||
|
|
||||||
|
When using channels (e.g. `futures::channel::mpsc` or `std::sync::mpsc`)
|
||||||
|
always use the bounded variant, never use the unbounded variant. When using a
|
||||||
|
bounded channel, a slow consumer eventually slows down a fast producer once
|
||||||
|
the channel bound is reached, ideally granting the slow consumer more system
|
||||||
|
resources e.g. CPU time, keeping queues small and thus latencies low. When
|
||||||
|
using an unbounded channel a fast producer continues being a fast producer,
|
||||||
|
growing the channel buffer indefinitely, increasing latency until the illusion
|
||||||
|
of unboundedness breaks and the system runs out of memory.
|
||||||
|
|
||||||
|
One may use an unbounded channel if one enforces backpressure through an
|
||||||
|
out-of-band mechanism, e.g. the consumer granting the producer send-tokens
|
||||||
|
through a side-channel.
|
||||||
|
|
||||||
|
### Local queues
|
||||||
|
|
||||||
|
As for channels shared across potentially concurrent actors (e.g. future tasks
|
||||||
|
or OS threads), the same applies for queues owned by a single actor only. E.g.
|
||||||
|
reading events from a socket into a `Vec<Event>` without some mechanism
|
||||||
|
bounding the size of that `Vec<Event>` again can lead to unbounded memory
|
||||||
|
growth and high latencies.
|
||||||
|
|
||||||
|
Note that rust-libp2p fails at this guideline, i.e. still has many unbounded
|
||||||
|
local queues.
|
||||||
|
|
||||||
|
### Further reading
|
||||||
|
|
||||||
|
- https://en.wikipedia.org/wiki/Bufferbloat
|
||||||
|
- https://apenwarr.ca/log/20170814
|
||||||
|
- https://twitter.com/peterbourgon/status/1212800031406739456
|
||||||
|
|
||||||
|
## No premature optimizations
|
||||||
|
|
||||||
|
Optimizations that add complexity need to be accompanied with a proof of their
|
||||||
|
effectiveness.
|
||||||
|
|
||||||
|
This as well applies to increasing buffer or channel sizes, as the downside of
|
||||||
|
such pseudo optimizations is increased memory footprint and latency.
|
||||||
|
|
||||||
|
## Keep things sequential unless proven to be slow
|
||||||
|
|
||||||
|
Concurrency adds complexity. Concurrency adds overhead due to synchronization.
|
||||||
|
Thus unless proven to be a bottleneck, don't make things concurrent. As an example
|
||||||
|
the hierarchical `NetworkBehaviour` state machine runs sequentially. It is easy
|
||||||
|
to debug as it runs sequentially. Thus far there has been no proof that
|
||||||
|
shows a speed up when running it concurrently.
|
||||||
|
|
||||||
|
## Use `async/await` for sequential execution only
|
||||||
|
|
||||||
|
Using `async/await` for sequential execution makes things significantly simpler.
|
||||||
|
Though unfortunately using `async/await` does not allow accesing methods on the
|
||||||
|
object being `await`ed unless paired with some synchronization mechanism like an
|
||||||
|
`Arc<Mutex<_>>`.
|
||||||
|
|
||||||
|
Example: Read and once done write from/to a socket. Use `async/await`.
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
socket.read_exact(&mut read_buf).await;
|
||||||
|
socket.write(&write_buf).await;
|
||||||
|
```
|
||||||
|
|
||||||
|
Example: Read and concurrently write from/to a socket. Use `poll`.
|
||||||
|
|
||||||
|
``` rust
|
||||||
|
loop {
|
||||||
|
match socket.poll_read(cx, &mut read_buf) {
|
||||||
|
Poll::Ready(_) => {
|
||||||
|
todo!();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Poll::Pending => {}
|
||||||
|
}
|
||||||
|
match socket.poll_write(cx, &write_buf) {
|
||||||
|
Poll::Ready(_) => {
|
||||||
|
todo!();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Poll::Pending => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Poll::Pending;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When providing `async` methods, make it explicit whether it is safe to cancel
|
||||||
|
the resulting `Future`, i.e. whether it is safe to drop the `Future` returned
|
||||||
|
by the `async` method.
|
||||||
|
|
||||||
|
## Don't communicate by sharing memory; share memory by communicating.
|
||||||
|
|
||||||
|
The majority of rust-libp2p's code base follows the above Golang philosophy,
|
||||||
|
e.g. using channels instead of mutexes. This pattern enforces single ownership
|
||||||
|
over data, which works well with Rust's ownership model and makes reasoning
|
||||||
|
about data flow easier.
|
||||||
|
|
||||||
|
### Further Reading
|
||||||
|
|
||||||
|
- https://go.dev/blog/codelab-share
|
||||||
|
|
||||||
|
## Use iteration not recursion
|
||||||
|
|
||||||
|
Rust does not support tail call optimization, thus using recursion may grow the
|
||||||
|
stack potentially unboundedly. Instead use iteration e.g. via `loop` or `for`.
|
||||||
|
|
||||||
|
### Further Reading
|
||||||
|
|
||||||
|
- https://en.wikipedia.org/wiki/Tail_call
|
||||||
|
- https://stackoverflow.com/questions/65948553/why-is-recursion-not-suggested-in-rust
|
||||||
|
- https://stackoverflow.com/questions/59257543/when-is-tail-recursion-guaranteed-in-rust
|
Reference in New Issue
Block a user