From 2cf6fc892be305dc83bc441fd07d07d29d1b1737 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Fri, 31 Jul 2020 06:52:29 -0500 Subject: [PATCH] Fix https://github.com/MerosCrypto/Meros/issues/235. --- .../LockedMerit/TwoHundredThirtyFiveTest.py | 128 ++++++++++++++++++ src/MainTransactions.nim | 2 +- 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 e2e/Tests/Merit/LockedMerit/TwoHundredThirtyFiveTest.py diff --git a/e2e/Tests/Merit/LockedMerit/TwoHundredThirtyFiveTest.py b/e2e/Tests/Merit/LockedMerit/TwoHundredThirtyFiveTest.py new file mode 100644 index 000000000..ee828f98e --- /dev/null +++ b/e2e/Tests/Merit/LockedMerit/TwoHundredThirtyFiveTest.py @@ -0,0 +1,128 @@ +from typing import Dict, Any +from time import sleep + +import ed25519 +from e2e.Libs.BLS import PrivateKey + +from e2e.Classes.Merit.Blockchain import BlockHeader +from e2e.Classes.Merit.Blockchain import BlockBody +from e2e.Classes.Merit.Blockchain import Block +from e2e.Classes.Merit.Blockchain import Blockchain + +from e2e.Classes.Consensus.SpamFilter import SpamFilter + +from e2e.Classes.Transactions.Data import Data + +from e2e.Meros.Meros import MessageType +from e2e.Meros.RPC import RPC + +from e2e.Tests.Errors import TestError + +#pylint: disable=too-many-locals,too-many-statements +def TwoHundredThirtyFiveTest( + rpc: RPC +) -> None: + blockchain: Blockchain = Blockchain() + dataFilter: SpamFilter = SpamFilter(5) + + edPrivKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32) + edPubKey: ed25519.VerifyingKey = edPrivKey.get_verifying_key() + + #Mine one Block to the node. + blsPrivKey: PrivateKey = PrivateKey(bytes.fromhex(rpc.call("personal", "getMiner"))) + blsPubKey: bytes = blsPrivKey.toPublicKey().serialize() + + #Call getBlockTemplate just to get an ID. + #Skips the need to write a sync loop for the BlockBody. + template: Dict[str, Any] = rpc.call( + "merit", + "getBlockTemplate", + [blsPubKey.hex()] + ) + + #Mine a Block. + block = Block( + BlockHeader( + 0, + blockchain.blocks[0].header.hash, + bytes(32), + 1, + bytes(4), + bytes(32), + blsPubKey, + blockchain.blocks[0].header.time + 1200, + 0 + ), + BlockBody() + ) + block.mine(blsPrivKey, blockchain.difficulty()) + blockchain.add(block) + + rpc.call("merit", "publishBlock", [template["id"], block.serialize().hex()]) + + #Send Meros a Data and receive its Verification to make sure it's verifying Transactions in the first place. + data: Data = Data(bytes(32), edPubKey.to_bytes()) + data.sign(edPrivKey) + data.beat(dataFilter) + + rpc.meros.liveConnect(blockchain.blocks[0].header.hash) + if rpc.meros.liveTransaction(data) != rpc.meros.live.recv(): + raise TestError("Meros didn't send back the Data.") + if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification: + raise TestError("Meros didn't send us its SignedVerification.") + + #Close our connection and mine 8 Blocks so its Merit is locked. + rpc.meros.live.connection.close() + for _ in range(8): + block = Block( + BlockHeader( + 0, + blockchain.blocks[-1].header.hash, + bytes(32), + 1, + bytes(4), + bytes(32), + 0, + blockchain.blocks[-1].header.time + 1200, + 0 + ), + BlockBody() + ) + #Reusing its key is fine as mining doesn't count as participation. + block.mine(blsPrivKey, blockchain.difficulty()) + blockchain.add(block) + + #Sleep 30 seconds to make sure Meros noted we disconnected, and then reconnect. + sleep(30) + rpc.meros.liveConnect(blockchain.blocks[0].header.hash) + rpc.meros.syncConnect(blockchain.blocks[0].header.hash) + + #Sync the Blocks. + for b in range(8): + header: bytes = rpc.meros.liveBlockHeader(blockchain.blocks[b + 2].header) + if rpc.meros.sync.recv() != (MessageType.BlockBodyRequest.toByte() + blockchain.blocks[b + 2].header.hash): + raise TestError("Meros didn't request the BlockBody.") + rpc.meros.blockBody(blockchain.blocks[b + 2]) + if rpc.meros.live.recv() != header: + raise TestError("Meros didn't send back the header.") + if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification: + raise TestError("Meros didn't verify this Block's data.") + + #Verify its Merit is locked. + #Theoretically, all code after this check is unecessary. + #Meros verifies a Block's Data after updating its State. + #Therefore, if the above last Block had its Data verified, this issue should be closed. + #That said, the timing is a bit too tight for comfort. + #Better safe than sorry. Hence why the code after this check exists. + if rpc.call("merit", "getMerit", [0])["status"] != "Locked": + raise TestError("Merit wasn't locked when it was supposed to be.") + + #Send it a Transaction and make sure Meros verifies it, despite having its Merit locked. + data = Data(data.hash, edPubKey.to_bytes()) + data.sign(edPrivKey) + data.beat(dataFilter) + + if rpc.meros.liveTransaction(data) != rpc.meros.live.recv(): + raise TestError("Meros didn't send back the Data.") + if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification: + raise TestError("Meros didn't send us its SignedVerification.") diff --git a/src/MainTransactions.nim b/src/MainTransactions.nim index 1f71674cc..527a1c4a8 100644 --- a/src/MainTransactions.nim +++ b/src/MainTransactions.nim @@ -20,7 +20,7 @@ proc verify( return #Make sure we're a Miner with Merit. - if wallet.miner.initiated and (merit.state[wallet.miner.nick, status.epoch] > 0): + if wallet.miner.initiated and (merit.state.merit[wallet.miner.nick] > 0): #Inform the WalletDB were verifying a Transaction. try: wallet.verifyTransaction(transaction)