def get_blockchain(): blockchain = Blockchain() blockchain_sql = Table("blockchain", "number", "hash", "previous", "data", "signature","time") for b in blockchain_sql.getall(): blockchain.add(Block((b.get('number')), b.get('previous'), b.get('data'), (b.get('signature')), b.get('time'))) return blockchain
def get_blockchain(): blockchain = Blockchain() blockchain_sql = Table("blockchain", "number", "hash", "previous", "data", "nonce") for b in blockchain_sql.getall(): blockchain.add(Block(int(b.get('number')), b.get('previous'), b.get('data'), int(b.get('nonce')))) return blockchain
def test_add_new_block_to_chain(): genesis_block = return_genesis_block() b = Block( 1, 0, 213123123123123, b'2\x84\x0f\xf6<\x88\xeb\xbej\xcc\xa6C\x02\xc47\x89J!\x93\xf5\x14S\xc6<Y=\xe2?\xf3\xe5\xae\xa2', 1577836800, "first block") # first of this is 10011100 bc = Blockchain(genesis_block, b) bc_short = Blockchain(genesis_block, b) assert bc.validate_chain() == True, "Chain Doesn't Validate" b1 = Block( 2, 0, 6477374, b'\x8a\x1c\x88T;\x86\x99\xe7i\xa1\xf9Y\x11\x9a\x9675\xd4^^ae+\x10h\x9f\x1f\x91{v\x99n', 1577836845, "second block") assert b1.check_difficulty(0) == True, "still in first block of difficulty" bc.add(b1) assert bc.validate_chain() == True, "Chain Doesn't Validate" longer_chain = bc.chain new_blockchain = bc.resolve_via_length(bc_short) assert new_blockchain.chain == longer_chain, "The chain is not the longer one" new_chain = bc_short.resolve_via_length(bc) assert new_blockchain.chain == longer_chain, "The chain is not the longer one"
def initializechain(): global txn4 chain = Blockchain() txn4 = Transaction('ServerReward',client1.publickey.to_string().hex(),100).to_json() block = Block([txn4]) chain.set_blockheader(block) chain.add(block,1) chain.transactionpool.append(txn4) return chain
def fileToBlockchain( f, dhs=None ): # f is the filename, dhs is the diffie hellman secret (default none) fBytes = open(f, 'rb') fBlockchain = Blockchain(dhs) cur = fBytes.read(64) while True: fBlockchain.add(cur) cur = fBytes.read(64) if len(cur) == 0: break return fBlockchain
def fileToBlockchainStream( f, dhs=None ): # f is the filename, dhs is the diffie hellman secret (default none) fBytes = open(f, 'rb') fBlockchain = Blockchain(dhs) cur = fBytes.read(64) while True: fBlockchain.add(cur) if fBlockchain.size > 1: yield fBlockchain.popHead() cur = fBytes.read(64) if len(cur) == 0: yield fBlockchain.popHead() break
def get_user_block(username): blockchain_sql = Table("blockchain", "number", "hash", "previous", "data", "nonce") user_blockchain = Blockchain() for b in blockchain_sql.getall(): data = b.get('data').split("-->") if username == data[0]: user_blockchain.add( Block(int(b.get('number')), b.get('previous'), b.get('data'), b.get('nonce'))) if username == data[1]: user_blockchain.add( Block(int(b.get('number')), b.get('previous'), b.get('data'), b.get('nonce'))) return user_blockchain
def init_chain(): genesis_block = return_genesis_block() b = Block( 1, 0, 213123123123123, b'2\x84\x0f\xf6<\x88\xeb\xbej\xcc\xa6C\x02\xc47\x89J!\x93\xf5\x14S\xc6<Y=\xe2?\xf3\xe5\xae\xa2', 1577836800, "first block") # first of this is 10011100 bc = Blockchain(genesis_block, b) b1 = Block( 2, 0, 6477374, b'\x8a\x1c\x88T;\x86\x99\xe7i\xa1\xf9Y\x11\x9a\x9675\xd4^^ae+\x10h\x9f\x1f\x91{v\x99n', 1577836845, "second block") bc.add(b1) return bc
def blockchain(): blockchain = Blockchain() private_keys = [43, 53, 63] public_keys = mapv(lambda priv: PrivateKey(priv).public_key().to_bytes(), private_keys) genesis_block = GenesisBlock(miner_pub_key=public_keys[0]) genesis_block.mine(blockchain.get_difficult()) blockchain.add(genesis_block) miners = [public_keys[1], public_keys[2]] outputs_array = [[(public_keys[0], 1), (public_keys[1], 2)], [(public_keys[2], 10), (public_keys[1], 1)]] for key, miner, outputs in zip(private_keys, miners, outputs_array): transaction = Wallet(key).sign(Transaction(outputs)) block = Block(blockchain.get_last_block(), [transaction], miner_pub_key=miner) block.mine(blockchain.get_difficult()) blockchain.add(block) return blockchain
def main(): bc = Blockchain() walletA = Wallet('A') walletB = Wallet('B') coinbase = Wallet('C') genesis_trx = Transaction(coinbase.public_key, walletA.public_key, 1000000, None) genesis_trx.generate_signature(coinbase.private_key, coinbase.password) genesis_trx.transaction_id = '0' genesis_trx.outputs.append(TransactionOutput(genesis_trx.recipient, genesis_trx.value, genesis_trx.transaction_id)) bc.genesis_trx = genesis_trx bc.UTXOs[bc.genesis_trx.outputs[0].id] = bc.genesis_trx.outputs[0] print('Creating and mining genesis block...') genesis = Block('0') genesis.add_transaction(genesis_trx) bc.add(genesis) f=open("time.csv", "w+") for i in range(1000000): print("%d: " % i, end='') start = time.time() block = Block(bc.get_last_hash()) # print("Wallet A's balance is:", walletA.get_balance()) # print("Wallet A is attempting to send funds(1) to Wallet B...") block.add_transaction(walletA.send_funds(walletB.public_key, 1)) bc.add(block) end = time.time() f.write(("%d,%f\n" % (i, end-start))) # print("Wallet A's balance is:", walletA.get_balance()) # print("Wallet B's balance is:", walletB.get_balance()) print("Wallet B's balance is:", walletB.get_balance()) print("Wallet B is attempting to send funds(1000000) to Wallet A...") start = time.time() block = Block(bc.get_last_hash()) block.add_transaction(walletB.send_funds(walletA.public_key, 1000000)) bc.add(block) end = time.time() print("Wallet A's balance is:", walletA.get_balance()) print("Wallet B's balance is:", walletB.get_balance()) print("Time elapsed: %fs" % (end-start)) bc.is_valid() f.close()
from blockchain import Blockchain, Transaction, Block ''' This is an example on how the simplified blockchain code can be used. To see it in action simply run the entire notebook. ''' # Setup blockchain blockchain = Blockchain() # Add new block by directly passing in transactions transaction_1 = Transaction("Aleksander Sadowski", "Wiktor Domaradzki", 1.00) transaction_2 = Transaction("Aleksander Sadowski", "Wiktor Domaradzki", 2.50) transaction_3 = Transaction("Wiktor Domaradzki", "Aleksander Sadowski", 3.50) blockchain.add_transactions([transaction_1, transaction_2, transaction_3]) # Add new block by first creating a new block and adding it to the blockchain afterwards transaction_4 = Transaction("Wiktor Domaradzki", "Aleksander Sadowski", 12.00) transaction_5 = Transaction("Aleksander Sadowski", "Wiktor Domaradzki", 5.50) block = Block(blockchain.blocks[1].hash.hexdigest(), [transaction_4, transaction_5]) blockchain.add(block) # Print blockchain to the console blockchain.display()
def test(): ## Generate Key sk = SigningKey.generate(curve=NIST192p) vk = sk.get_verifying_key() sk2 = SigningKey.generate(curve=NIST192p) vk2 = sk2.get_verifying_key() ## Create Transactions newTxn = Transaction(vk.to_string().hex(), 'receiverkey', 100) ## convert to JSON toJson = newTxn.to_json() ## Sign JSON signature = newTxn.sign(toJson, sk.to_string()) print(signature) ## Validate validated = newTxn.validate_signature(toJson, signature, vk.to_string()) txn1 = Transaction(vk.to_string().hex(), 'receiverkey1', 100).to_json() txn2 = Transaction(vk.to_string().hex(), 'client1', 100).to_json() txn3 = Transaction(vk2.to_string().hex(), 'client3', 100).to_json() transactionlist = [txn1, txn2, txn3] ## Create Block with transaction block = Block(transactionlist) block2 = Block([txn3]) chain = Blockchain() chain.set_blockheader(block) chain.add(block, 1) chain.set_blockheader(block2) chain.add(block2, 2) #Populate blockchain with blocks for i in range(2): chain.set_blockheader(block) chain.add(block, 1) txn4 = Transaction('receiverkey1', 'receiverkey3', 100).to_json() txn5 = Transaction('receiverkey3', 'receiverkey1', 100).to_json() chain.transactionpool.append(txn4) chain.transactionpool.append(txn5) # Miner Test m1 = Miner(chain) m2 = Miner(chain) block4 = m1.mine(chain) chain.add(block4, m1.publickey.to_string().hex()) block5 = m1.mine(chain) chain.add(block5, m1.publickey.to_string().hex()) # SPV Test spvclient = SPVClient() checktransaction = spvclient.receive_transaction(txn3, m1) newtxn = spvclient.new_txn(m1.publickey.to_string().hex(), 100) nt = m1.new_txn(spvclient.publickey.to_string().hex(), 100) print(nt) miners_list = [m1, m2] #####selfish mining attack#### m3 = SelfishMiner(chain) miners_list.append(m3) for miner in miners_list: block = miner.mine(chain) chain.add(block, miner.publickey.to_string().hex()) #trying to show the number of blocks mined by selfish miners selfish_blocks = m3.selfish_mine(chain) print("Selfish miner's work: ", selfish_blocks) ###DOUBLE SPENDING attack### m4 = DoubleSpender(chain) #first let m4 have some money #m2 make txn to send 60 to m4 txnToDS = m2.new_txn(m4.publickey.to_string().hex(), 60) #attacker mine the latest txn pool dsBlock = m4.mine(chain) chain.add(dsBlock, m4.publickey.to_string().hex()) print("Attacker's balance (before) is", m4.get_balance(chain, m4.publickey.to_string().hex())) #he then performs the attack dsBlocks = m4.attack(chain) print("Attacker's balance (after) is", m4.get_balance(chain, m4.publickey.to_string().hex()))
print("Valid: {}\n".format(self.valid)) ## Unit test if __name__ == "__main__": # Initialize MPI comm = MPI.COMM_WORLD size = comm.Get_size() # Returns the number of tasks in comm rank = comm.Get_rank() # Returns the rank of the calling task bchain = Blockchain() Coinbase = {"amount": "100.00", "recipient": "Anders"} Tx = [] bchain.add( Block_v3(block = "1", nonce = "16651", coinbase = Coinbase, tx = Tx) ) Coinbase = {"amount": "100.00", "recipient": "Anders"} Tx = [{"amount": "10.00", "from": "Anders", "recipient": "Sophia"}, {"amount": "20.00", "from": "Anders", "recipient": "Lucas"}, {"amount": "15.00", "from": "Anders", "recipient": "Emily"}, {"amount": "15.00", "from": "Anders", "recipient": "Madison"} ] bchain.add( Block_v3(block = "2", nonce = "215458", coinbase = Coinbase, tx = Tx) ) Coinbase = {"amount": "100.00", "recipient": "Anders"} Tx = [{"amount": "10.00", "from": "Emily", "recipient": "Jackson"}, {"amount": "5.00", "from": "Madison", "recipient": "Jackson"}, {"amount": "20.00", "from": "Lucas", "recipient": "Grace"} ] bchain.add( Block_v3(block = "3", nonce = "146", coinbase = Coinbase, tx = Tx) )
class Consensus: def __init__(self): self.state = StateMachine() self.blockchain = Blockchain() self.transaction_pool = [] self.executed_transactions = [] self.nodes = [] self.lock = Lock() def set_port(self, port): ports = [port] #5000, 5001, 5002] for p in ports: self.nodes.append(f'127.0.0.1:{p}') self.me = f'127.0.0.1:{port}' neighbours = list(self.nodes) neighbours.remove(self.me) self.network = Network(self.me, neighbours) def new_transaction(self, transaction): self.lock.acquire() # drive consensus over the transaction transaction.set_registrer(self.me) self.add_transaction(transaction) self.lock.release() return True def report_transaction(self, transaction): self.lock.acquire() self.add_transaction(transaction) self.lock.release() def add_transaction(self, transaction): if transaction not in self.executed_transactions and transaction not in self.transaction_pool: self.transaction_pool.append(transaction) self.network.broadcast_transaction(transaction) if self.my_turn(): self.sign() def my_turn(self): last_signer = self.blockchain.last_signer() last_index = self.nodes.index(last_signer) if last_signer else -1 next = 0 if last_index + 1 == len(self.nodes) else last_index + 1 return self.nodes[next] == self.me def execute_block(self, block): for transaction in block.transactions: self.state.execute_transaction(transaction) def sign(self): block = Block(self.transaction_pool, self.me, self.blockchain.last_hash()) self.blockchain.add(block) self.transaction_pool = [] self.network.broadcast_block(block) self.execute_block(block) def report_block(self, transactions, signer, previous): self.lock.acquire() if self.blockchain.last_hash() == previous: block = Block(transactions, signer, previous) self.blockchain.add(block) for transaction in transactions: if transaction in self.transaction_pool: self.transaction_pool.remove(transaction) self.executed_transactions.append(transaction) self.network.broadcast_block(block) self.execute_block(block) self.lock.release()
## Unit test if __name__ == "__main__": # Initialize MPI comm = MPI.COMM_WORLD size = comm.Get_size() # Returns the number of tasks in comm rank = comm.Get_rank() # Returns the rank of the calling task P1 = Person("Vincent") P2 = Person("Samir") bchain = Blockchain() Coinbase = {"amount": "100.00", "recipient": P1.pubkey} T = [] bchain.add(Block_v4(block="1", nonce="29082", coinbase=Coinbase, tx=T)) Coinbase = {"amount": "100.00", "recipient": P1.pubkey} T = [Tx("100", P1.public_key, P2.public_key, P1.private_key)] bchain.add(Block_v4(block="2", nonce="16651", coinbase=Coinbase, tx=T)) if rank == 0: bchain.show() bchain.mine() if rank == 0: print("We mine, and get the NEW nonce for every blocks") bchain.show()
class Miner(Node): NORMAL = 0 # normal miner DS_MUTATE = 1 # starts to plant private chain for double spending DS_ATTACK = 2 # publish the withheld blocks to effect double spending def __init__(self, privkey, pubkey, address, listener=MinerListener): print(f"address: {address}") super().__init__(privkey, pubkey, address, listener) self.unconfirmed_transactions = [] # data yet to get into blockchain self.blockchain = Blockchain() self.my_unconfirmed_txn = list( ) # all unconfirmed transactions sent by me self.copy_all_unconfirmed_txn = list() self.stop_mine = threading.Event( ) # a indicator for whether to continue mining #attack self.mode = Miner.NORMAL # self.private_chain = None self.hidden_blocks_num = 0 self.hidden_blocks = list() self.fork_block = None @classmethod def new(cls, address): """Create new Miner instance""" signing_key = ecdsa.SigningKey.generate() verifying_key = signing_key.get_verifying_key() privkey = signing_key pubkey = verifying_key return cls(privkey, pubkey, address) def get_own_balance(self): balance = self.get_balance(stringify_key(self.pubkey)) self.log(f"balance = {balance}") return balance """ inquiry """ def get_transaction_proof(self, tx_json): """Get proof of transaction given transaction json""" # ask the blockchain to search each block to obtain possible proof from merkle tree proof, blk = self.blockchain.get_proof(tx_json) return proof, blk.hash def get_balance(self, identifier): """Get balance given identifier ie. pubkey""" balance = self.blockchain.get_balance() if identifier not in balance: return 0 return balance[identifier] def get_blk_headers(self): """Get headers of blocks of the longest chain""" blk_headers = {} for block in self.blockchain.get_blks(): blk_headers[block.compute_hash()] = block.header return blk_headers """ Transactions """ def make_transaction(self, receiver, amount, comment=""): """Create a new transaction""" if self.get_balance(stringify_key(self.pubkey)) >= amount: tx = Transaction.new( sender=self._keypair[1], receiver=obtain_key_from_string(receiver), amount=amount, comment="", key=self._keypair[0], nonce=self.blockchain.get_nonce(stringify_key(self.pubkey)) + 1 + len(self.my_unconfirmed_txn)) tx_json = tx.serialize() self.log(" Made a new transaction") self.my_unconfirmed_txn.append(tx_json) self.add_transaction(tx) msg = "t" + json.dumps({"tx_json": tx_json}) self.broadcast_message(msg) return tx else: self.log("Not enough balance in your account!") def add_transaction(self, tx): """Add transaction to the pool of unconfirmed transactions and miner's own transaction list""" if not tx.validate(): raise Exception("New transaction failed signature verification.") if not self.tx_resend_check(tx): raise Exception("New transaction failed resending check.") tx_json = tx.serialize() self.unconfirmed_transactions.append(tx_json) self.log( f"{len(self.unconfirmed_transactions)} number of unconfirmed transactions" ) def tx_resend_check(self, tx): nonce = self.blockchain.get_nonce(stringify_key(tx.sender)) self.log(f"most recent nonce = {nonce} vs new nonce = {tx.nonce}") if tx.nonce <= nonce: self.log( "New transaction failed resending check based on most updated chain." ) return False else: self.log( "New transaction passed resending check based on most updated chain." ) return True """ Mining """ def mine(self): if self.peers is None and self.stop_mine.is_set(): return None self.log( f"mining on block height of {self.blockchain.last_node.block.blk_height} ....\n....\n" ) time.sleep(1) tx_collection = self.get_tx_pool() self.log( f"Number of unconfirmed transactions I'm mining on {len(self.get_tx_pool())}" ) if not self.check_balance_and_nonce( tx_collection, self.blockchain.last_node.block.hash): raise Exception("abnormal transactions!") return None new_block = self.create_new_block(tx_collection) proof = self.proof_of_work(new_block, self.stop_mine) if proof is None: return None self.log("prev_hash") self.blockchain.add(new_block, proof) for tx in tx_collection: self.unconfirmed_transactions.remove(tx) self.broadcast_blk(new_block, proof) self.log(" Mined a new block +$$$$$$$$") print(""" |---------| | block | |---------| """) self.blockchain.print() return new_block def get_tx_pool(self): if self.mode == Miner.DS_ATTACK: unconfirm = copy.deepcopy(self.copy_all_unconfirmed_txn) if len(self.my_unconfirmed_txn) != len(self.ds_txns): raise Exception("Double spend transactions wrongly replaced") unconfirm.extend(self.ds_txns) pool = [x for x in unconfirm if x not in self.my_unconfirmed_txn] else: pool = copy.deepcopy(self.unconfirmed_transactions) return pool def get_last_node(self): """returns last block of specified chain""" if self.mode == Miner.DS_ATTACK: if self.hidden_blocks_num == 0: return self.fork_block else: return self.hidden_blocks[self.hidden_blocks_num - 1] else: return self.blockchain.last_node.block def create_new_block(self, tx_collection): last_node = self.get_last_node() new_block = Block(transactions=tx_collection, timestamp=time.time(), previous_hash=last_node.compute_hash(), miner=self.pubkey) return new_block def broadcast_blk(self, new_blk, proof): blk_json = new_blk.serialize() self.broadcast_message("b" + json.dumps({ "blk_json": blk_json, "blk_proof": proof })) self.broadcast_message("h" + json.dumps({ "blk_hash": new_blk.compute_hash(), "blk_header": new_blk.header })) def proof_of_work(self, block, stop_mine): """ Function that tries different values of the nonce to get a hash that satisfies our difficulty criteria. """ start = time.time() computed_hash = block.compute_hash() while not computed_hash < TARGET: if self.stop_mine.is_set(): # self.log("Stop Mining as others have found the block") return None random.seed(time.time()) block.nonce = random.randint(0, 100000000) computed_hash = block.compute_hash() end = time.time() self.log( f"Found proof = {computed_hash} < TARGET in {end - start} seconds") return computed_hash def check_balance_and_nonce(self, transactions, blk_hash): """ Check balance state if transactions were applied. The balance of an account is checked to make sure it is larger than or equal to the spending transaction amount. """ balance = self.blockchain.get_balance(blk_hash) tx_nonce = {} for tx_json in transactions: recv_tx = Transaction.deserialize(tx_json) # Sender must exist so if it doesn't, return false sender = stringify_key(recv_tx.sender) receiver = stringify_key(recv_tx.receiver) if sender not in balance: return False # checking if nonce run into conflict with previous nonce if sender not in tx_nonce: tx_nonce[sender] = [] if recv_tx.nonce <= self.blockchain.get_nonce(sender, blk_hash): self.log( "Detect conflicting nonce from transactions in chain!") return False elif recv_tx.nonce in tx_nonce[sender]: self.log( "Detect conflicting nonce from transactions in collection") return False else: tx_nonce[sender].append(recv_tx.nonce) # Create new account for receiver if it doesn't exist if receiver not in balance: balance[receiver] = 0 balance[sender] -= recv_tx.amount balance[receiver] += recv_tx.amount # Negative balance, return false if balance[sender] < 0 or balance[receiver] < 0: print("Negative balance can exist!") return False return True """DS Miner functions""" def get_longest_len(self, chain): """Get length of longest chain""" if chain == "public": return self.blockchain.last_node.block.blk_height else: # return self.private_chain.last_node.block.blk_height return self.fork_block.blk_height + self.hidden_blocks_num def setup_ds_attack(self): """Change miner to DS mode and take note of fork location""" self.mode = Miner.DS_MUTATE self.fork_block = self.get_last_node() # self.private_chain = copy.deepcopy(self.blockchain) self.copy_all_unconfirmed_txn = copy.deepcopy( self.unconfirmed_transactions) self.ds_txns = self.create_ds_txn() self.log("Ready for DS attack") def create_ds_txn(self): """replace DS miner's own unconfirmed transactions with new senders""" ds_txns = list() if self.mode != Miner.DS_MUTATE: raise Exception( "Honest miners cannot create double spend transactions") for tx_json in self.my_unconfirmed_txn: tx = Transaction.deserialize(tx_json) if tx.sender != self._keypair[1]: raise Exception( "Sender is double spending on the wrong transaction") replacement_tx = Transaction.new(sender=self._keypair[1], receiver=self._keypair[1], amount=tx.amount, comment=tx.comment, key=self._keypair[0], nonce=tx.nonce) replacement_tx_json = replacement_tx.serialize() ds_txns.append(replacement_tx_json) return ds_txns def ds_mine(self): if self.mode == Miner.NORMAL: raise Exception("Normal Miner cannot double spend") else: self.mode = Miner.DS_ATTACK self.log( f"mining on block height of {self.blockchain.last_node.block.blk_height} ....\n....\n" ) tx_collection = self.get_tx_pool() # if not self.check_balance_and_nonce(tx_collection): # raise Exception("abnormal transactions!") new_block = self.create_new_block(tx_collection) proof = self.proof_of_work(new_block, self.stop_mine) if proof is None: return None # self.private_chain.add_block(new_block, proof) self.hidden_blocks.append(new_block) self.hidden_blocks_num += 1 for tx in tx_collection: if tx in self.copy_all_unconfirmed_txn: self.copy_all_unconfirmed_txn.remove(tx) self.log(" Mined a new block +$$$$$$$$") print(""" |---------| | dsblock | |---------| """) self.blockchain.print() # if hidden chain is longer than public chain, no longer need to mine, just publish pub = self.get_longest_len("public") priv = self.get_longest_len("hidden") self.log( f"Checking if length of private chain {priv} > public chain {pub}") if self.get_longest_len("public") < self.get_longest_len("hidden"): self.ds_broadcast() return return new_block def ds_broadcast(self): if self.mode != Miner.DS_ATTACK: raise Exception("Miner is not in attacking mode") self.log("Starting DS chain Broadcast...") blocks = self.hidden_blocks count = 1 for blk in blocks: self.log( f"Broadcasting block {count} out of {self.hidden_blocks_num}") self.blockchain.add_block(blk, blk.compute_hash()) self.broadcast_blk(blk, blk.compute_hash()) count += 1 time.sleep(2) self.end_ds_attack() def end_ds_attack(self): self.log("Ended DS attack...") self.hidden_blocks_num = 0 self.hidden_blocks = list() self.fork_block = None self.mode = Miner.NORMAL self.copy_all_unconfirmed_txn = list()
# -*- coding: utf-8 -*- """ Created on Fri Mar 26 09:47:11 2021 @author: Lenovo """ import json import random from uuid import uuid4 from blockchain import Blockchain, Block from transaction import Transaction if __name__ == '__main__': chain = Blockchain() for i in range(3): block = Block() for j in range(10): transaction = Transaction(sender=str(uuid4()), receiver=str(uuid4()), amount=random.randint(1, 1000000) ) block.add(transaction) chain.add(block) #if __name__ == '__main__': # print(json.dumps(json.loads(str(chain)), indent=4, sort_keys=True)) # print(chain.validate()) #测试更改 if __name__ == '__main__': chain.blocks[0].items[0].receiver = str(uuid4()) print(json.dumps(json.loads(str(chain)), indent=4, sort_keys=True)) print(chain.validate()) #