def ChainAdvancementTest(rpc: RPC) -> None: #Blockchain. blockchain: Blockchain = Blockchain( b"MEROS_DEVELOPER_NETWORK", 60, int( "FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 16)) #Blocks. file: IO[Any] = open("python_tests/Vectors/Merit/BlankBlocks.json", "r") blocks: List[Dict[str, Any]] = json.loads(file.read()) file.close() #Publish Blocks. for jsonBlock in blocks: #Parse the Block. block: Block = Block.fromJSON(jsonBlock) #Add it locally. blockchain.add(block) #Publish it. rpc.call("merit", "publishBlock", [block.serialize().hex()]) #Verify the difficulty. if int(rpc.call("merit", "getDifficulty"), 16) != blockchain.difficulty: raise TestError("Difficulty doesn't match.") #Verify the Blockchain. verifyBlockchain(rpc, blockchain)
def verifyBlockchain(rpc: RPC, blockchain: Blockchain) -> None: #Verify the height. if rpc.call("merit", "getHeight") != len(blockchain.blocks): raise TestError("Height doesn't match.") #Verify the difficulty. if blockchain.difficulty != int(rpc.call("merit", "getDifficulty"), 16): raise TestError("Difficulty doesn't match.") #Verify the blocks. for block in blockchain.blocks: if rpc.call("merit", "getBlock", [block.header.nonce]) != block.toJSON(): raise TestError("Block doesn't match.")
def verifyConsensus(rpc: RPC, consensus: Consensus) -> None: for pubKey in consensus.holders: for e in range(len(consensus.holders[pubKey])): if rpc.call( "consensus", "getElement", [pubKey.hex(), e]) != consensus.holders[pubKey][e].toJSON(): raise TestError("Element doesn't match.")
def verifyMeritRemoval(rpc: RPC, height: int, merit: int, removal: MeritRemoval, pending: bool) -> None: #Verify the Merit Holder height. if rpc.call("consensus", "getHeight", [removal.holder.hex()]) != height: raise TestError("Merit Holder height doesn't match.") #Get the MeritRemoval. mrJSON: Dict[str, Any] = rpc.call("consensus", "getElement", [removal.holder.hex(), removal.nonce]) #Verify the nonce. if pending: if mrJSON["nonce"] != 0: raise TestError("MeritRemoval nonce is invalid.") mrJSON["nonce"] = removal.nonce #Verify the MeritRemoval. if mrJSON != removal.toJSON(): raise TestError("Merit Removal doesn't match.") #Verify the Total Merit. if rpc.call("merit", "getTotalMerit") != merit if pending else 0: raise TestError("Total Merit doesn't match.") #Verify the Live Merit. if rpc.call("merit", "getLiveMerit", [removal.holder.hex()]) != merit if pending else 0: raise TestError("Live Merit doesn't match.") #Verify the Merit Holder's Merit. if rpc.call("merit", "getMerit", [removal.holder.hex()]) != { "live": True, "malicious": pending, "merit": merit if pending else 0 }: raise TestError("Merit Holder's Merit doesn't match.")
def MRPALiveTest(rpc: RPC) -> None: file: IO[Any] = open( "python_tests/Vectors/Consensus/MeritRemoval/PendingActions.json", "r") vectors: Dict[str, Any] = json.loads(file.read()) #Datas. datas: List[Data] = [] for data in vectors["datas"]: datas.append(Data.fromJSON(data)) #SignedVerifications. verifs: List[SignedVerification] = [] for verif in vectors["verifications"]: verifs.append(SignedVerification.fromJSON(verif)) #Removal. removal: SignedMeritRemoval = SignedMeritRemoval.fromJSON( vectors["removal"]) #Consensus. consensus: Consensus = Consensus( bytes.fromhex( "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ), bytes.fromhex( "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" ), ) consensus.add(verifs[0]) consensus.add(verifs[1]) consensus.add(verifs[2]) consensus.add(removal) #Blockchain. blockchain: Blockchain = Blockchain.fromJSON( b"MEROS_DEVELOPER_NETWORK", 60, int( "FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 16), vectors["blockchain"]) file.close() #Handshake with the node. rpc.meros.connect(254, 254, len(blockchain.blocks) - 2) hash: bytes = bytes() msg: bytes = bytes() height: int = 0 while True: msg = rpc.meros.recv() if MessageType(msg[0]) == MessageType.Syncing: rpc.meros.acknowledgeSyncing() elif MessageType(msg[0]) == MessageType.GetBlockHash: height = int.from_bytes(msg[1:5], byteorder="big") if height == 0: rpc.meros.blockHash(blockchain.blocks[1].header.hash) else: if height >= len(blockchain.blocks): raise TestError( "Meros asked for a Block Hash we do not have.") rpc.meros.blockHash(blockchain.blocks[height].header.hash) elif MessageType(msg[0]) == MessageType.BlockHeaderRequest: hash = msg[1:49] for block in blockchain.blocks: if block.header.hash == hash: rpc.meros.blockHeader(block.header) break if block.header.hash == blockchain.last(): raise TestError( "Meros asked for a Block Header we do not have.") elif MessageType(msg[0]) == MessageType.BlockBodyRequest: hash = msg[1:49] for block in blockchain.blocks: if block.header.hash == hash: rpc.meros.blockBody(block.body) break if block.header.hash == blockchain.last(): raise TestError( "Meros asked for a Block Body we do not have.") elif MessageType(msg[0]) == MessageType.SyncingOver: break else: raise TestError("Unexpected message sent: " + msg.hex().upper()) #Send the Datas. for data in datas: if rpc.meros.transaction(data) != rpc.meros.recv(): raise TestError("Unexpected message sent.") #Send the Verifications. for verif in verifs: if rpc.meros.signedElement(verif) != rpc.meros.recv(): raise TestError("Unexpected message sent.") #Verify every Data has 100 Merit. for data in datas: if rpc.call("transactions", "getMerit", [data.hash.hex()]) != { "merit": 100 }: raise TestError( "Meros didn't verify Transactions with received Verifications." ) #Send and verify the MeritRemoval. if rpc.meros.signedElement(removal) != rpc.meros.recv(): raise TestError("Meros didn't send us the Merit Removal.") verifyMeritRemoval(rpc, 1, 100, removal, True) #Verify every Data has 100 Merit. for data in datas: if rpc.call("transactions", "getMerit", [data.hash.hex()]) != { "merit": 0 }: raise TestError( "Meros didn't revert pending actions of a malicious MeritHolder." ) #Send the next Block. rpc.meros.blockHeader(blockchain.blocks[-2].header) while True: msg = rpc.meros.recv() if MessageType(msg[0]) == MessageType.Syncing: rpc.meros.acknowledgeSyncing() elif MessageType(msg[0]) == MessageType.GetBlockHash: height = int.from_bytes(msg[1:5], byteorder="big") if height == 0: rpc.meros.blockHash(blockchain.last()) else: if height >= len(blockchain.blocks): raise TestError( "Meros asked for a Block Hash we do not have.") rpc.meros.blockHash(blockchain.blocks[height].header.hash) elif MessageType(msg[0]) == MessageType.BlockHeaderRequest: hash = msg[1:49] for block in blockchain.blocks: if block.header.hash == hash: rpc.meros.blockHeader(block.header) break if block.header.hash == blockchain.last(): raise TestError( "Meros asked for a Block Header we do not have.") elif MessageType(msg[0]) == MessageType.BlockBodyRequest: hash = msg[1:49] for block in blockchain.blocks: if block.header.hash == hash: rpc.meros.blockBody(block.body) break if block.header.hash == blockchain.last(): raise TestError( "Meros asked for a Block Body we do not have.") elif MessageType(msg[0]) == MessageType.SyncingOver: pass elif MessageType(msg[0]) == MessageType.BlockHeader: break else: raise TestError("Unexpected message sent: " + msg.hex().upper()) #Update the MeritRemoval's nonce. removal.nonce = 3 #Verify the Datas have the Merit they should. for d in range(len(datas)): if rpc.call("transactions", "getMerit", [datas[d].hash.hex()]) != { "merit": 100 if d < 3 else 0 }: raise TestError( "Meros didn't apply reverted pending actions of a malicious MeritHolder." ) #Verify the MeritRemoval is now accessible with a nonce of 3. verifyMeritRemoval(rpc, 4, 200, removal, True) #Archive the MeritRemoval. rpc.meros.blockHeader(blockchain.blocks[-1].header) while True: msg = rpc.meros.recv() if MessageType(msg[0]) == MessageType.Syncing: rpc.meros.acknowledgeSyncing() elif MessageType(msg[0]) == MessageType.GetBlockHash: height = int.from_bytes(msg[1:5], byteorder="big") if height == 0: rpc.meros.blockHash(blockchain.last()) else: if height >= len(blockchain.blocks): raise TestError( "Meros asked for a Block Hash we do not have.") rpc.meros.blockHash(blockchain.blocks[height].header.hash) elif MessageType(msg[0]) == MessageType.BlockHeaderRequest: hash = msg[1:49] for block in blockchain.blocks: if block.header.hash == hash: rpc.meros.blockHeader(block.header) break if block.header.hash == blockchain.last(): raise TestError( "Meros asked for a Block Header we do not have.") elif MessageType(msg[0]) == MessageType.BlockBodyRequest: hash = msg[1:49] for block in blockchain.blocks: if block.header.hash == hash: rpc.meros.blockBody(block.body) break if block.header.hash == blockchain.last(): raise TestError( "Meros asked for a Block Body we do not have.") elif MessageType(msg[0]) == MessageType.SyncingOver: break else: raise TestError("Unexpected message sent: " + msg.hex().upper()) #Verify the Blockchain. verifyBlockchain(rpc, blockchain) #Verify the Consensus. verifyConsensus(rpc, consensus) #Verify the MeritRemoval again. verifyMeritRemoval(rpc, 4, 200, removal, False)
def VUnknown( rpc: RPC ) -> None: file: IO[Any] = open("python_tests/Vectors/Consensus/Verification/Parsable.json", "r") vectors: Dict[str, Any] = json.loads(file.read()) #SignedVerification. sv: SignedVerification = SignedVerification.fromJSON(vectors["verification"]) #Blockchain. blockchain: Blockchain = Blockchain.fromJSON( b"MEROS_DEVELOPER_NETWORK", 60, int("FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 16), vectors["blockchain"] ) file.close() #Handshake with the node. rpc.meros.connect( 254, 254, len(blockchain.blocks) ) sentLast: bool = False hash: bytes = bytes() while True: msg: bytes = rpc.meros.recv() if MessageType(msg[0]) == MessageType.Syncing: rpc.meros.acknowledgeSyncing() elif MessageType(msg[0]) == MessageType.GetBlockHash: height: int = int.from_bytes(msg[1 : 5], byteorder = "big") if height == 0: rpc.meros.blockHash(blockchain.last()) else: if height >= len(blockchain.blocks): raise TestError("Meros asked for a Block Hash we do not have.") rpc.meros.blockHash(blockchain.blocks[height].header.hash) elif MessageType(msg[0]) == MessageType.BlockHeaderRequest: hash = msg[1 : 49] for block in blockchain.blocks: if block.header.hash == hash: rpc.meros.blockHeader(block.header) break if block.header.hash == blockchain.last(): raise TestError("Meros asked for a Block Header we do not have.") elif MessageType(msg[0]) == MessageType.BlockBodyRequest: hash = msg[1 : 49] for block in blockchain.blocks: if block.header.hash == hash: rpc.meros.blockBody(block.body) break if block.header.hash == blockchain.last(): raise TestError("Meros asked for a Block Body we do not have.") elif MessageType(msg[0]) == MessageType.ElementRequest: rpc.meros.element(sv) elif MessageType(msg[0]) == MessageType.TransactionRequest: sentLast = True rpc.meros.dataMissing() elif MessageType(msg[0]) == MessageType.SyncingOver: if sentLast: break else: raise TestError("Unexpected message sent: " + msg.hex().upper()) #Verify the Verification and Block were not added. if rpc.call("consensus", "getHeight", [sv.holder.hex()]) != 0: raise TestError("Meros added an unknown Verification.") if rpc.call("merit", "getHeight") != 2: raise TestError("Meros added a block with an unknown Verification.")
pass #Run every test. for test in tests: if len(testsToRun) == 0: break if test.__name__ not in testsToRun: continue testsToRun.remove(test.__name__) print("Running " + test.__name__ + ".") meros: Meros = Meros(test.__name__, port, port + 1) sleep(2) rpc: RPC = RPC(meros) try: test(rpc) ress.append("\033[0;32m" + test.__name__ + " succeeded.") except EmptyError as e: ress.append("\033[0;33m" + test.__name__ + " is empty.") continue except NodeError as e: ress.append("\033[5;31m" + test.__name__ + " caused the node to crash!\033[0;31m") except TestError as e: ress.append("\033[0;31m" + test.__name__ + " failed: " + str(e)) continue except Exception as e: ress.append("\r\n") ress.append("\033[0;31m" + test.__name__ + " is invalid.")
def verifyTransaction(rpc: RPC, tx: Transaction) -> None: if rpc.call("transactions", "getTransaction", [tx.hash.hex()]) != tx.toJSON(): raise TestError("Transaction doesn't match.")