def __init__(self, rpc: RPC, blockchain: List[Dict[str, Any]], transactions: Union[Transactions, None] = None, settings: Dict[str, Any] = {}) -> None: self.rpc: RPC = rpc #Copy the arguments. self.merit: Merit = Merit.fromJSON(blockchain) self.transactions: Union[Transactions, None] = transactions self.settings: Dict[str, Any] = dict(settings) #Provide default settings when some aren't specified. if "height" not in self.settings: self.settings["height"] = len(self.merit.blockchain.blocks) - 1 if "playback" not in self.settings: self.settings["playback"] = True #List of Block hashes in this Blockchain. self.blockHashes: Set[bytes] = set() for b in range(1, self.settings["height"] + 1): self.blockHashes.add(self.merit.blockchain.blocks[b].header.hash) #List of mentioned Blocks. self.blocks: List[Block] = [ self.merit.blockchain.blocks[self.settings["height"]] ] #Dict of mentioned packets. self.packets: Dict[int, VerificationPacket] = {} #Set of mentioned Transactions. #Includes Transactions verified once the Verifications are sent. self.txs: Set[bytes] = set()
def finish(self) -> Blockchain: actual: Merit = Merit() for b in range(len(self.blocks)): actual.add(self.blocks[b].finish( self.miners[b] if self.keepUnlocked else 0, actual)) return actual.blockchain
def withMint() -> Merit: #Create a Mint by mining 8 Blank Blocks. #The first grants Merit; the second creates a Data; the third verifies the Data. #The next 5 finalize the Data. result: Merit = Merit.fromJSON(PrototypeChain(7).toJSON()) if len(result.mints) != 1: raise GenerationError( "PrototypeChain Mint generator didn't create a Mint.") return result
def TwoHundredFifteenTest(rpc: RPC) -> None: vectors: Dict[str, Any] with open("e2e/Vectors/Transactions/ClaimedMint.json", "r") as file: vectors = json.loads(file.read()) merit: Merit = Merit.fromJSON(vectors["blockchain"]) sendFilter: SpamFilter = SpamFilter(3) dataFilter: SpamFilter = SpamFilter(5) privKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32) pubKey: ed25519.VerifyingKey = privKey.get_verifying_key() def syncUnknown() -> None: claim: Claim = Claim([(merit.mints[0], 0)], pubKey.to_bytes()) claim.sign(PrivateKey(0)) #Create a series of Sends, forming a diamond. #Cross sendB and sendC to actually force this to work in an ordered fashion to pass. sendA: Send = Send([(claim.hash, 0)], [(pubKey.to_bytes(), claim.amount // 2), (pubKey.to_bytes(), claim.amount // 2)]) sendB: Send = Send([(sendA.hash, 0)], [(pubKey.to_bytes(), sendA.outputs[0][1] // 2), (pubKey.to_bytes(), sendA.outputs[0][1] // 2)]) sendC: Send = Send( [(sendA.hash, 1), (sendB.hash, 1)], [(pubKey.to_bytes(), sendA.outputs[1][1] + sendB.outputs[1][1])]) sendD: Send = Send([(sendB.hash, 0), (sendC.hash, 0)], [(pubKey.to_bytes(), claim.amount)]) for send in [sendA, sendB, sendC, sendD]: send.sign(privKey) send.beat(sendFilter) #Send the tail of the diamond, which should cause an ordered top-down sync. sent: bytes = rpc.meros.liveTransaction(sendD) for tx in [ sendC, sendB, sendA, claim, sendA, claim, sendB, sendA, claim ]: if rpc.meros.sync.recv() != ( MessageType.TransactionRequest.toByte() + tx.hash): raise TestError("Meros didn't request one of the inputs.") rpc.meros.syncTransaction(tx) if rpc.meros.live.recv() != sent: raise TestError("Meros didn't broadcast the Send.") #Do the same for a few Data Transactions. datas: List[Data] = [Data(bytes(32), pubKey.to_bytes())] datas.append(Data(datas[-1].hash, bytes(1))) datas.append(Data(datas[-1].hash, bytes(1))) for data in datas: data.sign(privKey) data.beat(dataFilter) Liver(rpc, vectors["blockchain"], callbacks={7: syncUnknown}).live()
def __init__(self, rpc: RPC, blockchain: List[Dict[str, Any]], transactions: Optional[Transactions] = None, callbacks: Dict[int, Callable[[], None]] = {}, everyBlock: Optional[Callable[[int], None]] = None) -> None: self.rpc: RPC = rpc #Copy the arguments into the class. self.merit: Merit = Merit.fromJSON(blockchain) self.transactions: Optional[Transactions] = transactions self.callbacks: Dict[int, Callable[[], None]] = dict(callbacks) self.everyBlock: Optional[Callable[[int], None]] = everyBlock
def HundredFortySevenTest(rpc: RPC) -> None: file: IO[Any] = open("e2e/Vectors/Transactions/ClaimedMint.json", "r") vectors: Dict[str, Any] = json.loads(file.read()) file.close() #Merit. merit: Merit = Merit.fromJSON(vectors["blockchain"]) #Transactions. transactions: Transactions = Transactions.fromJSON(vectors["transactions"]) #Ed25519 keys. privKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32) pubKey: ed25519.VerifyingKey = privKey.get_verifying_key() #Grab the Claim hash, claim: bytes = merit.blockchain.blocks[-1].body.packets[0].hash #Create a Send which underflows. send: Send = Send( [(claim, 0)], [(pubKey.to_bytes(), 18446744073709551231), (pubKey.to_bytes(), 385 + Claim.fromTransaction(transactions.txs[claim]).amount)]) send.sign(privKey) send.beat(SpamFilter(3)) #Custom function to send the last Block and verify it errors at the right place. def checkFail() -> None: #Send the Send. rpc.meros.liveTransaction(send) #Handle sync requests. while True: #Try receiving from the Live socket, where Meros sends keep-alives. try: if len(rpc.meros.live.recv()) != 0: raise Exception() except TestError: raise SuccessError( "Node disconnected us after we sent an invalid Transaction." ) except Exception: raise TestError("Meros sent a keep-alive.") #Create and execute a Liver. Liver(rpc, vectors["blockchain"], transactions, callbacks={ 12: checkFail }).live()
def reorgPast( mint: bytes ) -> Merit: #Safe due to performing the shallower reorg first. while coreMerit[-1]["hash"] != mint.hex().upper(): del coreMerit[-1] del coreMerit[-1] newMerit: Merit = Merit.fromJSON(coreMerit) #pylint: disable=global-statement global heightToBeat while len(newMerit.blockchain.blocks) <= heightToBeat: newMerit.add( PrototypeBlock( #Use a slightly faster time differential. newMerit.blockchain.blocks[-1].header.time + ((newMerit.blockchain.blocks[-1].header.time - newMerit.blockchain.blocks[-2].header.time) - 1) ).finish(1, newMerit) ) heightToBeat = len(newMerit.blockchain.blocks) return newMerit
from typing import IO, Any import json from e2e.Classes.Consensus.SendDifficulty import SendDifficulty from e2e.Classes.Consensus.DataDifficulty import DataDifficulty from e2e.Classes.Merit.Merit import Merit from e2e.Vectors.Generation.PrototypeChain import PrototypeBlock, PrototypeChain merit: Merit = Merit.fromJSON(PrototypeChain(49).finish().toJSON()) #Add the Difficulties. merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, elements=[SendDifficulty(2, 0, 0), DataDifficulty(2, 1, 0)], minerID=0).finish(0, merit)) #Close out this, and the next, Checkpoint period to lock our Merit. for _ in range(9): merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, minerID=0).finish(0, merit)) #Become Pending. merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, minerID=0).finish(1, merit)) vectors: IO[Any] = open("e2e/Vectors/Consensus/Difficulties/LockedMerit.json",
def TElementTest( rpc: RPC ) -> None: file: IO[Any] = open("e2e/Vectors/Merit/BlankBlocks.json", "r") blocks: List[Dict[str, Any]] = json.loads(file.read()) file.close() merit: Merit = Merit() blsPrivKey: PrivateKey = PrivateKey(0) blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex() #Handshake with the node. rpc.meros.liveConnect(merit.blockchain.blocks[0].header.hash) rpc.meros.syncConnect(merit.blockchain.blocks[0].header.hash) #Send the first Block. block: Block = Block.fromJSON(blocks[0]) merit.blockchain.add(block) rpc.meros.liveBlockHeader(block.header) #Handle sync requests. reqHash: bytes = bytes() while True: msg: bytes = rpc.meros.sync.recv() if MessageType(msg[0]) == MessageType.BlockBodyRequest: reqHash = msg[1 : 33] if reqHash != block.header.hash: raise TestError("Meros asked for a Block Body that didn't belong to the Block we just sent it.") rpc.meros.blockBody(block) break else: raise TestError("Unexpected message sent: " + msg.hex().upper()) if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader: raise TestError("Meros didn't broadcast the Block Header it just added.") #Create and transmit a DataDifficulty. dataDiff: SignedDataDifficulty = SignedDataDifficulty(0, 0, 0) dataDiff.sign(0, blsPrivKey) rpc.meros.signedElement(dataDiff) sleep(0.5) #Verify the block template has the DataDifficulty. template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate", [blsPubKey]) template["header"] = bytes.fromhex(template["header"]) if template["header"][36 : 68] != BlockHeader.createContents([], [dataDiff]): raise TestError("Block template doesn't have the Data Difficulty.") #Mine the Block. block = Block( BlockHeader( 0, block.header.hash, BlockHeader.createContents([], [dataDiff]), 1, template["header"][-43 : -39], BlockHeader.createSketchCheck(template["header"][-43 : -39], []), 0, int.from_bytes(template["header"][-4:], byteorder="little"), ), BlockBody([], [dataDiff], dataDiff.signature) ) if block.header.serializeHash()[:-4] != template["header"]: raise TestError("Failed to recreate the header.") if block.body.serialize(block.header.sketchSalt) != bytes.fromhex(template["body"]): raise TestError("Failed to recreate the body.") block.mine(blsPrivKey, merit.blockchain.difficulty()) merit.blockchain.add(block) #Publish it. rpc.call( "merit", "publishBlock", [ template["id"], ( template["header"] + block.header.proof.to_bytes(4, byteorder="little") + block.header.signature + block.body.serialize(block.header.sketchSalt) ).hex() ] ) #Create and transmit a new DataDifficulty. dataDiff = SignedDataDifficulty(3, 1, 0) dataDiff.sign(0, blsPrivKey) rpc.meros.signedElement(dataDiff) sleep(0.5) #Verify the block template has the DataDifficulty. template = rpc.call("merit", "getBlockTemplate", [blsPubKey]) template["header"] = bytes.fromhex(template["header"]) if template["header"][36 : 68] != BlockHeader.createContents([], [dataDiff]): raise TestError("Block template doesn't have the new Data Difficulty.") #Create and transmit a new DataDifficulty reusing an existing nonce. signatures: List[Signature] = [dataDiff.signature] dataDiff = SignedDataDifficulty(4, 1, 0) dataDiff.sign(0, blsPrivKey) signatures.append(dataDiff.signature) rpc.meros.signedElement(dataDiff) sleep(0.5) #Verify the block template has a MeritRemoval. mr: MeritRemoval = MeritRemoval( SignedDataDifficulty(3, 1, 0), SignedDataDifficulty(4, 1, 0), False ) template = rpc.call("merit", "getBlockTemplate", [blsPubKey]) template["header"] = bytes.fromhex(template["header"]) if template["header"][36 : 68] != BlockHeader.createContents([], [mr]): raise TestError("Block template doesn't have the Merit Removal.") #Mine the Block. block = Block( BlockHeader( 0, block.header.hash, BlockHeader.createContents([], [mr]), 1, template["header"][-43 : -39], BlockHeader.createSketchCheck(template["header"][-43 : -39], []), 0, int.from_bytes(template["header"][-4:], byteorder="little") ), BlockBody([], [mr], Signature.aggregate(signatures)) ) if block.header.serializeHash()[:-4] != template["header"]: raise TestError("Failed to recreate the header.") if block.body.serialize(block.header.sketchSalt) != bytes.fromhex(template["body"]): raise TestError("Failed to recreate the body.") block.mine(blsPrivKey, merit.blockchain.difficulty()) merit.blockchain.add(block) rpc.call( "merit", "publishBlock", [ template["id"], ( template["header"] + block.header.proof.to_bytes(4, byteorder="little") + block.header.signature + block.body.serialize(block.header.sketchSalt) ).hex() ] ) verifyBlockchain(rpc, merit.blockchain)
def MatchesHeaderQuantityTest(meros: Meros) -> None: #Create an instance of Merit to make sure the RandomX VM key was set. Merit() blocks: List[Block] txs: List[Data] = [] verifs: List[SignedVerification] = [] with open( "e2e/Vectors/Merit/TwoHundredSeventyFour/MatchesHeaderQuantity.json", "r") as file: vectors: Dict[str, Any] = json.loads(file.read()) blocks = [Block.fromJSON(block) for block in vectors["blocks"]] txs = [Data.fromJSON(tx) for tx in vectors["transactions"]] verifs = [ SignedVerification.fromSignedJSON(verif) for verif in vectors["verifications"] ] #Connect. meros.liveConnect(blocks[0].header.last) meros.syncConnect(blocks[0].header.last) #Send a single Block to earn Merit. meros.liveBlockHeader(blocks[0].header) meros.handleBlockBody(blocks[0]) #Send the header. meros.liveBlockHeader(blocks[1].header) #Fail Sketch Resolution, and send a different amount of sketch hashes. meros.handleBlockBody(blocks[1], 0) if MessageType(meros.sync.recv()[0]) != MessageType.SketchHashesRequest: raise TestError( "Meros didn't request the hashes after failing sketch resolution.") #Send a quantity of sketch hashes that doesn't match the header. meros.sketchHashes([ Sketch.hash(blocks[1].header.sketchSalt, VerificationPacket(tx.hash, [0])) for tx in txs ]) try: if len(meros.sync.recv()) == 0: raise TestError() raise Exception() except TestError: pass except Exception: raise TestError("Meros tried to further sync an invalid Block Body.") #Sleep so we can reconnect. sleep(65) #Repeat setup. meros.liveConnect(blocks[0].header.last) meros.syncConnect(blocks[0].header.last) #Send two Transactions. for i in range(2): meros.liveTransaction(txs[i]) meros.signedElement(verifs[i]) #Send the header and a large enough sketch to cause resolution. meros.liveBlockHeader(blocks[1].header) meros.handleBlockBody(blocks[1], 3) #Should now have been disconnected thanks to having 5 hashes. try: if len(meros.sync.recv()) == 0: raise TestError() raise Exception() except TestError: pass except Exception: raise TestError("Meros tried to further sync an invalid Block Body.")
from typing import IO, Any import json from e2e.Classes.Merit.Merit import Blockchain, Merit from e2e.Vectors.Generation.PrototypeChain import PrototypeBlock, PrototypeChain protoRoot: PrototypeChain = PrototypeChain(1, False) protoRoot.add(1) root: Blockchain = protoRoot.finish() main: Merit = Merit.fromJSON(root.toJSON()) alt: Merit = Merit.fromJSON(root.toJSON()) main.add( PrototypeBlock(main.blockchain.blocks[-1].header.time + 1200).finish( 0, main)) #Create the competing Block to the second miner. #Since the difficulty is fixed at the start, they're guaranteed to have the same amount of work. #Because of that, we can't just mine the Block; we need to mine it until it has a lower hash than the above Block. #Calculate a custom difficulty guaranteed to beat the above Block. hashAsInt: int = int.from_bytes(main.blockchain.blocks[-1].header.hash, "little") alt.blockchain.difficulties[-1] = 0 while (alt.blockchain.difficulties[-1] * hashAsInt).bit_length() <= 256: alt.blockchain.difficulties[-1] += 1 alt.add( PrototypeBlock(alt.blockchain.blocks[-1].header.time + 1200, minerID=1).finish(0, alt))
def sendAndVerify() -> None: rpc.meros.liveTransaction(send) rpc.meros.liveTransaction(data) rpc.meros.live.recv() rpc.meros.live.recv() #We now have a Mint, a Claim, a Send, a Data, a lion, a witch, and a wardrobe. #Check the Mint. mint: Mint = Merit.fromJSON(vectors["blockchain"]).mints[0] #pylint: disable=invalid-name EXPECTED_MINT: Dict[str, Any] = { "descendant": "Mint", "inputs": [], "outputs": [{ "amount": str(txOutput[1]), "nick": txOutput[0] } for txOutput in mint.outputs], "hash": mint.hash.hex().upper() } #Also sanity check against the in-house JSON. if mint.toJSON() != EXPECTED_MINT: raise TestError("Python's Mint toJSON doesn't match the spec.") if rpc.call("transactions", "getTransaction", {"hash": mint.hash.hex()}, False) != EXPECTED_MINT: raise TestError("getTransaction didn't report the Mint properly.") #Check the Claim. #pylint: disable=invalid-name EXPECTED_CLAIM: Dict[str, Any] = { "descendant": "Claim", "inputs": [{ "hash": txInput[0].hex().upper(), "nonce": txInput[1] } for txInput in claim.inputs], "outputs": [{ "amount": str(claim.amount), "key": claim.output.hex().upper() }], "hash": claim.hash.hex().upper(), "signature": claim.signature.hex().upper() } if claim.amount == 0: raise Exception( "Python didn't instantiate the Claim with an amount, leading to invalid testing methodology." ) if claim.toJSON() != EXPECTED_CLAIM: raise TestError("Python's Claim toJSON doesn't match the spec.") if rpc.call("transactions", "getTransaction", {"hash": claim.hash.hex()}, False) != EXPECTED_CLAIM: raise TestError("getTransaction didn't report the Claim properly.") #Check the Send. #pylint: disable=invalid-name EXPECTED_SEND: Dict[str, Any] = { "descendant": "Send", "inputs": [{ "hash": txInput[0].hex().upper(), "nonce": txInput[1] } for txInput in send.inputs], "outputs": [{ "amount": str(txOutput[1]), "key": txOutput[0].hex().upper() } for txOutput in send.outputs], "hash": send.hash.hex().upper(), "signature": send.signature.hex().upper(), "proof": send.proof } if send.toJSON() != EXPECTED_SEND: raise TestError("Python's Send toJSON doesn't match the spec.") if rpc.call("transactions", "getTransaction", {"hash": send.hash.hex()}, False) != EXPECTED_SEND: raise TestError("getTransaction didn't report the Send properly.") #Check the Data. #pylint: disable=invalid-name EXPECTED_DATA: Dict[str, Any] = { "descendant": "Data", "inputs": [{ "hash": data.txInput.hex().upper() }], "outputs": [], "hash": data.hash.hex().upper(), "data": data.data.hex().upper(), "signature": data.signature.hex().upper(), "proof": data.proof } if data.toJSON() != EXPECTED_DATA: raise TestError("Python's Data toJSON doesn't match the spec.") if rpc.call("transactions", "getTransaction", {"hash": data.hash.hex()}, False) != EXPECTED_DATA: raise TestError("getTransaction didn't report the Data properly.") #Non-existent hash; should cause an IndexError nonExistentHash: str = data.hash.hex() if data.hash[0] == "0": nonExistentHash = "1" + nonExistentHash[1:] else: nonExistentHash = "0" + nonExistentHash[1:] try: rpc.call("transactions", "getTransaction", {"hash": nonExistentHash}, False) except TestError as e: if str(e) != "-2 Transaction not found.": raise TestError( "getTransaction didn't raise IndexError on a non-existent hash." ) #Invalid argument; should cause a ParamError #This is still a hex value try: rpc.call("transactions", "getTransaction", {"hash": "00" + data.hash.hex()}, False) raise TestError( "Meros didn't error when we asked for a 33-byte hex value.") except TestError as e: if str(e) != "-32602 Invalid params.": raise TestError( "getTransaction didn't raise on invalid parameters.")
from e2e.Classes.Consensus.Verification import SignedVerification from e2e.Classes.Consensus.VerificationPacket import VerificationPacket from e2e.Classes.Consensus.SpamFilter import SpamFilter from e2e.Classes.Merit.BlockHeader import BlockHeader from e2e.Classes.Merit.BlockBody import BlockBody from e2e.Classes.Merit.Block import Block from e2e.Classes.Merit.Merit import Merit bbFile: IO[Any] = open("e2e/Vectors/Merit/BlankBlocks.json", "r") blankBlocks: List[Dict[str, Any]] = json.loads(bbFile.read()) bbFile.close() transactions: Transactions = Transactions() merit: Merit = Merit() dataFilter: SpamFilter = SpamFilter(5) edPrivKey: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32) edPubKey: bytes = edPrivKey.get_verifying_key() blsPrivKeys: List[PrivateKey] = [ PrivateKey(blake2b(b'\0', digest_size=32).digest()), PrivateKey(blake2b(b'\1', digest_size=32).digest()) ] blsPubKeys: List[PublicKey] = [ blsPrivKeys[0].toPublicKey(), blsPrivKeys[1].toPublicKey() ] for i in range(4): merit.add(Block.fromJSON(blankBlocks[i]))
from typing import Dict, List, Any import json import e2e.Libs.Ristretto.Ristretto as Ristretto from e2e.Libs.BLS import PrivateKey from e2e.Classes.Transactions.Transactions import Claim, Send, Transactions from e2e.Classes.Consensus.SpamFilter import SpamFilter from e2e.Classes.Consensus.VerificationPacket import VerificationPacket from e2e.Classes.Merit.Merit import Merit from e2e.Vectors.Generation.PrototypeChain import PrototypeBlock, PrototypeChain merit: Merit = Merit.fromJSON(PrototypeChain(47).toJSON()) transactions: Transactions = Transactions() privKey: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32) pubKey: bytes = privKey.get_verifying_key() recipientPriv: Ristretto.SigningKey = Ristretto.SigningKey(b'\1' * 32) recipientPub: bytes = recipientPriv.get_verifying_key() olderClaim: Claim = Claim([(merit.mints[-1], 0)], pubKey) olderClaim.sign(PrivateKey(0)) transactions.add(olderClaim) merit.add( PrototypeBlock( merit.blockchain.blocks[-1].header.time + 1200, packets=[VerificationPacket(olderClaim.hash, [0])] ).finish(0, merit)
from typing import Dict, List, Any import json from e2e.Libs.BLS import PrivateKey from e2e.Classes.Merit.Merit import Merit from e2e.Vectors.Generation.PrototypeChain import PrototypeBlock, PrototypeChain root: List[Dict[str, Any]] = PrototypeChain(9, False).finish().toJSON() main: Merit = Merit.fromJSON(root) alt: Merit = Merit.fromJSON(root) for _ in range(2): main.add( PrototypeBlock(main.blockchain.blocks[-1].header.time + 1200).finish( 0, main)) #Create a fork Block with a lower hash. #Same principle as DepthOne. hashAsInt: int = int.from_bytes(main.blockchain.blocks[-2].header.hash, "little") k: int = 1 while int.from_bytes( PrototypeBlock(alt.blockchain.blocks[-1].header.time + 1200, minerID=PrivateKey(k)).finish(0, alt).header.hash, "little") > hashAsInt: k += 1 alt.add( PrototypeBlock(alt.blockchain.blocks[-1].header.time + 1200, minerID=PrivateKey(k)).finish(0, alt))
def EightyEightTest( rpc: RPC ) -> None: edPrivKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32) edPubKey: ed25519.VerifyingKey = edPrivKey.get_verifying_key() blsPrivKey: PrivateKey = PrivateKey(0) blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex() file: IO[Any] = open("e2e/Vectors/Merit/BlankBlocks.json", "r") blocks: List[Dict[str, Any]] = json.loads(file.read()) file.close() merit: Merit = Merit() dataFilter: SpamFilter = SpamFilter(5) #Handshake with the node. rpc.meros.liveConnect(merit.blockchain.blocks[0].header.hash) rpc.meros.syncConnect(merit.blockchain.blocks[0].header.hash) #Send the first Block. block: Block = Block.fromJSON(blocks[0]) merit.blockchain.add(block) rpc.meros.liveBlockHeader(block.header) #Handle sync requests. reqHash: bytes = bytes() while True: msg: bytes = rpc.meros.sync.recv() if MessageType(msg[0]) == MessageType.BlockBodyRequest: reqHash = msg[1 : 33] if reqHash != block.header.hash: raise TestError("Meros asked for a Block Body that didn't belong to the Block we just sent it.") #Send the BlockBody. rpc.meros.blockBody(block) break else: raise TestError("Unexpected message sent: " + msg.hex().upper()) if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader: raise TestError("Meros didn't broadcast the Block Header it just added.") #Create two Datas. datas: List[Data] = [Data(bytes(32), edPubKey.to_bytes())] datas.append(Data(datas[0].hash, b"Hello there! General Kenobi.")) for data in datas: #Sign them and have them beat the spam filter. data.sign(edPrivKey) data.beat(dataFilter) #Transmit them. rpc.meros.liveTransaction(data) #Verify both. verifs: List[SignedVerification] = [ SignedVerification(datas[0].hash), SignedVerification(datas[1].hash) ] for verif in verifs: verif.sign(0, blsPrivKey) #Only transmit the second. rpc.meros.signedElement(verifs[1]) sleep(0.5) #Verify the block template has no verifications. if bytes.fromhex( rpc.call("merit", "getBlockTemplate", [blsPubKey])["header"] )[36 : 68] != bytes(32): raise TestError("Block template has Verification Packets.") #Transmit the first signed verification. rpc.meros.signedElement(verifs[0]) sleep(0.5) #Verify the block template has both verifications. template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate", [blsPubKey]) template["header"] = bytes.fromhex(template["header"]) packets: List[VerificationPacket] = [VerificationPacket(datas[0].hash, [0]), VerificationPacket(datas[1].hash, [0])] if template["header"][36 : 68] != BlockHeader.createContents(packets): raise TestError("Block template doesn't have both Verification Packets.") #Mine the Block. block = Block( BlockHeader( 0, block.header.hash, BlockHeader.createContents(packets), 1, template["header"][-43 : -39], BlockHeader.createSketchCheck(template["header"][-43 : -39], packets), 0, int.from_bytes(template["header"][-4:], byteorder="little") ), BlockBody( packets, [], Signature.aggregate([verifs[0].signature, verifs[1].signature]) ) ) if block.header.serializeHash()[:-4] != template["header"]: raise TestError("Failed to recreate the header.") if block.body.serialize( block.header.sketchSalt, len(packets) ) != bytes.fromhex(template["body"]): raise TestError("Failed to recreate the body.") block.mine(blsPrivKey, merit.blockchain.difficulty()) merit.blockchain.add(block) rpc.call( "merit", "publishBlock", [ template["id"], ( template["header"] + block.header.proof.to_bytes(4, byteorder="little") + block.header.signature + block.body.serialize(block.header.sketchSalt, len(packets)) ).hex() ] ) verifyBlockchain(rpc, merit.blockchain)
def SameInputTest(rpc: RPC) -> None: file: IO[Any] = open("e2e/Vectors/Transactions/SameInput/Claim.json", "r") vectors: Dict[str, Any] = json.loads(file.read()) file.close() merit: Merit = Merit.fromJSON(vectors["blockchain"]) transactions: Transactions = Transactions.fromJSON(vectors["transactions"]) #Custom function to send the last Block and verify it errors at the right place. def checkFail() -> None: #Grab the Block. block: Block = merit.blockchain.blocks[8] #Send the Block. rpc.meros.liveBlockHeader(block.header) #Handle sync requests. while True: msg: bytes = rpc.meros.sync.recv() if MessageType(msg[0]) == MessageType.BlockBodyRequest: if msg[1:33] != block.header.hash: raise TestError( "Meros asked for a Block Body that didn't belong to the Block we just sent it." ) rpc.meros.blockBody(block) elif MessageType(msg[0]) == MessageType.SketchHashRequests: if msg[1:33] != block.header.hash: raise TestError( "Meros asked for Verification Packets that didn't belong to the Block we just sent it." ) #Create a lookup of hash to packets. packets: Dict[int, VerificationPacket] = {} for packet in block.body.packets: packets[Sketch.hash(block.header.sketchSalt, packet)] = packet #Look up each requested packet and respond accordingly. for h in range(int.from_bytes(msg[33:37], byteorder="little")): sketchHash: int = int.from_bytes(msg[37 + (h * 8):45 + (h * 8)], byteorder="little") if sketchHash not in packets: raise TestError( "Meros asked for a non-existent Sketch Hash.") rpc.meros.packet(packets[sketchHash]) elif MessageType(msg[0]) == MessageType.TransactionRequest: reqHash: bytes = msg[1:33] if reqHash not in transactions.txs: raise TestError( "Meros asked for a non-existent Transaction.") rpc.meros.syncTransaction(transactions.txs[reqHash]) #Try receiving from the Live socket, where Meros sends keep-alives. try: if len(rpc.meros.live.recv()) != 0: raise Exception() except TestError: raise SuccessError( "Node disconnected us after we sent an invalid Transaction." ) except Exception: raise TestError("Meros sent a keep-alive.") else: raise TestError("Unexpected message sent: " + msg.hex().upper()) with raises(SuccessError): Liver(rpc, vectors["blockchain"], transactions, callbacks={ 7: checkFail }).live()
def TwoHundredSixtyOneTest(rpc: RPC) -> None: merit: Merit = Merit() blsPrivKey: PrivateKey = PrivateKey( bytes.fromhex(rpc.call("personal", "getMeritHolderKey"))) blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex() #Get a template. template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate", {"miner": blsPubKey}) template["header"] = bytes.fromhex(template["header"]) #Mine it. #Ignores the template except for the ID needed to publish it. #We could publish it over the socket to an identical effect, practically. #That said, this is more accurate to flow. block: Block = PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, minerID=blsPrivKey).finish(0, merit) merit.add(block) #Connect in order to receive their Verification of the Block's Data. rpc.meros.liveConnect(merit.blockchain.blocks[0].header.hash) rpc.meros.syncConnect(merit.blockchain.blocks[0].header.hash) #Publish it. rpc.call("merit", "publishBlock", { "id": template["id"], "header": block.header.serialize().hex() }) if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader: raise TestError("Meros didn't broadcast a published Block.") #Receive their Verification. if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification: raise TestError("Meros didn't verify the Block's Data.") #Reorg past the chain with them as the nick. with open("e2e/Vectors/Merit/BlankBlocks.json", "r") as file: blankBlocks: Blockchain = Blockchain.fromJSON(json.loads(file.read())) rpc.meros.liveBlockHeader(blankBlocks.blocks[2].header) if MessageType( rpc.meros.sync.recv()[0]) != MessageType.BlockListRequest: raise TestError( "Meros didn't request the Block List needed to reorg.") rpc.meros.blockList([blankBlocks.blocks[0].header.hash]) if MessageType( rpc.meros.sync.recv()[0]) != MessageType.BlockHeaderRequest: raise TestError( "Meros didn't request the next Block Header on the list.") rpc.meros.syncBlockHeader(blankBlocks.blocks[1].header) for b in range(2): rpc.meros.handleBlockBody(blankBlocks.blocks[b + 1]) #Close the connection to give us time to mine Blocks without worrying about the handshake. rpc.meros.live.connection.close() rpc.meros.sync.connection.close() sleep(65) #Mine Blocks so we can re-org back to the original chain. merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, minerID=PrivateKey(1)).finish(0, merit)) merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, minerID=1).finish(0, merit)) #Reconnect. rpc.meros.liveConnect(merit.blockchain.blocks[0].header.hash) rpc.meros.syncConnect(merit.blockchain.blocks[0].header.hash) #Send the header for the original chain. rpc.meros.liveBlockHeader(merit.blockchain.blocks[3].header) if MessageType(rpc.meros.sync.recv()[0]) != MessageType.BlockListRequest: raise TestError("Meros didn't request the Block List needed to reorg.") rpc.meros.blockList([ merit.blockchain.blocks[1].header.hash, merit.blockchain.blocks[0].header.hash ]) for h in range(2): if MessageType( rpc.meros.sync.recv()[0]) != MessageType.BlockHeaderRequest: raise TestError( "Meros didn't request the next Block Header on the list.") rpc.meros.syncBlockHeader(merit.blockchain.blocks[h + 1].header) for b in range(3): rpc.meros.handleBlockBody(merit.blockchain.blocks[b + 1]) if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader: raise TestError("Meros didn't broadcast a Block it just synced.") if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification: raise TestError( "Meros didn't verify the Block's Data after the re-org.")
def EightyEightTest(rpc: RPC) -> None: edPrivKey: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32) edPubKey: bytes = edPrivKey.get_verifying_key() blsPrivKey: PrivateKey = PrivateKey(0) blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex() merit: Merit = Merit() dataFilter: SpamFilter = SpamFilter(5) #Handshake with the node. rpc.meros.liveConnect(merit.blockchain.blocks[0].header.hash) rpc.meros.syncConnect(merit.blockchain.blocks[0].header.hash) #Send the first Block. block: Block with open("e2e/Vectors/Merit/BlankBlocks.json", "r") as file: block = Block.fromJSON(json.loads(file.read())[0]) merit.blockchain.add(block) rpc.meros.liveBlockHeader(block.header) rpc.meros.handleBlockBody(block) if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader: raise TestError( "Meros didn't broadcast the Block Header it just added.") #Create two Datas. datas: List[Data] = [Data(bytes(32), edPubKey)] datas.append(Data(datas[0].hash, b"Hello there! General Kenobi.")) for data in datas: #Sign them and have them beat the spam filter. data.sign(edPrivKey) data.beat(dataFilter) #Transmit them. rpc.meros.liveTransaction(data) #Verify both. verifs: List[SignedVerification] = [ SignedVerification(datas[0].hash), SignedVerification(datas[1].hash) ] for verif in verifs: verif.sign(0, blsPrivKey) #Only transmit the second. rpc.meros.signedElement(verifs[1]) sleep(1.5) #Verify the block template has no verifications. if bytes.fromhex( rpc.call("merit", "getBlockTemplate", {"miner": blsPubKey})["header"])[36:68] != bytes(32): raise TestError("Block template has Verification Packets.") #Transmit the first signed verification. rpc.meros.signedElement(verifs[0]) sleep(1.5) #Verify the block template has both verifications. template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate", {"miner": blsPubKey}) template["header"] = bytes.fromhex(template["header"]) packets: List[VerificationPacket] = [ VerificationPacket(datas[0].hash, [0]), VerificationPacket(datas[1].hash, [0]) ] if template["header"][36:68] != BlockHeader.createContents(packets): raise TestError( "Block template doesn't have both Verification Packets.") #Mine the Block. block = Block( BlockHeader( 0, block.header.hash, BlockHeader.createContents(packets), len(packets), template["header"][-43:-39], BlockHeader.createSketchCheck(template["header"][-43:-39], packets), 0, int.from_bytes(template["header"][-4:], byteorder="little")), BlockBody( packets, [], Signature.aggregate([verifs[0].signature, verifs[1].signature]))) if block.header.serializeHash()[:-4] != template["header"]: raise TestError("Failed to recreate the header.") block.mine(blsPrivKey, merit.blockchain.difficulty()) merit.blockchain.add(block) rpc.call( "merit", "publishBlock", { "id": template["id"], "header": (template["header"] + block.header.proof.to_bytes(4, byteorder="little") + block.header.signature).hex() }) verifyBlockchain(rpc, merit.blockchain)
def CompetingFinalizedTest(rpc: RPC) -> None: vectors: Dict[str, Any] with open("e2e/Vectors/Transactions/CompetingFinalized.json", "r") as file: vectors = json.loads(file.read()) merit: Merit = Merit.fromJSON(vectors["blockchain"]) transactions: Transactions = Transactions.fromJSON(vectors["transactions"]) #Custom function to send the last Block and verify it errors at the right place. def checkFail() -> None: #This Block should cause the node to disconnect us AFTER it syncs our Transaction. syncedTX: bool = False block: Block = merit.blockchain.blocks[-1] rpc.meros.liveBlockHeader(block.header) rpc.meros.handleBlockBody(block) #Handle sync requests. reqHash: bytes = bytes() while True: if syncedTX: #Try receiving from the Live socket, where Meros sends keep-alives. try: if len(rpc.meros.live.recv()) != 0: raise Exception() except TestError: raise SuccessError( "Node disconnected us after we sent an invalid Transaction." ) except Exception: raise TestError("Meros sent a keep-alive.") msg: bytes = rpc.meros.sync.recv() if MessageType(msg[0]) == MessageType.SketchHashesRequest: if not block.body.packets: raise TestError( "Meros asked for Sketch Hashes from a Block without any." ) reqHash = msg[1:33] if reqHash != block.header.hash: raise TestError( "Meros asked for Sketch Hashes that didn't belong to the Block we just sent it." ) #Create the haashes. hashes: List[int] = [] for packet in block.body.packets: hashes.append(Sketch.hash(block.header.sketchSalt, packet)) #Send the Sketch Hashes. rpc.meros.sketchHashes(hashes) elif MessageType(msg[0]) == MessageType.SketchHashRequests: if not block.body.packets: raise TestError( "Meros asked for Verification Packets from a Block without any." ) reqHash = msg[1:33] if reqHash != block.header.hash: raise TestError( "Meros asked for Verification Packets that didn't belong to the Block we just sent it." ) #Create a lookup of hash to packets. packets: Dict[int, VerificationPacket] = {} for packet in block.body.packets: packets[Sketch.hash(block.header.sketchSalt, packet)] = packet #Look up each requested packet and respond accordingly. for h in range(int.from_bytes(msg[33:37], byteorder="little")): sketchHash: int = int.from_bytes(msg[37 + (h * 8):45 + (h * 8)], byteorder="little") if sketchHash not in packets: raise TestError( "Meros asked for a non-existent Sketch Hash.") rpc.meros.packet(packets[sketchHash]) elif MessageType(msg[0]) == MessageType.TransactionRequest: reqHash = msg[1:33] if reqHash not in transactions.txs: raise TestError( "Meros asked for a non-existent Transaction.") rpc.meros.syncTransaction(transactions.txs[reqHash]) syncedTX = True else: raise TestError("Unexpected message sent: " + msg.hex().upper()) with raises(SuccessError): Liver(rpc, vectors["blockchain"], transactions, callbacks={ 7: checkFail }).live()
from e2e.Classes.Consensus.VerificationPacket import VerificationPacket from e2e.Classes.Consensus.SpamFilter import SpamFilter from e2e.Classes.Merit.Merit import Block, Merit from e2e.Vectors.Generation.PrototypeChain import PrototypeBlock, PrototypeChain edPrivKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32) edPubKey: bytes = edPrivKey.get_verifying_key().to_bytes() transactions: Transactions = Transactions() sendFilter: SpamFilter = SpamFilter(3) proto: PrototypeChain = PrototypeChain(40, keepUnlocked=True) proto.add(1) merit: Merit = Merit.fromJSON(proto.toJSON()) #Create a Claim. claim: Claim = Claim([(merit.mints[-1], 0)], edPubKey) claim.sign(PrivateKey(0)) transactions.add(claim) merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, packets=[VerificationPacket(claim.hash, list(range(2))) ]).finish(0, merit)) sends: List[Send] = [ #Transaction which will win. Send([(claim.hash, 0)], [(bytes(32), claim.amount)]), #Transaction which will be beaten.
def VUnknownTest(rpc: RPC) -> None: file: IO[Any] = open("e2e/Vectors/Consensus/Verification/Parsable.json", "r") vectors: Dict[str, Any] = json.loads(file.read()) file.close() #Merit. merit: Merit = Merit.fromJSON(vectors["blockchain"]) #Custom function to send the last Block and verify it errors at the right place. def checkFail() -> None: #This Block should cause the node to disconnect us AFTER it attempts to sync our Transaction. syncedTX: bool = False #Grab the Block. block: Block = merit.blockchain.blocks[2] #Send the Block. rpc.meros.liveBlockHeader(block.header) #Handle sync requests. reqHash: bytes = bytes() while True: if syncedTX: #Try receiving from the Live socket, where Meros sends keep-alives. try: if len(rpc.meros.live.recv()) != 0: raise Exception() except TestError: raise SuccessError( "Node disconnected us after we sent a parsable, yet invalid, Verification." ) except Exception: raise TestError("Meros sent a keep-alive.") msg: bytes = rpc.meros.sync.recv() if MessageType(msg[0]) == MessageType.BlockBodyRequest: reqHash = msg[1:33] if reqHash != block.header.hash: raise TestError( "Meros asked for a Block Body that didn't belong to the Block we just sent it." ) #Send the BlockBody. rpc.meros.blockBody(block) elif MessageType(msg[0]) == MessageType.SketchHashesRequest: if not block.body.packets: raise TestError( "Meros asked for Sketch Hashes from a Block without any." ) reqHash = msg[1:33] if reqHash != block.header.hash: raise TestError( "Meros asked for Sketch Hashes that didn't belong to the Block we just sent it." ) #Create the haashes. hashes: List[int] = [] for packet in block.body.packets: hashes.append(Sketch.hash(block.header.sketchSalt, packet)) #Send the Sketch Hashes. rpc.meros.sketchHashes(hashes) elif MessageType(msg[0]) == MessageType.SketchHashRequests: if not block.body.packets: raise TestError( "Meros asked for Verification Packets from a Block without any." ) reqHash = msg[1:33] if reqHash != block.header.hash: raise TestError( "Meros asked for Verification Packets that didn't belong to the Block we just sent it." ) #Create a lookup of hash to packets. packets: Dict[int, VerificationPacket] = {} for packet in block.body.packets: packets[Sketch.hash(block.header.sketchSalt, packet)] = packet #Look up each requested packet and respond accordingly. for h in range(int.from_bytes(msg[33:37], byteorder="big")): sketchHash: int = int.from_bytes(msg[37 + (h * 8):45 + (h * 8)], byteorder="big") if sketchHash not in packets: raise TestError( "Meros asked for a non-existent Sketch Hash.") rpc.meros.packet(packets[sketchHash]) elif MessageType(msg[0]) == MessageType.TransactionRequest: rpc.meros.dataMissing() syncedTX = True else: raise TestError("Unexpected message sent: " + msg.hex().upper()) #Create and execute a Liver. Liver(rpc, vectors["blockchain"], callbacks={1: checkFail}).live()
import json from e2e.Libs.BLS import PrivateKey from e2e.Classes.Merit.Merit import Merit from e2e.Vectors.Generation.PrototypeChain import PrototypeBlock, PrototypeChain proto: PrototypeChain = PrototypeChain(1, False) merit: Merit = Merit.fromJSON(proto.finish().toJSON()) #Use up all of our Blocks with Merit, except the last one. for i in range(98): merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, minerID=(PrivateKey(1) if i == 0 else 1)).finish( 0, merit)) #Right before the end, move to pending. merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, minerID=1).finish(1, merit)) #Have our Merit die. merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200, minerID=1).finish(0, merit)) #Regain Merit. merit.add( PrototypeBlock(merit.blockchain.blocks[-1].header.time + 1200,
def TElementTest(rpc: RPC) -> None: merit: Merit = Merit() blsPrivKey: PrivateKey = PrivateKey(0) blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex() #Handshake with the node. rpc.meros.liveConnect(merit.blockchain.blocks[0].header.hash) rpc.meros.syncConnect(merit.blockchain.blocks[0].header.hash) #Send the first Block. block: Block with open("e2e/Vectors/Merit/BlankBlocks.json", "r") as file: block = Block.fromJSON(json.loads(file.read())[0]) merit.blockchain.add(block) rpc.meros.liveBlockHeader(block.header) rpc.meros.handleBlockBody(block) if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader: raise TestError( "Meros didn't broadcast the Block Header it just added.") #Create and transmit a DataDifficulty. dataDiff: SignedDataDifficulty = SignedDataDifficulty(0, 0, 0) dataDiff.sign(0, blsPrivKey) rpc.meros.signedElement(dataDiff) sleep(1.5) #Verify the block template has the DataDifficulty. template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate", {"miner": blsPubKey}) template["header"] = bytes.fromhex(template["header"]) if template["header"][36:68] != BlockHeader.createContents([], [dataDiff]): raise TestError("Block template doesn't have the Data Difficulty.") #Mine the Block. block = Block( BlockHeader( 0, block.header.hash, BlockHeader.createContents([], [dataDiff]), 0, template["header"][-43:-39], BlockHeader.createSketchCheck(template["header"][-43:-39], []), 0, int.from_bytes(template["header"][-4:], byteorder="little"), ), BlockBody([], [dataDiff], dataDiff.signature)) if block.header.serializeHash()[:-4] != template["header"]: raise TestError("Failed to recreate the header.") block.mine(blsPrivKey, merit.blockchain.difficulty()) merit.blockchain.add(block) #Publish it. rpc.call( "merit", "publishBlock", { "id": template["id"], "header": (template["header"] + block.header.proof.to_bytes(4, byteorder="little") + block.header.signature).hex() }) #Create and transmit a new DataDifficulty. dataDiff = SignedDataDifficulty(3, 0, 0) dataDiff.sign(0, blsPrivKey) rpc.meros.signedElement(dataDiff) sleep(1.5) #Verify the block template has a MeritRemoval. #Thanks to implicit Merit Removals, this just means it has the new difficulty. template = rpc.call("merit", "getBlockTemplate", {"miner": blsPubKey}) template["header"] = bytes.fromhex(template["header"]) if template["header"][36:68] != BlockHeader.createContents([], [dataDiff]): raise TestError("Block template doesn't have the Merit Removal.") #Mine the Block. block = Block( BlockHeader( 0, block.header.hash, BlockHeader.createContents([], [dataDiff]), 0, template["header"][-43:-39], BlockHeader.createSketchCheck(template["header"][-43:-39], []), 0, int.from_bytes(template["header"][-4:], byteorder="little")), BlockBody([], [dataDiff], dataDiff.signature)) if block.header.serializeHash()[:-4] != template["header"]: raise TestError("Failed to recreate the header.") block.mine(blsPrivKey, merit.blockchain.difficulty()) merit.blockchain.add(block) rpc.call( "merit", "publishBlock", { "id": template["id"], "header": (template["header"] + block.header.proof.to_bytes(4, byteorder="little") + block.header.signature).hex() }) verifyBlockchain(rpc, merit.blockchain)
#Blake2b standard function. from hashlib import blake2b #JSON standard lib. import json #Blank Blocks. bbFile: IO[Any] = open("e2e/Vectors/Merit/BlankBlocks.json", "r") blankBlocks: List[Dict[str, Any]] = json.loads(bbFile.read()) bbFile.close() #Transactions. transactions: Transactions = Transactions() #Merit. merit: Merit = Merit() #SpamFilter. dataFilter: SpamFilter = SpamFilter(5) #Ed25519 keys. edPrivKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32) edPubKey: ed25519.VerifyingKey = edPrivKey.get_verifying_key() #BLS keys. blsPrivKey: PrivateKey = PrivateKey(blake2b(b'\0', digest_size=32).digest()) blsPubKey: PublicKey = blsPrivKey.toPublicKey() #Add 1 Blank Block. for i in range(1): merit.add(Block.fromJSON(blankBlocks[i]))
from e2e.Classes.Merit.Block import BlockHeader, BlockBody, Block from e2e.Classes.Merit.Merit import Merit from e2e.Vectors.Generation.PrototypeChain import PrototypeBlock blsPrivKey: PrivateKey = PrivateKey(0) edPrivKey: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32) edPubKey: bytes = edPrivKey.get_verifying_key() dataFilter: SpamFilter = SpamFilter(5) #Create a Block to earn Merit. blocks: List[Block] = [] blocks.append(PrototypeBlock(1200, minerID=blsPrivKey).finish(0, Merit())) #Create five Datas and matching Verifications. #The test only sends a couple of the Verifications; that said, it's easy to generate the Block signature thanks to this. txs: List[Data] = [Data(bytes(32), edPubKey)] verifs: List[SignedVerification] = [] for i in range(5): txs[-1].sign(edPrivKey) txs[-1].beat(dataFilter) verifs.append(SignedVerification(txs[-1].hash)) verifs[-1].sign(0, blsPrivKey) txs.append(Data(txs[-1].hash, b"\0")) del txs[-1] #Create the final Block.