예제 #1
0
    def test_broadcast_cross_shard_transactions_to_neighbor_only(self):
        """ Test the broadcast is only done to the neighbors """
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        # create 64 shards so that the neighbor rule can kick in
        # explicitly set num_slaves to 4 so that it does not spin up 64 slaves
        with ClusterContext(1, acc1, shard_size=64, num_slaves=4) as clusters:
            master = clusters[0].master

            # Add a root block first so that later minor blocks referring to this root
            # can be broadcasted to other shards
            root_block = call_async(
                master.get_next_block_to_mine(Address.create_empty_account(),
                                              branch_value=None))
            call_async(master.add_root_block(root_block))

            b1 = clusters[0].get_shard_state(64).create_block_to_mine(
                address=acc1)
            self.assertTrue(
                call_async(
                    master.add_raw_minor_block(b1.header.branch,
                                               b1.serialize())))

            neighbor_shards = [2**i for i in range(6)]
            for shard_id in range(64):
                xshard_tx_list = (clusters[0].get_shard_state(
                    64 | shard_id).db.get_minor_block_xshard_tx_list(
                        b1.header.get_hash()))
                # Only neighbor should have it
                if shard_id in neighbor_shards:
                    self.assertIsNotNone(xshard_tx_list)
                else:
                    self.assertIsNone(xshard_tx_list)
예제 #2
0
    def test_getCode(self):
        key = bytes.fromhex(
            "c987d4506fb6824639f9a9e3b8834584f5165e94680501d1b0044071cd36c3b3"
        )
        id1 = Identity.create_from_key(key)
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        created_addr = "0x8531eb33bba796115f56ffa1b7df1ea3acdd8cdd00000000"

        with ClusterContext(
            1, acc1, small_coinbase=True
        ) as clusters, jrpc_server_context(clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            tx = create_contract_with_storage_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_key=acc1.full_shard_key,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            _, block = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(call_async(clusters[0].get_shard(2 | 0).add_block(block)))

            for using_eth_endpoint in (True, False):
                if using_eth_endpoint:
                    resp = send_request("eth_getCode", created_addr[:-8], "0x0")
                else:
                    resp = send_request("getCode", created_addr)

                self.assertEqual(
                    resp,
                    "0x6080604052600080fd00a165627a7a72305820a6ef942c101f06333ac35072a8ff40332c71d0e11cd0e6d86de8cae7b42696550029",
                )
예제 #3
0
    def test_sendTransaction_with_bad_signature(self):
        """ sendTransaction validates signature """
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=1)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master

            block = call_async(
                master.get_next_block_to_mine(address=acc2, branch_value=None))
            call_async(master.add_root_block(block))

            request = dict(
                to="0x" + acc2.recipient.hex(),
                gasPrice="0x6",
                gas=hex(30000),
                value="0xf",
                v="0x1",
                r="0x2",
                s="0x3",
                nonce="0x0",
                fromFullShardKey="0x00000000",
                toFullShardKey="0x00000001",
            )
            self.assertEqual(send_request("sendTransaction", [request]),
                             EMPTY_TX_ID)
            self.assertEqual(len(clusters[0].get_shard_state(2 | 0).tx_queue),
                             0)
예제 #4
0
    def test_getTransactionReceipt_on_transfer(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        with ClusterContext(1, acc1) as clusters, jrpc_server_context(
                clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(2, 0)
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            _, block1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(
                call_async(clusters[0].get_shard(0).add_block(block1)))

            for endpoint in ("getTransactionReceipt",
                             "eth_getTransactionReceipt"):
                resp = send_request(
                    endpoint,
                    "0x" + tx.get_hash().hex() +
                    acc1.full_shard_id.to_bytes(4, "big").hex(),
                )
                self.assertEqual(resp["transactionHash"],
                                 "0x" + tx.get_hash().hex())
                self.assertEqual(resp["status"], "0x1")
                self.assertEqual(resp["cumulativeGasUsed"], "0x5208")
                self.assertIsNone(resp["contractAddress"])
예제 #5
0
    def test_createTransactions(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=1)

        loadtest_accounts = [
            {
                "address": "b067ac9ebeeecb10bbcd1088317959d58d1e38f6b0ee10d5",
                "key": "ca0143c9aa51c3013f08e83f3b6368a4f3ba5b52c4841c6e0c22c300f7ee6827",
            },
            {
                "address": "9f2b984937ff8e3f20d2a2592f342f47257870909fffa247",
                "key": "40efdb8528de149c35fb43a572fc821d8fbdf2469dcc7fe1a9e847ef29e3c941",
            },
        ]

        with ClusterContext(
            1, acc1, small_coinbase=True, loadtest_accounts=loadtest_accounts
        ) as clusters, jrpc_server_context(clusters[0].master):
            slaves = clusters[0].slave_list
            master = clusters[0].master

            block = call_async(
                master.get_next_block_to_mine(address=acc2, branch_value=None)
            )
            call_async(master.add_root_block(block))

            send_request("createTransactions", {"numTxPerShard": 1, "xShardPercent": 0})
예제 #6
0
    def test_sendTransaction_missing_from_full_shard_key(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master

            block = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=None))
            call_async(master.add_root_block(block))

            request = dict(
                to="0x" + acc1.recipient.hex(),
                gasPrice="0x6",
                gas=hex(30000),
                value="0xf",
                v="0x1",
                r="0x2",
                s="0x3",
                nonce="0x0",
            )

            with self.assertRaises(Exception):
                send_request("sendTransaction", [request])
예제 #7
0
    def test_gasPrice(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(2, 0)
            # run for multiple times
            for _ in range(3):
                tx = create_transfer_transaction(
                    shard_state=slaves[0].shards[branch].state,
                    key=id1.get_key(),
                    from_address=acc1,
                    to_address=acc1,
                    value=0,
                    gas_price=12,
                )
                self.assertTrue(slaves[0].add_tx(tx))

                _, block = call_async(
                    master.get_next_block_to_mine(address=acc1))
                self.assertTrue(
                    call_async(clusters[0].get_shard(0).add_block(block)))

            for using_eth_endpoint in (True, False):
                if using_eth_endpoint:
                    resp = send_request("eth_gasPrice", "0x0")
                else:
                    resp = send_request("gasPrice", "0x0")

                self.assertEqual(resp, "0xc")
예제 #8
0
    def test_getTransactionById(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        with ClusterContext(1, acc1) as clusters, jrpc_server_context(
                clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(2, 0)
            self.assertEqual(
                call_async(
                    master.get_primary_account_data(acc1)).transaction_count,
                0)
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            _, block1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(
                call_async(clusters[0].get_shard(0).add_block(block1)))

            resp = send_request(
                "getTransactionById",
                "0x" + tx.get_hash().hex() +
                acc1.full_shard_id.to_bytes(4, "big").hex(),
            )
            self.assertEqual(resp["hash"], "0x" + tx.get_hash().hex())
예제 #9
0
    def test_getMinorBlock(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
            1, acc1, small_coinbase=True
        ) as clusters, jrpc_server_context(clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            self.assertEqual(
                call_async(master.get_primary_account_data(acc1)).transaction_count, 0
            )
            tx = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            _, block1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(call_async(clusters[0].get_shard(2 | 0).add_block(block1)))

            # By id
            resp = send_request(
                "getMinorBlockById",
                "0x" + block1.header.get_hash().hex() + "0" * 8,
                False,
            )
            self.assertEqual(
                resp["transactions"][0], "0x" + tx.get_hash().hex() + "00000002"
            )
            resp = send_request(
                "getMinorBlockById",
                "0x" + block1.header.get_hash().hex() + "0" * 8,
                True,
            )
            self.assertEqual(
                resp["transactions"][0]["hash"], "0x" + tx.get_hash().hex()
            )

            resp = send_request("getMinorBlockById", "0x" + "ff" * 36, True)
            self.assertIsNone(resp)

            # By height
            resp = send_request("getMinorBlockByHeight", "0x0", "0x1", False)
            self.assertEqual(
                resp["transactions"][0], "0x" + tx.get_hash().hex() + "00000002"
            )
            resp = send_request("getMinorBlockByHeight", "0x0", "0x1", True)
            self.assertEqual(
                resp["transactions"][0]["hash"], "0x" + tx.get_hash().hex()
            )

            resp = send_request("getMinorBlockByHeight", "0x1", "0x2", False)
            self.assertIsNone(resp)
            resp = send_request("getMinorBlockByHeight", "0x0", "0x4", False)
            self.assertIsNone(resp)
예제 #10
0
    def test_get_primary_account_data(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)
        acc2 = Address.create_random_account(full_shard_id=1)

        with ClusterContext(1, acc1) as clusters:
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(2, 0)
            self.assertEqual(
                call_async(master.get_primary_account_data(acc1)).transaction_count, 0
            )
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            is_root, block1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(
                call_async(
                    master.add_raw_minor_block(block1.header.branch, block1.serialize())
                )
            )

            self.assertEqual(
                call_async(master.get_primary_account_data(acc1)).transaction_count, 1
            )
            self.assertEqual(
                call_async(master.get_primary_account_data(acc2)).transaction_count, 0
            )
예제 #11
0
    def test_shard_synchronizer_with_fork(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(2, acc1) as clusters:
            # shutdown cluster connection
            clusters[1].peer.close()

            block_list = []
            # cluster 0 has 13 blocks added
            shard_state0 = clusters[0].get_shard_state(0b10)
            for i in range(13):
                block = _tip_gen(shard_state0)
                add_result = call_async(clusters[0].master.add_raw_minor_block(
                    block.header.branch, block.serialize()))
                self.assertTrue(add_result)
                block_list.append(block)
            self.assertEqual(
                clusters[0].get_shard_state(0b10).header_tip.height, 13)

            # cluster 1 has 12 blocks added
            shard_state0 = clusters[1].get_shard_state(0b10)
            for i in range(12):
                block = _tip_gen(shard_state0)
                add_result = call_async(clusters[1].master.add_raw_minor_block(
                    block.header.branch, block.serialize()))
                self.assertTrue(add_result)
            self.assertEqual(
                clusters[1].get_shard_state(0b10).header_tip.height, 12)

            # reestablish cluster connection
            call_async(clusters[1].network.connect(
                "127.0.0.1",
                clusters[0].master.env.cluster_config.SIMPLE_NETWORK.
                BOOTSTRAP_PORT,
            ))

            # a new block from cluster 0 will trigger sync in cluster 1
            shard_state0 = clusters[0].get_shard_state(0b10)
            block = _tip_gen(shard_state0)
            add_result = call_async(clusters[0].master.add_raw_minor_block(
                block.header.branch, block.serialize()))
            self.assertTrue(add_result)
            block_list.append(block)

            # expect cluster 1 has all the blocks from cluter 0 and
            # has the same tip as cluster 0
            for block in block_list:
                assert_true_with_timeout(
                    lambda: clusters[1].slave_list[0].shards[Branch(0b10)].
                    state.contain_block_by_hash(block.header.get_hash()))
                assert_true_with_timeout(
                    lambda: clusters[1].master.root_state.db.
                    contain_minor_block_by_hash(block.header.get_hash()))

            self.assertEqual(
                clusters[1].get_shard_state(0b10).header_tip,
                clusters[0].get_shard_state(0b10).header_tip,
            )
예제 #12
0
    def test_getStorageAt(self):
        key = bytes.fromhex(
            "c987d4506fb6824639f9a9e3b8834584f5165e94680501d1b0044071cd36c3b3"
        )
        id1 = Identity.create_from_key(key)
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        created_addr = "0x8531eb33bba796115f56ffa1b7df1ea3acdd8cdd00000000"

        with ClusterContext(
            1, acc1, small_coinbase=True
        ) as clusters, jrpc_server_context(clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            tx = create_contract_with_storage_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_key=acc1.full_shard_key,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            block = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=0b10)
            )
            self.assertTrue(call_async(clusters[0].get_shard(2 | 0).add_block(block)))

            for using_eth_endpoint in (True, False):
                if using_eth_endpoint:
                    req = lambda k: send_request(
                        "eth_getStorageAt", created_addr[:-8], k, "0x0"
                    )
                else:
                    req = lambda k: send_request("getStorageAt", created_addr, k)

                # first storage
                response = req("0x0")
                # equals 1234
                self.assertEqual(
                    response,
                    "0x00000000000000000000000000000000000000000000000000000000000004d2",
                )

                # mapping storage
                k = sha3_256(
                    bytes.fromhex(acc1.recipient.hex().zfill(64) + "1".zfill(64))
                )
                response = req("0x" + k.hex())
                self.assertEqual(
                    response,
                    "0x000000000000000000000000000000000000000000000000000000000000162e",
                )

                # doesn't exist
                response = req("0x3")
                self.assertEqual(
                    response,
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                )
예제 #13
0
    def test_getTransactionReceipt_on_x_shard_transfer(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_from_identity(id1, full_shard_key=1)

        with ClusterContext(
            1, acc1, small_coinbase=True
        ) as clusters, jrpc_server_context(clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            is_root, block = call_async(master.get_next_block_to_mine(address=acc2))
            self.assertTrue(is_root)
            call_async(master.add_root_block(block))

            s1, s2 = (
                clusters[0].get_shard_state(2 | 0),
                clusters[0].get_shard_state(2 | 1),
            )
            tx_gen = lambda s, f, t: create_transfer_transaction(
                shard_state=s,
                key=id1.get_key(),
                from_address=f,
                to_address=t,
                gas=21000 if f == t else 30000,
                value=12345,
            )
            self.assertTrue(slaves[0].add_tx(tx_gen(s1, acc1, acc2)))
            _, b1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(call_async(clusters[0].get_shard(2 | 0).add_block(b1)))

            _, root_block = call_async(
                master.get_next_block_to_mine(address=acc1, prefer_root=True)
            )

            call_async(master.add_root_block(root_block))

            tx = tx_gen(s2, acc2, acc2)
            self.assertTrue(slaves[0].add_tx(tx))
            _, b3 = call_async(master.get_next_block_to_mine(address=acc2))
            self.assertTrue(call_async(clusters[0].get_shard(2 | 1).add_block(b3)))

            # in-shard tx 21000 + receiving x-shard tx 9000
            self.assertEqual(s2.evm_state.gas_used, 30000)
            self.assertEqual(s2.evm_state.xshard_receive_gas_used, 9000)

            for endpoint in ("getTransactionReceipt", "eth_getTransactionReceipt"):
                resp = send_request(
                    endpoint,
                    "0x"
                    + tx.get_hash().hex()
                    + acc2.full_shard_key.to_bytes(4, "big").hex(),
                )
                self.assertEqual(resp["transactionHash"], "0x" + tx.get_hash().hex())
                self.assertEqual(resp["status"], "0x1")
                self.assertEqual(resp["cumulativeGasUsed"], hex(30000))
                self.assertEqual(resp["gasUsed"], hex(21000))
                self.assertIsNone(resp["contractAddress"])
예제 #14
0
    def test_create_shard_at_different_height(self):
        acc1 = Address.create_random_account()
        with ClusterContext(1, acc1, genesis_root_heights=[1, 2]) as clusters:
            master = clusters[0].master
            slaves = clusters[0].slave_list

            self.assertEqual(len(slaves[0].shards), 0)
            self.assertEqual(len(slaves[1].shards), 0)

            is_root, root = call_async(master.get_next_block_to_mine(acc1))
            self.assertTrue(is_root)
            self.assertEqual(len(root.minor_block_header_list), 0)
            call_async(master.add_root_block(root))

            # shard 0 created at root height 1
            self.assertEqual(len(slaves[0].shards), 1)
            self.assertEqual(len(slaves[1].shards), 0)

            is_root, root = call_async(master.get_next_block_to_mine(acc1))
            self.assertTrue(is_root)
            self.assertEqual(len(root.minor_block_header_list), 1)
            call_async(master.add_root_block(root))

            self.assertEqual(len(slaves[0].shards), 1)
            # shard 1 created at root height 2
            self.assertEqual(len(slaves[1].shards), 1)

            is_root, block = call_async(master.get_next_block_to_mine(acc1))
            self.assertTrue(is_root)
            self.assertEqual(len(root.minor_block_header_list), 1)
            call_async(master.add_root_block(root))
예제 #15
0
    def test_getWork_and_submitWork(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        with ClusterContext(
                1, acc1, remote_mining=True, shard_size=1,
                small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(1, 0)
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=0,
                gas_price=12,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            for shard_id in ["0x0", None]:  # shard, then root
                resp = send_request("getWork", shard_id)
                self.assertEqual(resp[1:], ["0x1", "0xa"])  # height and diff

                header_hash_hex = resp[0]
                if shard_id is not None:  # shard 0
                    miner_address = Address.create_from(
                        master.env.quark_chain_config.SHARD_LIST[0].
                        COINBASE_ADDRESS)
                else:  # root
                    miner_address = Address.create_from(
                        master.env.quark_chain_config.ROOT.COINBASE_ADDRESS)
                _, block = call_async(
                    master.get_next_block_to_mine(
                        address=miner_address, prefer_root=shard_id is None))
                self.assertEqual(header_hash_hex[2:],
                                 block.header.get_hash_for_mining().hex())
                # solve it and submit
                work = MiningWork(bytes.fromhex(resp[0][2:]), 1, 10)
                solver = DoubleSHA256(work)
                nonce = solver.mine(0, 10000).nonce
                mixhash = "0x" + sha3_256(b"").hex()
                resp = send_request("submitWork", shard_id, header_hash_hex,
                                    hex(nonce), mixhash)
                self.assertTrue(resp)

            # show progress on shard 0
            _, new_block = call_async(
                master.get_next_block_to_mine(address=acc1))
            self.assertIsInstance(new_block, MinorBlock)
            self.assertEqual(new_block.header.height, 2)
예제 #16
0
    def test_getTransactionCount(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=1)

        with ClusterContext(
            1, acc1, small_coinbase=True
        ) as clusters, jrpc_server_context(clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            self.assertEqual(
                call_async(master.get_primary_account_data(acc1)).transaction_count, 0
            )
            for i in range(3):
                tx = create_transfer_transaction(
                    shard_state=clusters[0].get_shard_state(2 | 0),
                    key=id1.get_key(),
                    from_address=acc1,
                    to_address=acc1,
                    value=12345,
                )
                self.assertTrue(slaves[0].add_tx(tx))

                block = call_async(
                    master.get_next_block_to_mine(address=acc1, branch_value=0b10)
                )
                self.assertEqual(i + 1, block.header.height)
                self.assertTrue(
                    call_async(clusters[0].get_shard(2 | 0).add_block(block))
                )

            response = send_request(
                "getTransactionCount", "0x" + acc2.serialize().hex()
            )
            self.assertEqual(response, "0x0")

            response = send_request(
                "getTransactionCount", "0x" + acc1.serialize().hex()
            )
            self.assertEqual(response, "0x3")
            response = send_request(
                "getTransactionCount", "0x" + acc1.serialize().hex(), "latest"
            )
            self.assertEqual(response, "0x3")

            for i in range(3):
                response = send_request(
                    "getTransactionCount", "0x" + acc1.serialize().hex(), hex(i + 1)
                )
                self.assertEqual(response, hex(i + 1))
예제 #17
0
    def test_sendTransaction(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_random_account(full_shard_key=1)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            slaves = clusters[0].slave_list
            master = clusters[0].master

            block = call_async(
                master.get_next_block_to_mine(address=acc2, branch_value=None))
            call_async(master.add_root_block(block))

            evm_tx = EvmTransaction(
                nonce=0,
                gasprice=6,
                startgas=30000,
                to=acc2.recipient,
                value=15,
                data=b"",
                from_full_shard_key=acc1.full_shard_key,
                to_full_shard_key=acc2.full_shard_key,
                network_id=slaves[0].env.quark_chain_config.NETWORK_ID,
                gas_token_id=master.env.quark_chain_config.genesis_token,
                transfer_token_id=master.env.quark_chain_config.genesis_token,
            )
            evm_tx.sign(id1.get_key())
            request = dict(
                to="0x" + acc2.recipient.hex(),
                gasPrice="0x6",
                gas=hex(30000),
                value="0xf",  # 15
                v=quantity_encoder(evm_tx.v),
                r=quantity_encoder(evm_tx.r),
                s=quantity_encoder(evm_tx.s),
                nonce="0x0",
                fromFullShardKey="0x00000000",
                toFullShardKey="0x00000001",
                network_id=hex(slaves[0].env.quark_chain_config.NETWORK_ID),
            )
            tx = TypedTransaction(SerializedEvmTransaction.from_evm_tx(evm_tx))
            response = send_request("sendTransaction", [request])

            self.assertEqual(response, "0x" + tx.get_hash().hex() + "00000000")
            state = clusters[0].get_shard_state(2 | 0)
            self.assertEqual(len(state.tx_queue), 1)
            self.assertEqual(
                state.tx_queue.pop_transaction(state.get_transaction_count),
                evm_tx)
예제 #18
0
    def test_add_minor_block_request_list(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(2, acc1) as clusters:
            shard_state = clusters[0].slave_list[0].shards[Branch(0b10)].state
            coinbase_amount = (shard_state.env.quark_chain_config.shards[
                shard_state.full_shard_id].COINBASE_AMOUNT // 2)
            b1 = shard_state.get_tip().create_block_to_append()
            evm_state = shard_state.run_block(b1)
            b1.finalize(
                evm_state=evm_state,
                coinbase_amount=evm_state.block_fee + coinbase_amount,
            )
            add_result = call_async(clusters[0].master.add_raw_minor_block(
                b1.header.branch, b1.serialize()))
            self.assertTrue(add_result)

            # Make sure the xshard list is not broadcasted to the other shard
            self.assertFalse(clusters[0].slave_list[1].shards[Branch(
                0b11)].state.contain_remote_minor_block_hash(
                    b1.header.get_hash()))
            self.assertTrue(
                clusters[0].master.root_state.is_minor_block_validated(
                    b1.header.get_hash()))

            # Make sure another cluster received the new block
            assert_true_with_timeout(
                lambda: clusters[1].slave_list[0].shards[Branch(
                    0b10)].state.contain_block_by_hash(b1.header.get_hash()))
            assert_true_with_timeout(
                lambda: clusters[1].master.root_state.is_minor_block_validated(
                    b1.header.get_hash()))
예제 #19
0
def send_request(*args):
    async def __send_request(*args):
        async with aiohttp.ClientSession(loop=asyncio.get_event_loop()) as session:
            client = aiohttpClient(session, "http://localhost:38391")
            response = await client.request(*args)
            return response

    return call_async(__send_request(*args))
예제 #20
0
    def test_get_work_from_slave(self):
        genesis = Address.create_empty_account(full_shard_key=0)

        with ClusterContext(1, genesis, remote_mining=True) as clusters:
            slaves = clusters[0].slave_list

            # no posw
            state = clusters[0].get_shard_state(2 | 0)
            branch = state.create_block_to_mine().header.branch
            work = call_async(slaves[0].get_work(branch))
            self.assertEqual(work.difficulty, 10)

            # enable posw, with total stakes equal genesis balance
            state.shard_config.POSW_CONFIG.ENABLED = True
            state.shard_config.POSW_CONFIG.TOTAL_STAKE_PER_BLOCK = 1000000
            work = call_async(slaves[0].get_work(branch))
            self.assertEqual(work.difficulty, 0)
예제 #21
0
    def test_add_transaction(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_from_identity(id1, full_shard_key=1)

        with ClusterContext(2, acc1) as clusters:
            master = clusters[0].master

            root = call_async(
                master.get_next_block_to_mine(acc1, branch_value=None))
            call_async(master.add_root_block(root))

            tx1 = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(0b10),
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(call_async(master.add_transaction(tx1)))
            self.assertEqual(len(clusters[0].get_shard_state(0b10).tx_queue),
                             1)

            branch1 = Branch(2 | 1)
            tx2 = create_transfer_transaction(
                shard_state=clusters[0].get_shard_state(0b11),
                key=id1.get_key(),
                from_address=acc2,
                to_address=acc1,
                value=12345,
                gas=30000,
            )
            self.assertTrue(call_async(master.add_transaction(tx2)))
            self.assertEqual(len(clusters[0].get_shard_state(0b11).tx_queue),
                             1)

            # check the tx is received by the other cluster
            tx_queue = clusters[1].get_shard_state(0b10).tx_queue
            assert_true_with_timeout(lambda: len(tx_queue) == 1)
            self.assertEqual(tx_queue.pop_transaction(), tx1.tx.to_evm_tx())

            tx_queue = clusters[1].get_shard_state(0b11).tx_queue
            assert_true_with_timeout(lambda: len(tx_queue) == 1)
            self.assertEqual(tx_queue.pop_transaction(), tx2.tx.to_evm_tx())
예제 #22
0
    def test_add_transaction(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)
        acc2 = Address.create_from_identity(id1, full_shard_key=1)

        with ClusterContext(2, acc1) as clusters:
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch0 = Branch(2)
            tx1 = create_transfer_transaction(
                shard_state=slaves[0].shards[branch0].state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=12345,
            )
            self.assertTrue(call_async(master.add_transaction(tx1)))
            self.assertEqual(len(slaves[0].shards[branch0].state.tx_queue), 1)

            branch1 = Branch(2 | 1)
            tx2 = create_transfer_transaction(
                shard_state=slaves[1].shards[branch1].state,
                key=id1.get_key(),
                from_address=acc2,
                to_address=acc1,
                value=12345,
                gas=30000,
            )
            self.assertTrue(call_async(master.add_transaction(tx2)))
            self.assertEqual(len(slaves[1].shards[branch1].state.tx_queue), 1)

            # check the tx is received by the other cluster
            tx_queue = clusters[1].slave_list[0].shards[branch0].state.tx_queue
            assert_true_with_timeout(lambda: len(tx_queue) == 1)
            self.assertEqual(tx_queue.pop_transaction(),
                             tx1.code.get_evm_transaction())

            tx_queue = clusters[1].slave_list[1].shards[branch1].state.tx_queue
            assert_true_with_timeout(lambda: len(tx_queue) == 1)
            self.assertEqual(tx_queue.pop_transaction(),
                             tx2.code.get_evm_transaction())
예제 #23
0
    def test_getTransactionReceipt_on_contract_creation_failure(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            # Add a root block to update block gas limit for xshard tx throttling
            # so that the following tx can be processed
            is_root, root_block = call_async(
                master.get_next_block_to_mine(acc1))
            self.assertTrue(is_root)
            call_async(master.add_root_block(root_block))

            branch = Branch.create(2, 0)
            to_full_shard_id = (acc1.full_shard_id + 1
                                )  # x-shard contract creation should fail
            tx = create_contract_creation_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_id=to_full_shard_id,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            _, block1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(
                call_async(clusters[0].get_shard(0).add_block(block1)))

            for endpoint in ("getTransactionReceipt",
                             "eth_getTransactionReceipt"):
                resp = send_request(
                    endpoint,
                    "0x" + tx.get_hash().hex() + branch.serialize().hex())
                self.assertEqual(resp["transactionHash"],
                                 "0x" + tx.get_hash().hex())
                self.assertEqual(resp["status"], "0x0")
                self.assertEqual(resp["cumulativeGasUsed"], "0x13d6c")
                self.assertIsNone(resp["contractAddress"])
예제 #24
0
    def test_new_block_pool(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(1, acc1) as clusters:
            shard_state = clusters[0].get_shard_state(0b10)
            b1 = _tip_gen(shard_state)
            add_result = call_async(clusters[0].master.add_raw_minor_block(
                b1.header.branch, b1.serialize()))
            self.assertTrue(add_result)

            # Update config to force checking diff
            clusters[
                0].master.env.quark_chain_config.SKIP_MINOR_DIFFICULTY_CHECK = False
            b2 = b1.create_block_to_append(difficulty=12345)
            shard = clusters[0].slave_list[0].shards[b2.header.branch]
            with self.assertRaises(ValueError):
                call_async(shard.handle_new_block(b2))
            # Also the block should not exist in new block pool
            self.assertTrue(
                b2.header.get_hash() not in shard.state.new_block_pool)
예제 #25
0
    def test_getTransactionReceipt_on_contract_creation(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(
                1, acc1, small_coinbase=True) as clusters, jrpc_server_context(
                    clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            to_full_shard_key = acc1.full_shard_key + 2
            tx = create_contract_creation_transaction(
                shard_state=clusters[0].get_shard_state(2 | 0),
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_key=to_full_shard_key,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            block1 = call_async(
                master.get_next_block_to_mine(address=acc1, branch_value=0b10))
            self.assertTrue(
                call_async(clusters[0].get_shard(2 | 0).add_block(block1)))

            for endpoint in ("getTransactionReceipt",
                             "eth_getTransactionReceipt"):
                resp = send_request(endpoint,
                                    ["0x" + tx.get_hash().hex() + "00000002"])
                self.assertEqual(resp["transactionHash"],
                                 "0x" + tx.get_hash().hex())
                self.assertEqual(resp["status"], "0x1")
                self.assertEqual(resp["cumulativeGasUsed"], "0x213eb")

                contract_address = mk_contract_address(acc1.recipient, 0,
                                                       to_full_shard_key)
                self.assertEqual(
                    resp["contractAddress"],
                    "0x" + contract_address.hex() +
                    to_full_shard_key.to_bytes(4, "big").hex(),
                )
예제 #26
0
    def test_getTransactionReceipt_on_contract_creation(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        with ClusterContext(1, acc1) as clusters, jrpc_server_context(
                clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(2, 0)
            to_full_shard_id = acc1.full_shard_id + 2
            tx = create_contract_creation_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_full_shard_id=to_full_shard_id,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            _, block1 = call_async(master.get_next_block_to_mine(address=acc1))
            self.assertTrue(
                call_async(clusters[0].get_shard(0).add_block(block1)))

            resp = send_request(
                "getTransactionReceipt",
                "0x" + tx.get_hash().hex() + branch.serialize().hex(),
            )
            self.assertEqual(resp["transactionHash"],
                             "0x" + tx.get_hash().hex())
            self.assertEqual(resp["status"], "0x1")
            self.assertEqual(resp["cumulativeGasUsed"], "0x213eb")

            contract_address = mk_contract_address(acc1.recipient,
                                                   to_full_shard_id, 0)
            self.assertEqual(
                resp["contractAddress"],
                "0x" + contract_address.hex() +
                to_full_shard_id.to_bytes(4, "big").hex(),
            )
예제 #27
0
    def test_create_shard_at_different_height(self):
        acc1 = Address.create_random_account()
        id1 = 0 << 16 | 1 | 0
        id2 = 1 << 16 | 1 | 0
        genesis_root_heights = {id1: 1, id2: 2}
        with ClusterContext(
            1,
            acc1,
            chain_size=2,
            shard_size=1,
            genesis_root_heights=genesis_root_heights,
        ) as clusters:
            master = clusters[0].master

            self.assertIsNone(clusters[0].get_shard(id1))
            self.assertIsNone(clusters[0].get_shard(id2))

            is_root, root = call_async(master.get_next_block_to_mine(acc1))
            self.assertTrue(is_root)
            self.assertEqual(len(root.minor_block_header_list), 0)
            call_async(master.add_root_block(root))

            # shard 0 created at root height 1
            self.assertIsNotNone(clusters[0].get_shard(id1))
            self.assertIsNone(clusters[0].get_shard(id2))

            is_root, root = call_async(master.get_next_block_to_mine(acc1))
            self.assertTrue(is_root)
            self.assertEqual(len(root.minor_block_header_list), 1)
            call_async(master.add_root_block(root))

            self.assertIsNotNone(clusters[0].get_shard(id1))
            # shard 1 created at root height 2
            self.assertIsNotNone(clusters[0].get_shard(id2))

            is_root, block = call_async(master.get_next_block_to_mine(acc1))
            self.assertTrue(is_root)
            self.assertEqual(len(root.minor_block_header_list), 1)
            call_async(master.add_root_block(root))
예제 #28
0
    def test_getWork_and_submitWork(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_id=0)

        with ClusterContext(1, acc1, remote_mining=True,
                            shard_size=1) as clusters, jrpc_server_context(
                                clusters[0].master):
            master = clusters[0].master
            slaves = clusters[0].slave_list

            branch = Branch.create(1, 0)
            tx = create_transfer_transaction(
                shard_state=slaves[0].shards[branch].state,
                key=id1.get_key(),
                from_address=acc1,
                to_address=acc1,
                value=0,
                gas_price=12,
            )
            self.assertTrue(slaves[0].add_tx(tx))

            for shard_id in ["0x0", None]:  # shard, then root
                resp = send_request("getWork", shard_id)
                self.assertEqual(resp[1:], ["0x1", "0xa"])  # height and diff

                header_hash_hex = resp[0]
                _, block = call_async(
                    master.get_next_block_to_mine(address=acc1))
                self.assertEqual(header_hash_hex[2:],
                                 block.header.get_hash_for_mining().hex())
                # solve it and submit
                solver = DoubleSHA256(block)
                mined = solver.mine(0, 1000)
                self.assertTrue(mined)
                nonce_found = "0x" + solver.nonce_found.hex()
                mixhash = "0x" + sha3_256(b"").hex()
                resp = send_request("submitWork", shard_id, header_hash_hex,
                                    nonce_found, mixhash)
                # FIXME: also verify root chain block addition after fixing https://github.com/QuarkChain/pyquarkchain/issues/130
                if shard_id is not None:
                    self.assertTrue(resp)
예제 #29
0
    def test_add_minor_block_request_list(self):
        id1 = Identity.create_random_identity()
        acc1 = Address.create_from_identity(id1, full_shard_key=0)

        with ClusterContext(2, acc1) as clusters:
            shard_state = clusters[0].get_shard_state(0b10)
            b1 = _tip_gen(shard_state)
            add_result = call_async(clusters[0].master.add_raw_minor_block(
                b1.header.branch, b1.serialize()))
            self.assertTrue(add_result)

            # Make sure the xshard list is not broadcasted to the other shard
            self.assertFalse(clusters[0].get_shard_state(
                0b11).contain_remote_minor_block_hash(b1.header.get_hash()))
            self.assertTrue(
                clusters[0].master.root_state.db.contain_minor_block_by_hash(
                    b1.header.get_hash()))

            # Make sure another cluster received the new block
            assert_true_with_timeout(lambda: clusters[0].get_shard_state(
                0b10).contain_block_by_hash(b1.header.get_hash()))
            assert_true_with_timeout(
                lambda: clusters[1].master.root_state.db.
                contain_minor_block_by_hash(b1.header.get_hash()))
예제 #30
0
def create_test_clusters(
    num_cluster,
    genesis_account,
    chain_size,
    shard_size,
    num_slaves,
    genesis_root_heights,
    genesis_minor_quarkash,
    remote_mining=False,
    small_coinbase=False,
    loadtest_accounts=None,
    connect=True,  # connect the bootstrap node by default
    should_set_gas_price_limit=False,
    mblock_coinbase_amount=None,
):
    # so we can have lower minimum diff
    easy_diff_calc = EthDifficultyCalculator(
        cutoff=45, diff_factor=2048, minimum_diff=10
    )

    bootstrap_port = get_next_port()  # first cluster will listen on this port
    cluster_list = []
    loop = asyncio.get_event_loop()

    for i in range(num_cluster):
        env = get_test_env(
            genesis_account,
            genesis_minor_quarkash=genesis_minor_quarkash,
            chain_size=chain_size,
            shard_size=shard_size,
            genesis_root_heights=genesis_root_heights,
            remote_mining=remote_mining,
        )
        env.cluster_config.P2P_PORT = bootstrap_port if i == 0 else get_next_port()
        env.cluster_config.JSON_RPC_PORT = get_next_port()
        env.cluster_config.PRIVATE_JSON_RPC_PORT = get_next_port()
        env.cluster_config.SIMPLE_NETWORK = SimpleNetworkConfig()
        env.cluster_config.SIMPLE_NETWORK.BOOTSTRAP_PORT = bootstrap_port
        env.quark_chain_config.loadtest_accounts = loadtest_accounts or []
        if should_set_gas_price_limit:
            env.quark_chain_config.MIN_TX_POOL_GAS_PRICE = 10
            env.quark_chain_config.MIN_MINING_GAS_PRICE = 10

        if small_coinbase:
            # prevent breaking previous tests after tweaking default rewards
            env.quark_chain_config.ROOT.COINBASE_AMOUNT = 5
            for c in env.quark_chain_config.shards.values():
                c.COINBASE_AMOUNT = 5
        if mblock_coinbase_amount is not None:
            for c in env.quark_chain_config.shards.values():
                c.COINBASE_AMOUNT = mblock_coinbase_amount

        env.cluster_config.SLAVE_LIST = []
        check(is_p2(num_slaves))

        for j in range(num_slaves):
            slave_config = SlaveConfig()
            slave_config.ID = "S{}".format(j)
            slave_config.PORT = get_next_port()
            slave_config.FULL_SHARD_ID_LIST = []
            env.cluster_config.SLAVE_LIST.append(slave_config)

        full_shard_ids = [
            (i << 16) + shard_size + j
            for i in range(chain_size)
            for j in range(shard_size)
        ]
        for i, full_shard_id in enumerate(full_shard_ids):
            slave = env.cluster_config.SLAVE_LIST[i % num_slaves]
            slave.FULL_SHARD_ID_LIST.append(full_shard_id)

        slave_server_list = []
        for j in range(num_slaves):
            slave_env = env.copy()
            slave_env.db = InMemoryDb()
            slave_env.slave_config = env.cluster_config.get_slave_config(
                "S{}".format(j)
            )
            slave_server = SlaveServer(slave_env, name="cluster{}_slave{}".format(i, j))
            slave_server.start()
            slave_server_list.append(slave_server)

        root_state = RootState(env, diff_calc=easy_diff_calc)
        master_server = MasterServer(env, root_state, name="cluster{}_master".format(i))
        master_server.start()

        # Wait until the cluster is ready
        loop.run_until_complete(master_server.cluster_active_future)

        # Substitute diff calculate with an easier one
        for slave in slave_server_list:
            for shard in slave.shards.values():
                shard.state.diff_calc = easy_diff_calc

        # Start simple network and connect to seed host
        network = SimpleNetwork(env, master_server, loop)
        network.start_server()
        if connect and i != 0:
            peer = call_async(network.connect("127.0.0.1", bootstrap_port))
        else:
            peer = None

        cluster_list.append(Cluster(master_server, slave_server_list, network, peer))

    return cluster_list