예제 #1
0
    def test_submit_work_with_guardian(self):
        now = 42
        block = RootBlock(
            RootBlockHeader(create_time=42, extra_data=b"{}", difficulty=1000))

        async def create(retry=True):
            return block

        async def add(_):
            pass

        miner = self.miner_gen(
            ConsensusType.POW_SHA3SHA3,
            create,
            add,
            remote=True,
            # fake pk, will succeed in test but fail in real world when
            # adding the block to the root chain
            guardian_private_key=ecies.generate_privkey(),
        )

        async def go():
            for i in range(42, 100):
                work = await miner.get_work(now=now)
                self.assertEqual(work.height, 0)

                # guardian: diff 1000 -> 1, any number should work
                res = await miner.submit_work(work.hash, i, sha3_256(b""))
                self.assertTrue(res)

        loop = asyncio.get_event_loop()
        loop.run_until_complete(go())
예제 #2
0
 async def create(retry=True):
     if len(self.added_blocks) >= 5:
         return None  # stop the game
     return RootBlock(
         RootBlockHeader(create_time=int(time.time())),
         tracking_data="{}".encode("utf-8"),
     )
예제 #3
0
    def test_mine_ethash_new_block_overwrite(self):
        # set a super low `rounds`, and put blocks into input queue beforehand
        # which will make miner consistently drop current block and start mining new one
        block = RootBlock(
            RootBlockHeader(
                create_time=42,  # so we have deterministic hash
                extra_data="{}".encode("utf-8"),
                difficulty=
                5,  # low probability on successful mining at first try
            ))

        async def create():
            nonlocal block
            return block

        async def add(block_to_add):
            nonlocal miner
            self.added_blocks.append(block_to_add)
            miner.input_q.put((None, {}))

        miner = self.miner_gen(ConsensusType.POW_ETHASH, create, add)
        # only one round!
        miner.get_mining_param_func = functools.partial(self.get_mining_params,
                                                        rounds=1)
        # insert 5 blocks beforehand
        for _ in range(5):
            miner.input_q.put((block, {}))
        loop = asyncio.get_event_loop()
        loop.run_until_complete(miner._mine_new_block_async())
        # will only have 1 block mined
        self.assertEqual(len(self.added_blocks), 1)
예제 #4
0
 async def create():
     nonlocal i
     if i >= 5:
         return None
     return RootBlock(
         RootBlockHeader(create_time=int(time.time()),
                         extra_data="{}".encode("utf-8")))
예제 #5
0
    def test_submit_work_with_guardian(self):
        now = 42
        doublesha = ConsensusType.POW_DOUBLESHA256
        block = RootBlock(
            RootBlockHeader(create_time=42, extra_data=b"{}", difficulty=1000))
        priv = ecies.generate_privkey()

        async def create(retry=True):
            return block

        async def add(block_to_add):
            h = block_to_add.header
            diff = h.difficulty
            if h.verify_signature(priv.public_key):
                diff = Guardian.adjust_difficulty(diff, h.height)
            validate_seal(block_to_add.header, doublesha, adjusted_diff=diff)

        miner = self.miner_gen(doublesha,
                               create,
                               add,
                               remote=True,
                               guardian_private_key=priv)

        async def go():
            for i in range(42, 100):
                work, _ = await miner.get_work(now=now)
                self.assertEqual(work.height, 0)

                # guardian: diff 1000 -> 1, any number should work
                res = await miner.submit_work(work.hash, i, sha3_256(b""))
                self.assertTrue(res)

        loop = asyncio.get_event_loop()
        loop.run_until_complete(go())
예제 #6
0
 async def create(retry=True):
     nonlocal i
     if i >= 5:
         return None
     return RootBlock(
         RootBlockHeader(create_time=int(time.time())),
         tracking_data="{}".encode("utf-8"),
     )
예제 #7
0
 async def create(**kwargs):
     nonlocal now, mock_tip
     return RootBlock(
         RootBlockHeader(
             create_time=now,
             extra_data=b"{}",
             hash_prev_block=mock_tip.get_hash(),
             height=mock_tip.height + 1,
         ))
예제 #8
0
 async def send_ping(self):
     # TODO: Send real root tip and allow shards to confirm each other
     req = Ping(
         self.slave_server.id,
         self.slave_server.shard_mask_list,
         RootBlock(RootBlockHeader()),
     )
     op, resp, rpc_id = await self.write_rpc_request(ClusterOp.PING, req)
     return (resp.id, resp.shard_mask_list)
예제 #9
0
    def test_submit_work(self):
        now, height = 42, 42
        doublesha = ConsensusType.POW_DOUBLESHA256
        mock_tip = RootBlockHeader(height=height)
        block = RootBlock(
            RootBlockHeader(create_time=42, extra_data=b"{}", difficulty=5))

        async def create(coinbase_addr=None, retry=True):
            nonlocal block, mock_tip
            ret = copy.deepcopy(block)
            ret.header.height = mock_tip.height + 1
            ret.header.hash_prev_block = mock_tip.get_hash()
            return ret

        async def add(block_to_add):
            validate_seal(block_to_add.header, doublesha)
            self.added_blocks.append(block_to_add)

        def tip_getter():
            nonlocal mock_tip
            return mock_tip

        miner = self.miner_gen(doublesha, create, add, tip_getter, remote=True)

        async def go():
            nonlocal mock_tip
            work, _ = await miner.get_work(EMPTY_ADDR, now=now)
            self.assertEqual(work.height, 43)
            self.assertEqual(work.difficulty, 5)
            # submitted block doesn't exist
            res = await miner.submit_work(b"lolwut", 0, sha3_256(b""))
            self.assertFalse(res)

            solver = DoubleSHA256(work)
            sol = solver.mine(200, 300).nonce
            self.assertGreater(sol, 200)  # ensure non-solution is tried
            non_sol = sol - 1
            # invalid pow proof
            res = await miner.submit_work(work.hash, non_sol, sha3_256(b""))
            self.assertFalse(res)
            # valid submission, but tip updated so should fail
            mock_tip.height += 1
            res = await miner.submit_work(work.hash, sol, sha3_256(b""))
            self.assertFalse(res)
            self.assertEqual(miner.work_map, {})
            # bring tip back and regenerate the work
            mock_tip.height -= 1
            work, _ = await miner.get_work(EMPTY_ADDR, now=now)
            # valid submission, also check internal state afterwards
            res = await miner.submit_work(work.hash, sol, sha3_256(b""))
            self.assertTrue(res)
            self.assertEqual(miner.work_map, {})
            self.assertEqual(len(self.added_blocks), 1)

        loop = asyncio.get_event_loop()
        loop.run_until_complete(go())
예제 #10
0
 def create_root_block(self) -> RootBlock:
     """ Create the genesis root block """
     genesis = self._qkc_config.ROOT.GENESIS
     header = RootBlockHeader(
         version=genesis.VERSION,
         height=genesis.HEIGHT,
         hash_prev_block=bytes.fromhex(genesis.HASH_PREV_BLOCK),
         hash_merkle_root=bytes.fromhex(genesis.HASH_MERKLE_ROOT),
         create_time=genesis.TIMESTAMP,
         difficulty=genesis.DIFFICULTY,
     )
     return RootBlock(header=header, minor_block_header_list=[])
예제 #11
0
 def test_sha3sha3(self):
     miner = self.miner_gen(ConsensusType.POW_SHA3SHA3, None, None)
     block = RootBlock(
         RootBlockHeader(create_time=42,
                         extra_data="{}".encode("utf-8"),
                         difficulty=5))
     # only process one block, which is passed in
     miner.input_q.put((None, {}))
     miner.mine_sha3sha3(block, miner.input_q, miner.output_q, {})
     mined_block = miner.output_q.get()
     self.assertEqual(mined_block.header.nonce, 3)
     validate_seal(mined_block.header, ConsensusType.POW_SHA3SHA3)
예제 #12
0
    def test_submit_work_with_remote_guardian(self):
        now = 42
        doublesha = ConsensusType.POW_DOUBLESHA256
        block = RootBlock(
            RootBlockHeader(
                create_time=42,
                extra_data=b"{}",
                difficulty=1000,
                hash_prev_block=RootBlockHeader().get_hash(),
            ))
        priv = ecies.generate_privkey()

        async def create(coinbase_addr=None, retry=True):
            return block

        async def add(block_to_add):
            h = block_to_add.header
            diff = h.difficulty

            if h.verify_signature(priv.public_key):
                diff = Guardian.adjust_difficulty(diff, h.height)

            validate_seal(block_to_add.header, doublesha, adjusted_diff=diff)

        # just with the guardian public key
        miner = self.miner_gen(doublesha, create, add, remote=True)

        async def go():
            for i in range(42, 100):
                work, _ = await miner.get_work(EMPTY_ADDR, now=now)
                self.assertEqual(work.height, 0)

                # remote guardian: diff 1000 -> 1, any number should work
                # mimic the sign process of the remote guardian server
                block.header.nonce = i
                block.header.mixhash = sha3_256(b"")
                block.header.sign_with_private_key(priv)
                signature = block.header.signature

                # reset the signature to the default value
                block.header.signature = bytes(65)
                # submit the signature through the submit work
                res = await miner.submit_work(work.hash, i, sha3_256(b""),
                                              signature)
                self.assertTrue(res)
                res = await miner.submit_work(work.hash, i, sha3_256(b""),
                                              bytes(65))
                self.assertFalse(res)

        loop = asyncio.get_event_loop()
        loop.run_until_complete(go())
예제 #13
0
    def test_validate_seal_with_adjusted_diff(self):
        diff = 1000
        block = RootBlock(
            RootBlockHeader(create_time=42, difficulty=diff),
            tracking_data="{}".encode("utf-8"),
        )
        block.header.nonce = 0
        with self.assertRaises(ValueError):
            validate_seal(block.header, ConsensusType.POW_DOUBLESHA256)

        # significantly lowering the diff should pass
        validate_seal(block.header,
                      ConsensusType.POW_DOUBLESHA256,
                      adjusted_diff=1)
예제 #14
0
 def test_sha3sha3(self):
     miner = self.miner_gen(ConsensusType.POW_SHA3SHA3, None, None)
     block = RootBlock(
         RootBlockHeader(create_time=42, difficulty=5),
         tracking_data="{}".encode("utf-8"),
     )
     work = MiningWork(block.header.get_hash_for_mining(), 42, 5)
     # only process one block, which is passed in. `None` means termination right after
     miner.input_q.put((None, {}))
     miner._mine_loop(
         ConsensusType.POW_SHA3SHA3, work, {}, miner.input_q, miner.output_q
     )
     mined_res = miner.output_q.get()
     self.assertEqual(mined_res.nonce, 8)
     block.header.nonce = mined_res.nonce
     validate_seal(block.header, ConsensusType.POW_SHA3SHA3)
예제 #15
0
 def test_qkchash(self):
     miner = self.miner_gen(ConsensusType.POW_QKCHASH, None, None)
     block = RootBlock(
         RootBlockHeader(create_time=42, difficulty=5),
         tracking_data="{}".encode("utf-8"),
     )
     work = MiningWork(block.header.get_hash_for_mining(), 42, 5)
     # only process one block, which is passed in. `None` means termination right after
     miner.input_q.put((None, {}))
     miner.mine_loop(
         work,
         {"consensus_type": ConsensusType.POW_QKCHASH},
         miner.input_q,
         miner.output_q,
     )
     mined_res = miner.output_q.get()
     block.header.nonce = mined_res.nonce
     block.header.mixhash = mined_res.mixhash
     validate_seal(block.header, ConsensusType.POW_QKCHASH)
예제 #16
0
    def test_submit_work(self):
        now = 42
        block = RootBlock(
            RootBlockHeader(create_time=42, extra_data=b"{}", difficulty=2))

        async def create():
            return block

        async def add(block_to_add):
            self.added_blocks.append(block_to_add)

        miner = self.miner_gen(ConsensusType.POW_SHA3SHA3,
                               create,
                               add,
                               remote=True)

        async def go():
            work = await miner.get_work(now=now)
            self.assertEqual(work.height, 0)
            self.assertEqual(work.difficulty, 2)
            # submitted block doesn't exist
            res = await miner.submit_work(b"lolwut", 0, sha3_256(b""))
            self.assertFalse(res)

            solver = DoubleSHA256(block)
            mined = solver.mine(100, 200)
            self.assertTrue(mined)
            sol = int.from_bytes(solver.nonce_found, byteorder="big")
            self.assertGreater(sol, 100)  # ensure non-solution is tried
            non_sol = sol - 1
            # invalid pow proof
            res = await miner.submit_work(work.hash, non_sol, sha3_256(b""))
            self.assertFalse(res)
            # valid submission, also check internal state afterwards
            res = await miner.submit_work(work.hash, sol, sha3_256(b""))
            self.assertTrue(res)
            self.assertEqual(miner.work_map, {})
            self.assertEqual(len(self.added_blocks), 1)
            self.assertIsNone(miner.current_work)

        loop = asyncio.get_event_loop()
        loop.run_until_complete(go())
예제 #17
0
    def test_submit_work(self):
        now = 42
        doublesha = ConsensusType.POW_DOUBLESHA256
        block = RootBlock(
            RootBlockHeader(create_time=42, extra_data=b"{}", difficulty=5))

        async def create(retry=True):
            return block

        async def add(block_to_add):
            validate_seal(block_to_add.header, doublesha)
            self.added_blocks.append(block_to_add)

        miner = self.miner_gen(doublesha, create, add, remote=True)

        async def go():
            work, _ = await miner.get_work(now=now)
            self.assertEqual(work.height, 0)
            self.assertEqual(work.difficulty, 5)
            # submitted block doesn't exist
            res = await miner.submit_work(b"lolwut", 0, sha3_256(b""))
            self.assertFalse(res)

            solver = DoubleSHA256(work)
            sol = solver.mine(200, 300).nonce
            self.assertGreater(sol, 200)  # ensure non-solution is tried
            non_sol = sol - 1
            # invalid pow proof
            res = await miner.submit_work(work.hash, non_sol, sha3_256(b""))
            self.assertFalse(res)
            # valid submission, also check internal state afterwards
            res = await miner.submit_work(work.hash, sol, sha3_256(b""))
            self.assertTrue(res)
            self.assertEqual(miner.work_map, {})
            self.assertEqual(len(self.added_blocks), 1)
            self.assertIsNone(miner.current_work)

        loop = asyncio.get_event_loop()
        loop.run_until_complete(go())
예제 #18
0
 async def dummy_create_block_async() -> Optional[RootBlock]:
     if len(TestMiner.added_blocks) >= 5:
         return None  # stop the game
     return RootBlock(RootBlockHeader(create_time=int(time.time()), extra_data="{}".encode("utf-8")))
예제 #19
0
 async def create(retry=True):
     nonlocal now
     return RootBlock(RootBlockHeader(create_time=now,
                                      extra_data=b"{}"))