|
| 1 | +from typing import Dict, Any |
| 2 | +from time import sleep |
| 3 | + |
| 4 | +import ed25519 |
| 5 | +from e2e.Libs.BLS import PrivateKey |
| 6 | + |
| 7 | +from e2e.Classes.Merit.Blockchain import BlockHeader |
| 8 | +from e2e.Classes.Merit.Blockchain import BlockBody |
| 9 | +from e2e.Classes.Merit.Blockchain import Block |
| 10 | +from e2e.Classes.Merit.Blockchain import Blockchain |
| 11 | + |
| 12 | +from e2e.Classes.Consensus.SpamFilter import SpamFilter |
| 13 | + |
| 14 | +from e2e.Classes.Transactions.Data import Data |
| 15 | + |
| 16 | +from e2e.Meros.Meros import MessageType |
| 17 | +from e2e.Meros.RPC import RPC |
| 18 | + |
| 19 | +from e2e.Tests.Errors import TestError |
| 20 | + |
| 21 | +#pylint: disable=too-many-locals,too-many-statements |
| 22 | +def TwoHundredThirtyFiveTest( |
| 23 | + rpc: RPC |
| 24 | +) -> None: |
| 25 | + blockchain: Blockchain = Blockchain() |
| 26 | + dataFilter: SpamFilter = SpamFilter(5) |
| 27 | + |
| 28 | + edPrivKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32) |
| 29 | + edPubKey: ed25519.VerifyingKey = edPrivKey.get_verifying_key() |
| 30 | + |
| 31 | + #Mine one Block to the node. |
| 32 | + blsPrivKey: PrivateKey = PrivateKey(bytes.fromhex(rpc.call("personal", "getMiner"))) |
| 33 | + blsPubKey: bytes = blsPrivKey.toPublicKey().serialize() |
| 34 | + |
| 35 | + #Call getBlockTemplate just to get an ID. |
| 36 | + #Skips the need to write a sync loop for the BlockBody. |
| 37 | + template: Dict[str, Any] = rpc.call( |
| 38 | + "merit", |
| 39 | + "getBlockTemplate", |
| 40 | + [blsPubKey.hex()] |
| 41 | + ) |
| 42 | + |
| 43 | + #Mine a Block. |
| 44 | + block = Block( |
| 45 | + BlockHeader( |
| 46 | + 0, |
| 47 | + blockchain.blocks[0].header.hash, |
| 48 | + bytes(32), |
| 49 | + 1, |
| 50 | + bytes(4), |
| 51 | + bytes(32), |
| 52 | + blsPubKey, |
| 53 | + blockchain.blocks[0].header.time + 1200, |
| 54 | + 0 |
| 55 | + ), |
| 56 | + BlockBody() |
| 57 | + ) |
| 58 | + block.mine(blsPrivKey, blockchain.difficulty()) |
| 59 | + blockchain.add(block) |
| 60 | + |
| 61 | + rpc.call("merit", "publishBlock", [template["id"], block.serialize().hex()]) |
| 62 | + |
| 63 | + #Send Meros a Data and receive its Verification to make sure it's verifying Transactions in the first place. |
| 64 | + data: Data = Data(bytes(32), edPubKey.to_bytes()) |
| 65 | + data.sign(edPrivKey) |
| 66 | + data.beat(dataFilter) |
| 67 | + |
| 68 | + rpc.meros.liveConnect(blockchain.blocks[0].header.hash) |
| 69 | + if rpc.meros.liveTransaction(data) != rpc.meros.live.recv(): |
| 70 | + raise TestError("Meros didn't send back the Data.") |
| 71 | + if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification: |
| 72 | + raise TestError("Meros didn't send us its SignedVerification.") |
| 73 | + |
| 74 | + #Close our connection and mine 8 Blocks so its Merit is locked. |
| 75 | + rpc.meros.live.connection.close() |
| 76 | + for _ in range(8): |
| 77 | + block = Block( |
| 78 | + BlockHeader( |
| 79 | + 0, |
| 80 | + blockchain.blocks[-1].header.hash, |
| 81 | + bytes(32), |
| 82 | + 1, |
| 83 | + bytes(4), |
| 84 | + bytes(32), |
| 85 | + 0, |
| 86 | + blockchain.blocks[-1].header.time + 1200, |
| 87 | + 0 |
| 88 | + ), |
| 89 | + BlockBody() |
| 90 | + ) |
| 91 | + #Reusing its key is fine as mining doesn't count as participation. |
| 92 | + block.mine(blsPrivKey, blockchain.difficulty()) |
| 93 | + blockchain.add(block) |
| 94 | + |
| 95 | + #Sleep 30 seconds to make sure Meros noted we disconnected, and then reconnect. |
| 96 | + sleep(30) |
| 97 | + rpc.meros.liveConnect(blockchain.blocks[0].header.hash) |
| 98 | + rpc.meros.syncConnect(blockchain.blocks[0].header.hash) |
| 99 | + |
| 100 | + #Sync the Blocks. |
| 101 | + for b in range(8): |
| 102 | + header: bytes = rpc.meros.liveBlockHeader(blockchain.blocks[b + 2].header) |
| 103 | + if rpc.meros.sync.recv() != (MessageType.BlockBodyRequest.toByte() + blockchain.blocks[b + 2].header.hash): |
| 104 | + raise TestError("Meros didn't request the BlockBody.") |
| 105 | + rpc.meros.blockBody(blockchain.blocks[b + 2]) |
| 106 | + if rpc.meros.live.recv() != header: |
| 107 | + raise TestError("Meros didn't send back the header.") |
| 108 | + if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification: |
| 109 | + raise TestError("Meros didn't verify this Block's data.") |
| 110 | + |
| 111 | + #Verify its Merit is locked. |
| 112 | + #Theoretically, all code after this check is unecessary. |
| 113 | + #Meros verifies a Block's Data after updating its State. |
| 114 | + #Therefore, if the above last Block had its Data verified, this issue should be closed. |
| 115 | + #That said, the timing is a bit too tight for comfort. |
| 116 | + #Better safe than sorry. Hence why the code after this check exists. |
| 117 | + if rpc.call("merit", "getMerit", [0])["status"] != "Locked": |
| 118 | + raise TestError("Merit wasn't locked when it was supposed to be.") |
| 119 | + |
| 120 | + #Send it a Transaction and make sure Meros verifies it, despite having its Merit locked. |
| 121 | + data = Data(data.hash, edPubKey.to_bytes()) |
| 122 | + data.sign(edPrivKey) |
| 123 | + data.beat(dataFilter) |
| 124 | + |
| 125 | + if rpc.meros.liveTransaction(data) != rpc.meros.live.recv(): |
| 126 | + raise TestError("Meros didn't send back the Data.") |
| 127 | + if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification: |
| 128 | + raise TestError("Meros didn't send us its SignedVerification.") |
0 commit comments