def mineBlock(rpc: RPC, nick: int = 0) -> None: privKey: PrivateKey = PrivateKey(nick) template: Dict[str, Any] = rpc.call( "merit", "getBlockTemplate", {"miner": privKey.toPublicKey().serialize().hex()}) header: bytes = bytes.fromhex(template["header"])[:-4] header += (rpc.call( "merit", "getBlock", {"block": rpc.call("merit", "getHeight") - 1})["header"]["time"] + 1200).to_bytes(4, "little") proof: int = -1 tempHash: bytes = bytes() signature: bytes = bytes() while ((proof == -1) or ((int.from_bytes(tempHash, "little") * template["difficulty"]) > int.from_bytes(bytes.fromhex("FF" * 32), "little"))): proof += 1 tempHash = RandomX(header + proof.to_bytes(4, "little")) signature = privKey.sign(tempHash).serialize() tempHash = RandomX(tempHash + signature) rpc.call( "merit", "publishBlock", { "id": template["id"], "header": header.hex() + proof.to_bytes(4, "little").hex() + signature.hex() }) if rpc.meros.live.recv() != (MessageType.BlockHeader.toByte() + header + proof.to_bytes(4, "little") + signature): raise TestError("Meros didn't broadcast back the BlockHeader.")
def verifyRecreation() -> None: template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate", [key.toPublicKey().serialize().hex()]) if bytes.fromhex( template["header"])[36:68] != BlockHeader.createContents( [VerificationPacket(data.hash, [1])]): raise TestError( "New Block template doesn't have a properly recreated packet.") #Mining it further verifies the internal state. header: bytes = bytes.fromhex(template["header"]) proof: int = 0 sig: bytes while True: initial: bytes = RandomX(header + proof.to_bytes(4, byteorder="little")) sig = key.sign(initial).serialize() final: bytes = RandomX(initial + sig) if (int.from_bytes(final, "little") * template["difficulty"]) < int.from_bytes( bytes.fromhex("FF" * 32), "little"): break proof += 1 rpc.call("merit", "publishBlock", [ template["id"], (header + proof.to_bytes(4, byteorder="little") + sig).hex() ]) raise SuccessError( "Stop Liver from trying to verify the vector chain which doesn't have this Block." )
def mine(self, privKey: PrivateKey, difficulty: int) -> None: self.proof = -1 while ((self.proof == -1) or ((int.from_bytes(self.hash, "little") * difficulty) > int.from_bytes(bytes.fromhex("FF" * 32), "little"))): self.proof += 1 self.hash = RandomX(self.serializeHash()) self.signature = privKey.sign(self.hash).serialize() self.hash = RandomX(self.hash + self.signature)
def RandomXTest() -> None: #Generate 100 RandomX keys, and create 10 hashes with each. #As this is single threaded, it's guaranteed to be safe. keys: List[bytes] = [] hashed: List[List[bytes]] = [] hashes: List[List[bytes]] = [] for _ in range(100): keys.append(bytes(getrandbits(8) for _ in range(32))) setRandomXKey(keys[-1]) hashed.append([]) hashes.append([]) for _ in range(10): hashed[-1].append( bytes(getrandbits(8) for _ in range(getrandbits(8)))) hashes[-1].append(RandomX(hashed[-1][-1])) def rxThread(t: int) -> None: for k in range(t * 25, (t + 1) * 25): setRandomXKey(keys[k]) for h in range(len(hashed[k])): if RandomX(hashed[k][h]) != hashes[k][h]: raise TestError( "Threaded RandomX returned a different result than the single-threaded version." ) #Now, spawn 4 threads and re-iterate over every hash. threads: List[Thread] = [] for t in range(4): threads.append(Thread(None, rxThread, "RX-" + str(t), [t])) threads[-1].start() for thread in threads: thread.join()
def rxThread(t: int) -> None: for k in range(t * 25, (t + 1) * 25): setRandomXKey(keys[k]) for h in range(len(hashed[k])): if RandomX(hashed[k][h]) != hashes[k][h]: raise TestError( "Threaded RandomX returned a different result than the single-threaded version." )
def test() -> None: #Send to the first address from outside the Wallet. First address is now funded. sendHash: bytes = createSend( rpc, claims[0], decodeAddress(rpc.call("personal", "getAddress"))) #Send to the second address with all of the funds. Second address is now funded. #Tests send's minimal case (single input, no change). nextAddr: str = rpc.call("personal", "getAddress") sends: List[str] = [ rpc.call( "personal", "send", { "outputs": [{ "address": nextAddr, "amount": str(claims[0].amount) }] }) ] checkSend( rpc, sends[-1], { "inputs": [{ "hash": sendHash.hex().upper(), "nonce": 0 }], "outputs": [{ "key": decodeAddress(nextAddr).hex().upper(), "amount": str(claims[0].amount) }] }) verify(rpc, bytes.fromhex(sends[-1])) #Send to the third address with some of the funds. Third and change addresses are now funded. #Tests send's capability to create a change output. mnemonic: str = rpc.call("personal", "getMnemonic") nextAddr = rpc.call("personal", "getAddress") sends.append( rpc.call( "personal", "send", { "outputs": [{ "address": nextAddr, "amount": str(claims[0].amount - 1) }] })) checkSend( rpc, sends[-1], { "inputs": [{ "hash": sends[-2], "nonce": 0 }], "outputs": [{ "key": decodeAddress(nextAddr).hex().upper(), "amount": str(claims[0].amount - 1) }, { "key": getChangePublicKey(mnemonic, "", 0).hex().upper(), "amount": "1" }] }) verify(rpc, bytes.fromhex(sends[-1])) #Send all funds out of Wallet. #Tests MuSig signing and change UTXO detection. privKey: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32) pubKey: bytes = privKey.get_verifying_key() sends.append( rpc.call( "personal", "send", { "outputs": [{ "address": bech32_encode("mr", convertbits(bytes([0]) + pubKey, 8, 5)), "amount": str(claims[0].amount) }] })) checkSend( rpc, sends[-1], { "inputs": [{ "hash": sends[-2], "nonce": 0 }, { "hash": sends[-2], "nonce": 1 }], "outputs": [{ "key": pubKey.hex().upper(), "amount": str(claims[0].amount) }] }) verify(rpc, bytes.fromhex(sends[-1])) #Clear Wallet. Set a password this time around to make sure the password is properly carried. #Send two instances of funds to the first address. rpc.call("personal", "setWallet", {"password": "******"}) mnemonic = rpc.call("personal", "getMnemonic") nodeKey: bytes = decodeAddress(rpc.call("personal", "getAddress")) send: Send = Send([(bytes.fromhex(sends[-1]), 0)], [(nodeKey, claims[0].amount // 2), (nodeKey, claims[0].amount // 2)]) send.sign(Ristretto.SigningKey(b'\0' * 32)) send.beat(SpamFilter(3)) if rpc.meros.liveTransaction(send) != rpc.meros.live.recv(): raise TestError("Meros didn't send back a Send.") verify(rpc, send.hash) sends = [send.hash.hex().upper()] #Send to self. #Tests send's capability to handle multiple UTXOs per key/lack of aggregation when all keys are the same/multiple output Sends. nextAddr = rpc.call("personal", "getAddress") changeKey: bytes = getChangePublicKey(mnemonic, "test", 0) sends.append( rpc.call( "personal", "send", { "outputs": [{ "address": nextAddr, "amount": str(claims[0].amount - 1) }], "password": "******" })) checkSend( rpc, sends[-1], { "inputs": [{ "hash": sends[-2], "nonce": 0 }, { "hash": sends[-2], "nonce": 1 }], "outputs": [{ "key": decodeAddress(nextAddr).hex().upper(), "amount": str(claims[0].amount - 1) }, { "key": changeKey.hex().upper(), "amount": "1" }] }) verify(rpc, bytes.fromhex(sends[-1])) #Externally send to the second/change address. #Enables entering multiple instances of each key into MuSig, which is significant as we originally only used the unique keys. sends.append( createSend(rpc, claims[1], decodeAddress(nextAddr)).hex().upper()) sends.append(createSend(rpc, claims[2], changeKey).hex().upper()) #Check personal_getUTXOs. utxos: List[Dict[str, Any]] = [{ "hash": sends[-3], "nonce": 0, "address": nextAddr }, { "hash": sends[-3], "nonce": 1, "address": bech32_encode("mr", convertbits(bytes([0]) + changeKey, 8, 5)) }, { "hash": sends[-2], "nonce": 0, "address": nextAddr }, { "hash": sends[-1], "nonce": 0, "address": bech32_encode("mr", convertbits(bytes([0]) + changeKey, 8, 5)) }] if sortUTXOs(rpc.call("personal", "getUTXOs")) != sortUTXOs(utxos): raise TestError("personal_getUTXOs was incorrect.") for utxo in utxos: del utxo["address"] #Send to any address with all funds minus one. #Test MuSig signing, multiple inputs per key on account chains, change output creation to the next change key... sends.append( rpc.call( "personal", "send", { "outputs": [{ "address": nextAddr, "amount": str(claims[0].amount + claims[1].amount + claims[2].amount - 1) }], "password": "******" })) checkSend( rpc, sends[-1], { "inputs": utxos, "outputs": [{ "key": decodeAddress(nextAddr).hex().upper(), "amount": str(claims[0].amount + claims[1].amount + claims[2].amount - 1) }, { "key": getChangePublicKey(mnemonic, "test", 1).hex().upper(), "amount": "1" }] }) verify(rpc, bytes.fromhex(sends[-1])) #Mine a Block so we can reboot the node without losing data. blsPrivKey: PrivateKey = PrivateKey( bytes.fromhex(rpc.call("personal", "getMeritHolderKey"))) for _ in range(6): template: Dict[str, Any] = rpc.call( "merit", "getBlockTemplate", {"miner": blsPrivKey.toPublicKey().serialize().hex()}) proof: int = -1 tempHash: bytes = bytes() tempSignature: bytes = bytes() while ((proof == -1) or ( (int.from_bytes(tempHash, "little") * template["difficulty"]) > int.from_bytes(bytes.fromhex("FF" * 32), "little"))): proof += 1 tempHash = RandomX( bytes.fromhex(template["header"]) + proof.to_bytes(4, "little")) tempSignature = blsPrivKey.sign(tempHash).serialize() tempHash = RandomX(tempHash + tempSignature) rpc.call( "merit", "publishBlock", { "id": template["id"], "header": template["header"] + proof.to_bytes(4, "little").hex() + tempSignature.hex() }) #Reboot the node and verify it still tracks the same change address. #Also reload the Wallet and verify it still tracks the same change address. #Really should be part of address discovery; we just have the opportunity right here. #Due to the timing of how the codebase was developed, and a personal frustration for how long this has taken... rpc.quit() sleep(3) rpc.meros = Meros(rpc.meros.db, rpc.meros.tcp, rpc.meros.rpc) if rpc.call("personal", "getTransactionTemplate", {"outputs": [{ "address": nextAddr, "amount": "1" }]})["outputs"][1]["key"] != getChangePublicKey( mnemonic, "test", 2).hex().upper(): raise TestError( "Rebooting the node caused the WalletDB to stop tracking the next change address." ) rpc.call("personal", "setAccount", rpc.call("personal", "getAccount")) if rpc.call("personal", "getTransactionTemplate", {"outputs": [{ "address": nextAddr, "amount": "1" }]})["outputs"][1]["key"] != getChangePublicKey( mnemonic, "test", 2).hex().upper(): raise TestError( "Reloading the Wallet caused the WalletDB to stop tracking the next change address." ) raise SuccessError()
def getBlockTemplateTest(rpc: RPC) -> None: edPrivKey: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32) edPubKey: bytes = edPrivKey.get_verifying_key() blockchain: Blockchain = Blockchain() #Get multiple templates to verify they share an ID if they're requested within the same second. templates: List[Dict[str, Any]] = [] startTime: float = nextSecond() for k in range(5): templates.append( rpc.call("merit", "getBlockTemplate", {"miner": getMiner(k)}, False)) if int(startTime) != int(time.time()): #Testing https://github.com/MerosCrypto/Meros/issues/278 has a much more forgiving timer of < 1 second each. #That said, this test was written on the fair assumption of all the above taking place in a single second. raise Exception( "getBlockTemplate is incredibly slow, to the point an empty Block template takes > 0.2 seconds to grab, invalidating this test." ) for k, template in zip(range(5), templates): if template["id"] != int(startTime): raise TestError("Template ID isn't the time.") #Also check general accuracy. if bytes.fromhex(template["key"]) != blockchain.genesis: raise TestError("Template has the wrong RandomX key.") bytesHeader: bytes = bytes.fromhex(template["header"]) serializedHeader: bytes = BlockHeader( 0, blockchain.blocks[0].header.hash, bytes(32), 0, bytes(4), bytes(32), PrivateKey(k).toPublicKey().serialize(), int(startTime)).serialize()[:-52] #Skip over the randomized sketch salt. if (bytesHeader[:72] + bytesHeader[76:]) != (serializedHeader[:72] + serializedHeader[76:]): raise TestError("Template has an invalid header.") #Difficulty modified as this is a new miner. if template["difficulty"] != (blockchain.difficulty() * 11 // 10): raise TestError("Template's difficulty is wrong.") currTime: int = int(nextSecond()) template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate", {"miner": getMiner(0)}, False) if template["id"] != currTime: raise TestError("Template ID wasn't advanced with the time.") #Override the ID to enable easy comparison against a historical template. template["id"] = int(startTime) if int.from_bytes(bytes.fromhex(template["header"])[-4:], "little") != currTime: raise TestError("The header has the wrong time.") template["header"] = ( bytes.fromhex(template["header"])[:72] + #Use the header we'll compare to's salt. bytes.fromhex(templates[0]["header"])[72:76] + bytes.fromhex(template["header"])[76:-4] + #Also use its time. int(startTime).to_bytes(4, "little")).hex().upper() if template != templates[0]: raise TestError( "Template, minus the time difference, doesn't match the originally provided template." ) #Test that the templates are deleted whenever a new Block appears. #This is done by checking the error given when we use an old template. with open("e2e/Vectors/Merit/BlankBlocks.json", "r") as file: block: Block = Block.fromJSON(json.loads(file.read())[0]) blockchain.add(block) rpc.meros.liveConnect(blockchain.blocks[0].header.hash) rpc.meros.syncConnect(blockchain.blocks[0].header.hash) rpc.meros.liveBlockHeader(block.header) rpc.meros.rawBlockBody(block, 0) time.sleep(1) #Sanity check. if rpc.call("merit", "getHeight", auth=False) != 2: raise Exception("Didn't successfully send Meros the Block.") #Get a new template so Meros realizes the template situation has changed. rpc.call("merit", "getBlockTemplate", {"miner": getMiner(0)}, False) try: rpc.call("merit", "publishBlock", { "id": int(startTime), "header": "" }, False) raise Exception("") except Exception as e: if str(e) != "-2 Invalid ID.": raise TestError("Meros didn't delete old template IDs.") #Test VerificationPacket inclusion. data: Data = Data(bytes(32), edPubKey) data.sign(edPrivKey) data.beat(SpamFilter(5)) verif: SignedVerification = SignedVerification(data.hash) verif.sign(0, PrivateKey(0)) packet = VerificationPacket(data.hash, [0]) rpc.meros.liveTransaction(data) rpc.meros.signedElement(verif) time.sleep(1) if bytes.fromhex( rpc.call("merit", "getBlockTemplate", {"miner": getMiner(0)}, False)["header"])[36:68] != BlockHeader.createContents( [packet]): raise TestError( "Meros didn't include the Verification in its new template.") #Test Element inclusion. sendDiff: SignedSendDifficulty = SignedSendDifficulty(0, 0) sendDiff.sign(0, PrivateKey(0)) rpc.meros.signedElement(sendDiff) time.sleep(1) if bytes.fromhex( rpc.call("merit", "getBlockTemplate", {"miner": getMiner(0)}, False)["header"])[36:68] != BlockHeader.createContents( [packet], [sendDiff]): raise TestError( "Meros didn't include the Element in its new template.") #The 88 test checks for the non-inclusion of Verifications with unmentioned predecessors. #Test for non-inclusion of Elements with unmentioned predecessors. sendDiffChild: SignedSendDifficulty = SignedSendDifficulty(0, 2) sendDiffChild.sign(0, PrivateKey(0)) rpc.meros.signedElement(sendDiffChild) time.sleep(1) if bytes.fromhex( rpc.call("merit", "getBlockTemplate", {"miner": getMiner(0)}, False)["header"])[36:68] != BlockHeader.createContents( [packet], [sendDiff]): raise TestError( "Meros did include an Element with an unmentioned parent in its new template." ) #If we send a block with a time in the future, yet within FTL (of course), make sure Meros can still generate a template. #Naively using the current time will create a negative clock, which isn't allowed. #Start by closing the sockets to give us time to work. rpc.meros.live.connection.close() rpc.meros.sync.connection.close() #Sleep to reset the connection state. time.sleep(35) #Create and mine the Block. header: BlockHeader = BlockHeader( 0, blockchain.blocks[-1].header.hash, bytes(32), 0, bytes(4), bytes(32), PrivateKey(0).toPublicKey().serialize(), 0, ) miningStart: int = 0 #If this block takes longer than 10 seconds to mine, try another. #Low future time (20 seconds) is chosen due to feasibility + supporting lowering the FTL in the future. while time.time() > miningStart + 10: miningStart = int(time.time()) header = BlockHeader( 0, blockchain.blocks[-1].header.hash, bytes(32), 0, bytes(4), bytes(32), #Mod by something is due to a 2-byte limit (IIRC -- Kayaba). #100 is just clean. +11 ensures an offset from the above, which really shouldn't be necessary. #If we did need one, +1 should work, as we only ever work with PrivateKey(0) on the blockchain. PrivateKey((miningStart % 100) + 10).toPublicKey().serialize(), int(time.time()) + 20, ) header.mine(PrivateKey((miningStart % 100) + 10), blockchain.difficulty() * 11 // 10) blockchain.add(Block(header, BlockBody())) #Send it and verify it. rpc.meros.liveConnect(blockchain.blocks[0].header.hash) rpc.meros.syncConnect(blockchain.blocks[0].header.hash) rpc.meros.liveBlockHeader(header) rpc.meros.rawBlockBody(Block(header, BlockBody()), 0) rpc.meros.live.connection.close() rpc.meros.sync.connection.close() time.sleep(1) #Ensure a stable template ID. currTime = int(nextSecond()) template = rpc.call("merit", "getBlockTemplate", {"miner": getMiner(0)}, False) if template["id"] != currTime: raise TestError( "Template ID isn't the time when the previous Block is in the future." ) if int.from_bytes(bytes.fromhex(template["header"])[-4:], "little") != (header.time + 1): raise TestError( "Meros didn't handle generating a template off a Block in the future properly." ) #Verify a Block with three Elements from a holder, where two form a Merit Removal. #Only the two which cause a MeritRemoval should be included. #Mine a Block to a new miner and clear the current template with it (might as well). #Also allows us to test template clearing. template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate", {"miner": getMiner(1)}, False) #Mine the Block. proof: int = -1 tempHash: bytes = bytes() tempSignature: bytes = bytes() while ((proof == -1) or ((int.from_bytes(tempHash, "little") * (blockchain.difficulty() * 11 // 10)) > int.from_bytes( bytes.fromhex("FF" * 32), "little"))): proof += 1 tempHash = RandomX( bytes.fromhex(template["header"]) + proof.to_bytes(4, "little")) tempSignature = PrivateKey(1).sign(tempHash).serialize() tempHash = RandomX(tempHash + tempSignature) rpc.call( "merit", "publishBlock", { "id": template["id"], "header": template["header"] + proof.to_bytes(4, "little").hex() + tempSignature.hex() }) time.sleep(1) #Verify the template was cleared. currTime = int(nextSecond()) bytesHeader: bytes = bytes.fromhex( rpc.call("merit", "getBlockTemplate", {"miner": getMiner(0)}, False)["header"]) serializedHeader: bytes = BlockHeader( 0, tempHash, bytes(32), 0, bytes(4), bytes(32), 0, #Ensures that the previous time manipulation doesn't come back to haunt us. max(currTime, blockchain.blocks[-1].header.time + 1)).serialize()[:-52] #Skip over the randomized sketch salt and time (which we don't currently have easy access to). if (bytesHeader[:72] + bytesHeader[76:-4]) != (serializedHeader[:72] + serializedHeader[76:-4]): raise TestError("Template wasn't cleared.") #Sleep so we can reconnect. time.sleep(35) rpc.meros.liveConnect(blockchain.blocks[0].header.hash) #Finally create the Elements. dataDiff: SignedDataDifficulty = SignedDataDifficulty(1, 0) dataDiff.sign(2, PrivateKey(1)) rpc.meros.signedElement(dataDiff) sendDiffs: List[SignedSendDifficulty] = [ SignedSendDifficulty(1, 1), SignedSendDifficulty(2, 1) ] for sd in sendDiffs: sd.sign(2, PrivateKey(1)) rpc.meros.signedElement(sd) time.sleep(1) #`elem for elem` is used below due to Pyright not handling inheritance properly when nested. #pylint: disable=unnecessary-comprehension if bytes.fromhex( rpc.call("merit", "getBlockTemplate", {"miner": getMiner(0)}, False)["header"])[36:68] != BlockHeader.createContents( [], [elem for elem in sendDiffs[::-1]]): raise TestError( "Meros didn't include just the malicious Elements in its new template." )
def restOfTest() -> None: #Move expected into scope. expected: str = getAddress(mnemonic, password, 0) #Send to the new address, then call getAddress again. Verify a new address appears. last: Send = createSend( rpc, Claim.fromTransaction(iter(transactions.txs.values()).__next__()), expected) hashes: List[bytes] = [last.hash] expected = getAddress(mnemonic, password, 1) if rpc.call("personal", "getAddress") != expected: raise TestError( "Meros didn't move to the next address once the existing one was used." ) #Send to the new unused address, spending the funds before calling getAddress again. #Checks address usage isn't defined as having an UTXO, yet rather any TXO. #Also confirm the spending TX with full finalization before checking. #Ensures the TXO isn't unspent by any definition. last = createSend(rpc, last, expected) hashes.append(last.hash) #Spending TX. send: Send = Send([(hashes[-1], 0)], [(bytes(32), 1)]) send.signature = ed.sign(b"MEROS" + send.hash, getPrivateKey(mnemonic, password, 1)) send.beat(SpamFilter(3)) if rpc.meros.liveTransaction(send) != rpc.meros.live.recv(): raise TestError("Meros didn't broadcast back the spending Send.") hashes.append(send.hash) #In order to finalize, we need to mine 6 Blocks once this Transaction and its parent have Verifications. for txHash in hashes: sv: SignedVerification = SignedVerification(txHash) sv.sign(0, PrivateKey(0)) if rpc.meros.signedElement(sv) != rpc.meros.live.recv(): raise TestError("Meros didn't broadcast back a Verification.") #Close the sockets while we mine. rpc.meros.live.connection.close() rpc.meros.sync.connection.close() #Mine these to the Wallet on the node so we can test getMeritHolderNick. privKey: PrivateKey = PrivateKey( bytes.fromhex(rpc.call("personal", "getMeritHolderKey"))) blockchain: Blockchain = Blockchain.fromJSON(vectors["blockchain"]) for _ in range(6): template: Dict[str, Any] = rpc.call( "merit", "getBlockTemplate", {"miner": privKey.toPublicKey().serialize().hex()}) proof: int = -1 tempHash: bytes = bytes() tempSignature: bytes = bytes() while ((proof == -1) or ((int.from_bytes(tempHash, "little") * (blockchain.difficulty() * 11 // 10)) > int.from_bytes( bytes.fromhex("FF" * 32), "little"))): proof += 1 tempHash = RandomX( bytes.fromhex(template["header"]) + proof.to_bytes(4, "little")) tempSignature = privKey.sign(tempHash).serialize() tempHash = RandomX(tempHash + tempSignature) rpc.call( "merit", "publishBlock", { "id": template["id"], "header": template["header"] + proof.to_bytes(4, "little").hex() + tempSignature.hex() }) blockchain.add( Block.fromJSON( rpc.call("merit", "getBlock", {"block": len(blockchain.blocks)}))) #Verify a new address is returned. expected = getAddress(mnemonic, password, 2) if rpc.call("personal", "getAddress") != expected: raise TestError( "Meros didn't move to the next address once the existing one was used." ) #Get a new address after sending to the address after it. #Use both, and then call getAddress. #getAddress should detect X is used, move to Y, detect Y is used, and move to Z. #It shouldn't assume the next address after an used address is unused. #Actually has two Ys as one iteration of the code only ran for the next address; not all future addresses. #Send to the next next addresses. for i in range(2): addy: str = getAddress(mnemonic, password, 3 + i) #Reopen the sockets. This isn't done outside of the loop due to the time deriving the final address can take. #Due to how slow the reference Python code is, it is necessary to redo the socket connections. sleep(65) rpc.meros.liveConnect(Blockchain().blocks[0].header.hash) rpc.meros.syncConnect(Blockchain().blocks[0].header.hash) last = createSend(rpc, last, addy) if MessageType(rpc.meros.live.recv() [0]) != MessageType.SignedVerification: raise TestError( "Meros didn't create and broadcast a SignedVerification for this Send." ) if i == 0: #Close them again. rpc.meros.live.connection.close() rpc.meros.sync.connection.close() #Verify getAddress returns the existing next address. if rpc.call("personal", "getAddress") != expected: raise TestError( "Sending to the address after this address caused Meros to consider this address used." ) #Send to the next address. last = createSend(rpc, last, expected) if MessageType( rpc.meros.live.recv()[0]) != MessageType.SignedVerification: raise TestError( "Meros didn't create and broadcast a SignedVerification for this Send." ) #Verify getAddress returns the address after the next next addresses. expected = getAddress(mnemonic, password, 5) if rpc.call("personal", "getAddress") != expected: raise TestError( "Meros didn't return the correct next address after using multiple addresses in a row." ) #Now that we have mined a Block as part of this test, ensure the Merit Holder nick is set. if rpc.call("personal", "getMeritHolderNick") != 1: raise TestError( "Merit Holder nick wasn't made available despite having one.") #Sanity check off Mnemonic. if rpc.call("personal", "getMnemonic") != mnemonic: raise TestError("getMnemonic didn't return the correct Mnemonic.") #Existing values used to test getMnemonic/getMeritHolderKey/getMeritHolderNick/getAccount/getAddress consistency. existing: Dict[str, Any] = { #Should be equal to the mnemonic variable, which is verified in a check above. "getMnemonic": rpc.call("personal", "getMnemonic"), "getMeritHolderKey": rpc.call("personal", "getMeritHolderKey"), "getMeritHolderNick": rpc.call("personal", "getMeritHolderNick"), "getAccount": rpc.call("personal", "getAccount"), #Should be equal to expected, which is also verified in a check above. "getAddress": rpc.call("personal", "getAddress") } #Set a new seed and verify the Merit Holder nick is cleared. rpc.call("personal", "setWallet") try: rpc.call("personal", "getMeritHolderNick") raise TestError("") except TestError as e: if str( e ) != "-2 Wallet doesn't have a Merit Holder nickname assigned.": raise TestError( "getMeritHolderNick returned something or an unexpected error when a new Mnemonic was set." ) #Set back the old seed and verify consistency. rpc.call("personal", "setWallet", { "mnemonic": mnemonic, "password": password }) for method in existing: if rpc.call("personal", method) != existing[method]: raise TestError( "Setting an old seed caused the WalletDB to improperly reload." ) #Verify calling getAddress returns the expected address. if rpc.call("personal", "getAddress") != expected: raise TestError( "Meros returned an address that wasn't next after reloading the seed." ) #Reboot the node and verify consistency. rpc.quit() sleep(3) rpc.meros = Meros(rpc.meros.db, rpc.meros.tcp, rpc.meros.rpc) for method in existing: if rpc.call("personal", method) != existing[method]: raise TestError( "Rebooting the node caused the WalletDB to improperly reload." ) #Used so Liver doesn't run its own post-test checks. #Since we added our own Blocks, those will fail. raise SuccessError()
def rehash(self) -> None: self.hash = RandomX(RandomX(self.serializeHash()) + self.signature)
from e2e.Libs.BLS import PrivateKey from e2e.Libs.RandomX import RandomX from e2e.Classes.Merit.Blockchain import BlockHeader, Blockchain privKey: PrivateKey = PrivateKey(0) blockchain: Blockchain = Blockchain() header: BlockHeader = BlockHeader(0, blockchain.last(), bytes(32), 0, bytes(4), bytes(32), privKey.toPublicKey().serialize(), 1200) difficulty: int = blockchain.difficulties[-1] raisedDifficulty: int = difficulty * 11 // 10 header.proof = -1 while ((header.proof == -1) or #Standard difficulty check. Can't overflow against the difficulty. ((int.from_bytes(header.hash, "little") * difficulty) > int.from_bytes( bytes.fromhex("FF" * 32), "little")) or #That said, it also can't beat the raised difficulty it should. ((int.from_bytes(header.hash, "little") * raisedDifficulty) <= int.from_bytes(bytes.fromhex("FF" * 32), "little"))): header.proof += 1 header.hash = RandomX(header.serializeHash()) header.signature = privKey.sign(header.hash).serialize() header.hash = RandomX(header.hash + header.signature) with open("e2e/Vectors/Merit/TwoHundredSeventyThree.json", "w") as vectors: vectors.write(json.dumps(header.toJSON()))