3.4-protocol.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # Section 3.4 from "Streamlet: Textbook Streamlined Blockchains"
  2. from block import Block
  3. from node import Node
  4. from vrf import VRF
  5. import math
  6. import numpy as np
  7. # Genesis block is generated.
  8. genesis_block = Block("⊥", 0, '⊥')
  9. # We create some nodes to participate in the Protocol.
  10. # There are in total n nodes numbered.
  11. node0 = Node(0, "clock", "node_password0", genesis_block)
  12. node1 = Node(1, "clock", "node_password1", genesis_block)
  13. node2 = Node(2, "clock", "node_password2", genesis_block)
  14. node3 = Node(3, "clock", "node_password3", genesis_block)
  15. node4 = Node(4, "clock", "node_password4", genesis_block)
  16. node5 = Node(5, "clock", "node_password5", genesis_block)
  17. nodes = [node0, node1, node2, node3, node4, node5]
  18. # We simulate some rounds to test consistency.
  19. epoch = 1
  20. # Nodes receive transactions and broacasts them between them.
  21. # node0 receives input and broadcasts it to rest nodes.
  22. node0.receive_transaction("tx0")
  23. node0.broadcast_transaction([node1, node2, node3, node4, node5], "tx0")
  24. # node1 receives input and broadcasts it to rest nodes.
  25. node1.receive_transaction("tx2")
  26. node1.broadcast_transaction([node0, node2, node3, node4, node5], "tx2")
  27. # node4 receives input and broadcasts it to rest nodes.
  28. node4.receive_transaction("tx3")
  29. node4.broadcast_transaction([node0, node1, node2, node3, node5], "tx3")
  30. vrf = VRF()
  31. x = epoch
  32. y, pi, g = vrf.sign(x)
  33. Y = np.array(y)
  34. y_hypotenuse2 = np.sum(Y[1]**2+Y[2]**2)
  35. # A random leader is selected.
  36. leader = nodes[math.ceil(y_hypotenuse2)%len(nodes)]
  37. print(f"proposed {x}, {y}, {pi}, {vrf.pk}, {g}")
  38. # Leader forms a block and broadcasts it.
  39. leader.propose_block(1, y, pi, vrf.pk, g, nodes)
  40. # Nodes vote on the block and broadcast their vote to rest nodes.
  41. for node in nodes:
  42. node.vote_on_round_block(nodes)
  43. # We verify that all nodes have the same blockchain on round end.
  44. assert(node0.output() == node1.output() == node2.output() == node3.output() == node4.output() == node5.output())
  45. epoch = 2
  46. # We introduce a new node. Assumption: no history sync, a Node starts participating in next epoch.
  47. node6 = Node(6, "clock", "node_password5", node0.output()[-1])
  48. nodes.append(node6)
  49. # node3 receives input and broadcasts it to rest nodes.
  50. node3.receive_transaction("tx4")
  51. node3.broadcast_transaction([node0, node1, node2, node4, node5, node6], "tx4")
  52. # node5 receives input and broadcasts it to rest nodes.
  53. node5.receive_transaction("tx5")
  54. node5.broadcast_transaction([node0, node1, node2, node3, node4, node6], "tx5")
  55. # node6 receives input and broadcasts it to rest nodes.
  56. node6.receive_transaction("tx6")
  57. node6.broadcast_transaction([node0, node1, node2, node3, node4, node5], "tx6")
  58. x = epoch
  59. vrf = VRF()
  60. y, pi, g = vrf.sign(x)
  61. Y = np.array(y)
  62. y_hypotenuse2 = np.sum(Y[1]**2+Y[2]**2)
  63. # A random leader is selected.
  64. leader = nodes[math.ceil(y_hypotenuse2)%len(nodes)]
  65. # A random leader is selected.
  66. print(f"epoch number in protocol: {epoch}")
  67. # Leader forms a block and broadcasts it.
  68. leader.propose_block(epoch, y, pi, vrf.pk, g, nodes)
  69. # Nodes vote on the block and broadcast their vote to rest nodes.
  70. for node in nodes:
  71. node.vote_on_round_block(nodes)
  72. # We verify that all nodes have the same blockchain on round end.
  73. assert(node0.output() == node1.output() == node2.output() == node3.output() == node4.output() == node5.output())
  74. # Since node6 joined later, node0 output is a prefix or equal to node6 output.
  75. # Based on that, node6 output is a suffix of node0 output.
  76. assert(node0.output().blocks[-len(node6.output()):] == node6.output().blocks)
  77. print('finished...')