2-execution-model-and-definitions.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # Section 2 from "Streamlet: Textbook Streamlined Blockchains"
  2. class Node:
  3. ''' This class represents a simplyfied protocol node.
  4. Each node is numbered and has a secret-public keys pair, to sign messages.
  5. Modes receive inputs (transactions) and maintain an ordered log (blockchain),
  6. containing a sequense of strings (blocks). '''
  7. def __init__(self, id, secret_key, public_key):
  8. self.id = id
  9. self.secret_key = secret_key
  10. self.public_key = public_key
  11. self.blockchain = Blockchain()
  12. self.inputs = []
  13. def __repr__(self):
  14. return "Node=[id={0}, secret_key={1}, public_key={2}, blockchain={3}, inputs={4}".format(self.id, self.secret_key, self.public_key, self.blockchain, self.inputs)
  15. def receive_input(self, input):
  16. # Additional validity rules must be defined by the protocol for its blockchain data structure.
  17. self.inputs.append(input)
  18. def output(self):
  19. return self.blockchain
  20. def broadcast(self, nodes, input):
  21. for node in nodes:
  22. node.receive_input(input)
  23. def finalize_block(self):
  24. block = Block(self.inputs)
  25. self.blockchain.add_block(block) # Block is appended to nodes blockchain
  26. self.inputs = []
  27. class Block:
  28. ''' This class represents a simplyfied block structure. '''
  29. def __init__(self, transactions):
  30. self.transactions = transactions
  31. def __repr__(self):
  32. return "Block=[transactions={0}]".format(self.transactions)
  33. def __eq__(self, other):
  34. return self.transactions == other.transactions
  35. class Blockchain:
  36. ''' This class represents a simplyfied blockchain structure. '''
  37. def __init__(self):
  38. self.blocks = []
  39. def __repr__(self):
  40. return "Blockchain=[blocks={0}]".format(self.blocks)
  41. def __eq__(self, other):
  42. return self.blocks == other.blocks
  43. def __len__(self):
  44. return len(self.blocks)
  45. def __getitem__(self, index):
  46. return self.blocks[index]
  47. def add_block(self, block):
  48. self.blocks.append(block)
  49. # There are in total n nodes numbered.
  50. node0 = Node(0, "dummy_secret_key0", "dummy_public_key0")
  51. node1 = Node(1, "dummy_secret_key1", "dummy_public_key1")
  52. # Advesary chooses last node to corrupt(static corruption).
  53. corruptedNode = Node(2, "dummy_secret_key2", "dummy_public_key2")
  54. # We simulate some rounds to test consistency.
  55. # Round 0 synchronization period.
  56. # node0 receives input and broadcasts it to rest nodes.
  57. node0.receive_input("tx0")
  58. node0.broadcast([node1, corruptedNode], "tx0")
  59. # node1 receives input and broadcasts it to rest nodes.
  60. node1.receive_input("tx1")
  61. node1.broadcast([node0, corruptedNode], "tx1")
  62. # corruptedNode receives input but doesn't broadcast to rest nodes.
  63. corruptedNode.receive_input("tx2")
  64. # We assume nodes finalize blocks(append to blockchain) at the end of each round.
  65. node0.finalize_block()
  66. node1.finalize_block()
  67. corruptedNode.finalize_block()
  68. # In round 1, a new node joins.
  69. node3 = Node(3, "dummy_secret_key3", "dummy_public_key3")
  70. # node3 receives input and broadcasts it to rest nodes.
  71. node3.receive_input("tx3")
  72. node3.broadcast([node0, node1, corruptedNode], "tx3")
  73. # Nodes finalize blocks.
  74. node0.finalize_block()
  75. node1.finalize_block()
  76. corruptedNode.finalize_block()
  77. node3.finalize_block()
  78. # Consistency testing.
  79. # node0 and node1 remained honest, therefore their outputs must be the same.
  80. assert(node0.output() == node1.output())
  81. # Since node3 joined later, node0 and node1 outputs are a prefix or equal to node3 output.
  82. # Based on that, node3 output is a suffix of node0 and node1 outputs.
  83. assert(node0.output()[-len(node3.output()):] == node3.output().blocks)
  84. assert(node1.output()[-len(node3.output()):] == node3.output().blocks)
  85. # Below assertion will fail, as corrupt node deviated from the protocol.
  86. # assert(node0.output() == corruptedNode.output())