import%20marimo%0A%0A__generated_with%20%3D%20%220.15.3%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20json%0A%20%20%20%20from%20hashlib%20import%20sha256%0A%0A%20%20%20%20class%20Block%3A%0A%20%20%20%20%20%20%20%20%22%22%22Represents%20a%20block%20in%20a%20blockchain%20with%20message%2C%20timestamp%2C%20and%20reference%20to%20previous%20block.%22%22%22%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20message%2C%20time%2C%20reference%3DNone)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Initialize%20a%20new%20Block.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Args%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20message%3A%20Content%20of%20the%20block%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20time%3A%20Timestamp%20of%20the%20block%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20reference%3A%20Hash%20of%20the%20previous%20block%20(None%20for%20genesis%20block)%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20self.message%20%3D%20message%0A%20%20%20%20%20%20%20%20%20%20%20%20self.time%20%3D%20time%0A%20%20%20%20%20%20%20%20%20%20%20%20self.reference%20%3D%20reference%0A%0A%20%20%20%20%20%20%20%20%40property%0A%20%20%20%20%20%20%20%20def%20hash(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Calculate%20the%20hash%20of%20this%20block%20based%20on%20its%20contents.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20str%3A%20SHA-256%20hash%20of%20the%20block's%20contents%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20x%20%3D%20%7B%22message%22%3A%20self.message%2C%20%22time%22%3A%20self.time%2C%20%22reference%22%3A%20self.reference%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20sha256(json.dumps(x).encode()).hexdigest()%0A%0A%20%20%20%20class%20Chain%3A%0A%20%20%20%20%20%20%20%20%22%22%22Represents%20a%20blockchain%20-%20a%20sequence%20of%20linked%20blocks.%22%22%22%0A%0A%20%20%20%20%20%20%20%20def%20__init__(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Initialize%20a%20new%20empty%20blockchain.%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20self.__chain%20%3D%20%5B%5D%0A%0A%20%20%20%20%20%20%20%20def%20append(self%2C%20message%2C%20time)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Add%20a%20new%20block%20to%20the%20chain.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Args%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20message%3A%20Content%20for%20the%20new%20block%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20time%3A%20Timestamp%20for%20the%20new%20block%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20append%20a%20block%20to%20the%20chain%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20if%20there%20is%20at%20least%20one%20block%20in%20the%20chain%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20len(self.__chain)%20%3E%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20compute%20the%20hash%20digest%20of%20the%20last%20block%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20reference%20%3D%20self.__chain%5B-1%5D.hash%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20reference%20%3D%20None%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20compute%20the%20Block%0A%20%20%20%20%20%20%20%20%20%20%20%20block%20%3D%20Block(message%3Dmessage%2C%20time%3Dtime%2C%20reference%3Dreference)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20append%20it%20to%20the%20chain%0A%20%20%20%20%20%20%20%20%20%20%20%20self.__chain.append(block)%0A%0A%20%20%20%20%20%20%20%20def%20__getitem__(self%2C%20item)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Access%20a%20block%20in%20the%20chain%20by%20index.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Args%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20item%3A%20Index%20of%20the%20block%20to%20retrieve%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Block%3A%20The%20requested%20block%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20self.__chain%5Bitem%5D%0A%0A%20%20%20%20%20%20%20%20%40property%0A%20%20%20%20%20%20%20%20def%20valid(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22Check%20if%20the%20blockchain%20is%20valid%20by%20verifying%20all%20block%20references.%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Returns%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bool%3A%20True%20if%20the%20chain%20is%20valid%2C%20False%20otherwise%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20a%2C%20b%20in%20zip(self.__chain%5B%3A-1%5D%2C%20self.__chain%5B1%3A%5D)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20a.hash%20!%3D%20b.reference%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20False%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20True%0A%20%20%20%20return%20(Chain%2C)%0A%0A%0A%40app.cell%0Adef%20_(Chain)%3A%0A%20%20%20%20chain%20%3D%20Chain()%0A%20%20%20%20chain.append(message%3D%22A%22%2C%20time%3D1)%0A%20%20%20%20chain.append(message%3D%22B%22%2C%20time%3D2)%0A%20%20%20%20chain.append(message%3D%22C%22%2C%20time%3D3)%0A%20%20%20%20chain.append(message%3D%22D%22%2C%20time%3D4)%0A%0A%20%20%20%20%23%20the%20chain%20is%20valid%20because%20the%20recomputed%20hash%20code%0A%20%20%20%20%23%20for%20block%20n%20is%20matching%20the%20reference%20in%20block%20n%2B1%0A%20%20%20%20assert%20chain.valid%0A%0A%20%20%20%20%23%20we%20chain%20the%20message%20of%20the%203rd%20block%0A%20%20%20%20%23%20and%20therefore%20the%20hash%20code%20for%20Block%203%0A%20%20%20%20%23%20is%20not%20matching%20the%20reference%20in%20Block%204%0A%20%20%20%20chain%5B2%5D.message%20%3D%20%22Thomas%20was%20here%22%0A%20%20%20%20assert%20not%20chain.valid%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
4f233e6ca68d95164136dd9c8068f5376b182bd512e74ffe0e50d1601a382ae6