async def test_only_apps_query(self):

        data_encoder, private_key_to_address
        users = [('bob{}'.format(i),
                  private_key_to_address(data_encoder(os.urandom(32))), False)
                 for i in range(6)]
        bots = [('bot{}'.format(i),
                 private_key_to_address(data_encoder(os.urandom(32))), True)
                for i in range(4)]

        async with self.pool.acquire() as con:
            for args in users + bots:
                await con.execute(
                    "INSERT INTO users (username, toshi_id, is_app) VALUES ($1, $2, $3)",
                    *args)

        resp = await self.fetch("/search/user?query=bo", method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 10)

        resp = await self.fetch("/search/user?query=bo&apps=false",
                                method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 6)

        resp = await self.fetch("/search/user?query=bo&apps=true",
                                method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 4)
Exemple #2
0
    async def get_tx_skel(self,
                          from_key,
                          to_addr,
                          val,
                          nonce=None,
                          gas_price=None,
                          gas=None,
                          data=None):
        from_addr = private_key_to_address(from_key)
        body = {"from": from_addr, "to": to_addr, "value": val}
        if nonce is not None:
            body['nonce'] = nonce
        if gas_price is not None:
            body['gasPrice'] = gas_price
        if gas is not None:
            body['gas'] = gas
        if data is not None:
            body['data'] = data

        resp = await self.fetch("/tx/skel", method="POST", body=body)

        self.assertResponseCodeEqual(resp, 200, resp.body)

        body = json_decode(resp.body)

        tx = body['tx']

        return tx
    async def get_tx_skel(self,
                          from_key,
                          to_addr,
                          val,
                          nonce=None,
                          gas_price=None,
                          gas=None,
                          data=None,
                          token_address=None,
                          expected_response_code=200):
        from_addr = private_key_to_address(from_key)
        body = {
            "from": from_addr,
            "to": to_addr,
            "value": hex(val) if isinstance(val, int) else val
        }
        if nonce is not None:
            body['nonce'] = nonce
        if gas_price is not None:
            body['gasPrice'] = gas_price
        if gas is not None:
            body['gas'] = gas
        if data is not None:
            body['data'] = data
        if token_address is not None:
            body['token_address'] = token_address

        resp = await self.fetch("/tx/skel", method="POST", body=body)

        self.assertResponseCodeEqual(resp, expected_response_code, resp.body)
        if expected_response_code == 200:
            body = json_decode(resp.body)
            tx = body['tx']
            return tx
        return None
    async def test_username_query(self):
        username = "******"
        positive_query = 'Tos'

        private_key = os.urandom(32)
        toshi_id = private_key_to_address(private_key)

        async with self.pool.acquire() as con:
            await con.execute(
                "INSERT INTO users (username, name, toshi_id, is_bot, is_public) VALUES ($1, $2, $3, $4, $5)",
                username, username, toshi_id, True, True)

        resp = await self.fetch("/search/apps?query={}".format(positive_query),
                                method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 0)

        con = await self.websocket_connect(private_key)

        resp = await self.fetch("/search/apps?query={}".format(positive_query),
                                method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 1)
 def __init__(self,
              name,
              contract,
              *,
              from_key=None,
              constant=None,
              return_raw_tx=False):
     self.name = name
     self.contract = contract
     # TODO: forcing const seems to do nothing, since eth_call
     # will just return a tx_hash (on parity at least)
     if constant is None:
         self.is_constant = self.contract.translator.function_data[name][
             'is_constant']
     else:
         # force constantness of this function
         self.is_constant = constant
     if from_key:
         if isinstance(from_key, str):
             self.from_key = data_decoder(from_key)
         else:
             self.from_key = from_key
         self.from_address = private_key_to_address(from_key)
     else:
         self.from_key = None
         self.from_address = None
     self.return_raw_tx = return_raw_tx
    async def test_apps_vs_public(self):
        """Make sure if something is marked as being an app it doesn't show up
        in the public list even if marked with public"""

        no_of_users_to_generate = 20
        insert_vals = []
        for i in range(0, no_of_users_to_generate):
            key = os.urandom(32)
            name = namegen.get_full_name()
            username = name.lower().replace(' ', '')
            insert_vals.append((private_key_to_address(key), username, name,
                                (i / (no_of_users_to_generate - 1)) * 5.0, 10,
                                True, True if i % 2 == 0 else False))

        async with self.pool.acquire() as con:
            await con.executemany(
                "INSERT INTO users (toshi_id, username, name, reputation_score, review_count, is_public, is_app) VALUES ($1, $2, $3, $4, $5, $6, $7)",
                insert_vals)

        resp = await self.fetch("/search/user?limit={}".format(i + 1),
                                method="GET")
        self.assertEqual(resp.code, 200)
        results = json_decode(resp.body)['results']
        self.assertEqual(len(results), no_of_users_to_generate)

        resp = await self.fetch("/search/user?public=true&limit={}".format(i +
                                                                           1),
                                method="GET")
        self.assertEqual(resp.code, 200)
        results = json_decode(resp.body)['results']
        self.assertEqual(len(results), (i + (1 if i % 2 == 1 else 2)) // 2)
Exemple #7
0
    async def test_large_volume_of_txs(self):
        """Tests that the service can handle a large volume of transactions
        from different users
        """

        num_of_txs = 10
        # create sending user keys
        from_keys = [os.urandom(32) for _ in range(num_of_txs)]
        # create receiver user addresses
        to_addresses = [data_encoder(os.urandom(20)) for _ in range(num_of_txs)]
        # faucet sending users
        txs = []
        for key in from_keys:
            addr = private_key_to_address(key)
            txs.append((await self.send_tx(FAUCET_PRIVATE_KEY, addr, 10 * (10 ** 18))))
        # send transactions
        for key, address in zip(from_keys, to_addresses):
            txs.append((await self.send_tx(key, address, 10 ** 18)))

        while True:
            async with self.pool.acquire() as con:
                rows = await con.fetch("SELECT status, COUNT(*) FROM transactions WHERE hash = ANY($1) GROUP BY status",
                                       txs)
            s = []
            for row in rows:
                s.append("{}: {}".format(row['status'], row['count']))
                if row['status'] == 'confirmed' and row['count'] == len(txs):
                    return
                if row['status'] == 'queued' and row['count'] == 1:
                    async with self.pool.acquire() as con:
                        row = await con.fetchrow("SELECT * FROM transactions WHERE status = 'queued'")
                    print(row)

            print(', '.join(s))
            await asyncio.sleep(1)
Exemple #8
0
    def fetch_signed(self, path, *, signing_key=None, signature=None, timestamp=None, address=None, **kwargs):

        if not isinstance(path, str) or not path.startswith("/"):
            # for simplicity's sake, don't accept HTTPRequest objects or external urls in the tests
            raise Exception("first argument must be path string starting with a / (e.g. /v1/tx)")

        # find out if there's a path prefix added by get_url
        prefix = "/{}".format(self.get_url(path).split('/', 3)[-1]).split(path)[0]

        headers = kwargs.setdefault('headers', tornado.httputil.HTTPHeaders())

        if 'body' in kwargs:
            body = kwargs.pop('body')
            if isinstance(body, dict):
                headers['Content-Type'] = "application/json"
                body = tornado.escape.json_encode(body).encode('utf-8')
            elif isinstance(body, str):
                # try and find the charset to use to encode this
                if 'Content-Type' in headers:
                    idx = headers['Content-Type'].find('charset=')
                    if idx >= 0:
                        charset = headers['Content-Type'][idx + 8:]
                        idx = charset.find(';')
                        if idx >= 0:
                            charset = charset[:idx]
                    else:
                        charset = 'utf-8'
                else:
                    charset = 'utf-8'
                # encode to a byte string
                body = body.encode(charset)
            elif not isinstance(body, bytes):
                raise Exception("Unable to handle bodys of type '{}'".format(type(body)))
        else:
            body = None

        method = kwargs.setdefault('method', 'GET').upper()

        if signing_key is None and (address is None or signature is None):
            raise Exception("signing_key is required unless address and signature is given")

        if timestamp is None and signature is not None:
            raise Exception("timestamp is required if signature is given explicitly")

        if address is None:
            address = private_key_to_address(signing_key)
        if timestamp is None:
            timestamp = int(time.time())
        if signature is None:
            signature = sign_request(signing_key, method, "{}{}".format(prefix, path), timestamp, body)

        headers[TOSHI_ID_ADDRESS_HEADER] = address
        headers[TOSHI_SIGNATURE_HEADER] = signature
        headers[TOSHI_TIMESTAMP_HEADER] = str(timestamp)

        # because tornado doesn't like POSTs with body set to None
        if body is None and method == "POST":
            body = b""

        return self.fetch(path, body=body, **kwargs)
Exemple #9
0
    async def test_non_query_search(self):

        positive_query = 'bot'

        setup_data = [("ToshiBotA", "toshi bot a", os.urandom(32), True),
                      ("ToshiBotB", "toshi bot b", os.urandom(32), True),
                      ("ToshiBotC", "toshi bot c", os.urandom(32), True),
                      ("ToshiBotD", "toshi bot d", os.urandom(32), True),
                      ("ToshiBotE", "toshi bot e", os.urandom(32), True)]

        count = 0
        sessions = []
        for username, name, private_key, featured in setup_data:
            async with self.pool.acquire() as con:
                toshi_id = private_key_to_address(private_key)
                if count > 2:
                    time = datetime.utcnow() - timedelta(minutes=2)
                else:
                    time = datetime.utcnow()
                session_id = uuid.uuid4().hex

                await con.execute(
                    "INSERT INTO users (username, name, toshi_id, featured, is_app, is_public) VALUES ($1, $2, $3, $4, $5, $6)",
                    username, name, toshi_id, featured, True, True)
                await con.execute(
                    "INSERT INTO websocket_sessions VALUES ($1, $2, $3)",
                    session_id, toshi_id, time)
                sessions.append((session_id, toshi_id))
                count += 1

        resp = await self.fetch("/search/apps".format(positive_query),
                                method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 5)

        housekeeping = HousekeepingApplication(
            config=self._app.config,
            connection_pool=self._app.connection_pool,
            delay=1)
        housekeeping.start()
        await asyncio.sleep(0.1)

        resp = await self.fetch("/search/apps".format(positive_query),
                                method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 3)

        async with self.pool.acquire() as con:
            await con.execute("UPDATE websocket_sessions SET last_seen = $1",
                              datetime.utcnow() - timedelta(minutes=2))
        await asyncio.sleep(1)

        resp = await self.fetch("/search/apps".format(positive_query),
                                method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 0)
Exemple #10
0
    async def faucet(self,
                     to,
                     value,
                     *,
                     from_private_key=FAUCET_PRIVATE_KEY,
                     startgas=None,
                     gasprice=DEFAULT_GASPRICE,
                     nonce=None,
                     data=b"",
                     wait_on_confirmation=True):

        if isinstance(from_private_key, str):
            from_private_key = data_decoder(from_private_key)
        from_address = private_key_to_address(from_private_key)

        ethclient = JsonRPCClient(config['ethereum']['url'])

        to = data_decoder(to)
        if len(to) not in (20, 0):
            raise Exception(
                'Addresses must be 20 or 0 bytes long (len was {})'.format(
                    len(to)))

        if nonce is None:
            nonce = await ethclient.eth_getTransactionCount(from_address)
        balance = await ethclient.eth_getBalance(from_address)

        if startgas is None:
            startgas = await ethclient.eth_estimateGas(from_address,
                                                       to,
                                                       data=data,
                                                       nonce=nonce,
                                                       value=value,
                                                       gasprice=gasprice)

        tx = Transaction(nonce, gasprice, startgas, to, value, data, 0, 0, 0)

        if balance < (tx.value + (tx.startgas * tx.gasprice)):
            raise Exception("Faucet doesn't have enough funds")

        tx.sign(from_private_key)

        tx_encoded = data_encoder(rlp.encode(tx, Transaction))

        tx_hash = await ethclient.eth_sendRawTransaction(tx_encoded)

        while wait_on_confirmation:
            resp = await ethclient.eth_getTransactionByHash(tx_hash)
            if resp is None or resp['blockNumber'] is None:
                await asyncio.sleep(0.1)
            else:
                break

        if to == b'':
            print("contract address: {}".format(data_encoder(tx.creates)))

        return tx_hash
 async def test_search_order_by_reputation(self):
     no_of_users_to_generate = 7
     insert_vals = []
     for i in range(0, no_of_users_to_generate):
         key = os.urandom(32)
         name = "John Smith"
         username = '******'.format(i)
         insert_vals.append((private_key_to_address(key), username, name,
                             (i / (no_of_users_to_generate - 1)) * 5.0, 10))
     for j in range(i + 1, i + 4):
         key = os.urandom(32)
         name = "John Smith"
         username = '******'.format(j)
         insert_vals.append((private_key_to_address(key), username, name,
                             (i / (no_of_users_to_generate - 1)) * 5.0, j))
     # add some users with no score to make sure
     # users who haven't been reviewed appear last
     for k in range(j + 1, j + 2):
         key = os.urandom(32)
         username = '******'.format(k)
         insert_vals.append(
             (private_key_to_address(key), username, name, None, 0))
     async with self.pool.acquire() as con:
         await con.executemany(
             "INSERT INTO users (toshi_id, username, name, reputation_score, review_count) VALUES ($1, $2, $3, $4, $5)",
             insert_vals)
     resp = await self.fetch("/search/user?query=Smith&limit={}".format(k +
                                                                        1),
                             method="GET")
     self.assertEqual(resp.code, 200)
     results = json_decode(resp.body)['results']
     self.assertEqual(len(results), k + 1)
     # make sure that the highest rated "Smith" is first
     previous_rating = 5.1
     previous_count = None
     for user in results:
         rep = 2.01 if user['reputation_score'] is None else user[
             'reputation_score']
         self.assertLessEqual(rep, previous_rating)
         if rep == previous_rating:
             self.assertLessEqual(user['review_count'], previous_count)
         previous_count = user['review_count']
         previous_rating = rep
Exemple #12
0
    async def deploy_contract(self,
                              bytecode,
                              *,
                              from_private_key=FAUCET_PRIVATE_KEY,
                              startgas=None,
                              gasprice=DEFAULT_GASPRICE,
                              wait_on_confirmation=True):

        if isinstance(from_private_key, str):
            from_private_key = data_decoder(from_private_key)
        from_address = private_key_to_address(from_private_key)

        ethclient = JsonRPCClient(config['ethereum']['url'])

        nonce = await ethclient.eth_getTransactionCount(from_address)
        balance = await ethclient.eth_getBalance(from_address)

        gasestimate = await ethclient.eth_estimateGas(from_address,
                                                      '',
                                                      data=bytecode,
                                                      nonce=nonce,
                                                      value=0,
                                                      gasprice=gasprice)

        if startgas is None:
            startgas = gasestimate
        elif gasestimate > startgas:
            raise Exception(
                "Estimated gas usage is larger than the provided gas")

        tx = Transaction(nonce, gasprice, startgas, '', 0, bytecode, 0, 0, 0)

        if balance < (tx.value + (tx.startgas * tx.gasprice)):
            raise Exception("Faucet doesn't have enough funds")

        tx.sign(from_private_key)

        tx_encoded = data_encoder(rlp.encode(tx, Transaction))

        tx_hash = await ethclient.eth_sendRawTransaction(tx_encoded)

        contract_address = data_encoder(tx.creates)

        while wait_on_confirmation:
            resp = await ethclient.eth_getTransactionByHash(tx_hash)
            if resp is None or resp['blockNumber'] is None:
                await asyncio.sleep(0.1)
            else:
                code = await ethclient.eth_getCode(contract_address)
                if code == '0x':
                    raise Exception("Failed to deploy contract")
                break

        return tx_hash, contract_address
 async def test_fulltextsearch(self):
     no_of_users_to_generate = 100
     insert_vals = [(private_key_to_address(os.urandom(32)), "user0",
                     "Bob Smith")]
     some_bobs = False
     for i in range(1, no_of_users_to_generate):
         key = os.urandom(32)
         while True:
             name = namegen.get_full_name()
             # make sure we never generate any user's called bob
             if 'Bob' in name or 'bob' in name:
                 continue
             break
         # give ten of the users a 'bob##' username
         if i % (no_of_users_to_generate / 10) == 0:
             some_bobs = True
             username = '******'.format(i)
         else:
             username = '******'.format(i)
         #resp = await self.fetch_signed(
         #    "/user", method="POST", signing_key=key,
         #    body=body)
         #self.assertEqual(resp.code, 200)
         insert_vals.append((private_key_to_address(key), username, name))
     async with self.pool.acquire() as con:
         await con.executemany(
             "INSERT INTO users (toshi_id, username, name) VALUES ($1, $2, $3)",
             insert_vals)
         count = await con.fetchrow("SELECT count(*) FROM users")
         bobcount = await con.fetchrow(
             "SELECT count(*) FROM users where username ilike 'bob%'")
     self.assertTrue(count['count'] > 0)
     self.assertTrue(bobcount['count'] > 0)
     self.assertTrue(some_bobs)
     resp = await self.fetch("/search/user?query=bob", method="GET")
     self.assertEqual(resp.code, 200)
     results = json_decode(resp.body)['results']
     self.assertTrue(len(results) > 1)
     # make sure that name is prefered over username
     self.assertEqual(results[0]['name'], "Bob Smith")
     self.assertTrue(results[1]['username'].startswith("bob"))
    async def test_multiple_websockets(self):
        username = "******"
        private_key = os.urandom(32)
        toshi_id = private_key_to_address(private_key)

        username2 = "ToshiBot2"
        private_key2 = os.urandom(32)
        toshi_id2 = private_key_to_address(private_key2)

        async with self.pool.acquire() as con:
            await con.execute(
                "INSERT INTO users (username, name, toshi_id, is_bot, is_public) VALUES ($1, $2, $3, $4, $5)",
                username, username, toshi_id, True, True)
            await con.execute(
                "INSERT INTO users (username, name, toshi_id, is_bot, is_public) VALUES ($1, $2, $3, $4, $5)",
                username2, username2, toshi_id2, True, True)

        resp = await self.fetch("/search/apps", method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 0)

        cons = []
        for _ in range(10):
            con = await self.websocket_connect(private_key)
            cons.append(con)

        async with self.pool.acquire() as con:
            count = await con.fetchval(
                "SELECT COUNT(*) FROM websocket_sessions")
        self.assertEqual(count, len(cons))

        resp = await self.fetch("/search/apps", method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 1)
Exemple #15
0
    async def connect(self):

        # find out if there's a path prefix added by get_url
        path = "/{}".format(self.url.split('/', 3)[-1])

        address = private_key_to_address(self.signing_key)
        timestamp = int(time.time())
        signature = sign_request(self.signing_key, "GET", path, timestamp,
                                 None)

        request = tornado.httpclient.HTTPRequest(
            self.url,
            headers={
                'User-Agent': 'Toshi-Test-Websocket-Client',
                TOSHI_ID_ADDRESS_HEADER: address,
                TOSHI_SIGNATURE_HEADER: signature,
                TOSHI_TIMESTAMP_HEADER: str(timestamp)
            })

        self.con = await tornado.websocket.websocket_connect(request)
        return self.con
    async def test_users_vs_public(self):
        """Make sure only apps show up in public searches"""

        no_of_users_to_generate = 20
        insert_vals = []
        for i in range(0, no_of_users_to_generate):
            key = os.urandom(32)
            name = namegen.get_full_name()
            username = name.lower().replace(' ', '')
            insert_vals.append(
                (private_key_to_address(key), username, name,
                 (i / (no_of_users_to_generate - 1)) * 5.0, 10,
                 True if i % 4 == 0 else False, True if i % 2 == 0 else False))

        no_of_apps = (i + (1 if i % 2 == 1 else 2)) // 2
        no_of_public_apps = (i + (1 if i % 4 == 1 else 2)) // 4

        async with self.pool.acquire() as con:
            await con.executemany(
                "INSERT INTO users (toshi_id, username, name, reputation_score, review_count, is_public, is_bot) VALUES ($1, $2, $3, $4, $5, $6, $7)",
                insert_vals)

        resp = await self.fetch("/search/user?apps=true&limit={}".format(i +
                                                                         1),
                                method="GET")
        self.assertEqual(resp.code, 200)
        results = json_decode(resp.body)['results']
        self.assertEqual(len(results), no_of_apps)
        for user in results:
            self.assertTrue(user['is_app'])

        # make sure apps search only includes public apps by default
        resp = await self.fetch("/search/apps?limit={}".format(i + 1),
                                method="GET")
        self.assertEqual(resp.code, 200)
        results = json_decode(resp.body)['results']
        self.assertEqual(len(results), no_of_public_apps)
        for user in results:
            self.assertTrue(user['is_app'])
            self.assertTrue(user['public'])
    async def test_non_query_search(self):

        setup_data = [("ToshiBotA", "toshi bot a", os.urandom(32), True),
                      ("ToshiBotB", "toshi bot b", os.urandom(32), True),
                      ("ToshiBotC", "toshi bot c", os.urandom(32), True),
                      ("ToshiBotD", "toshi bot d", os.urandom(32), True),
                      ("ToshiBotE", "toshi bot e", os.urandom(32), True)]

        cons = []
        for username, name, private_key, featured in setup_data:
            async with self.pool.acquire() as con:
                await con.execute(
                    "INSERT INTO users (username, name, toshi_id, featured, is_bot, is_public) VALUES ($1, $2, $3, $4, $5, $6)",
                    username, name, private_key_to_address(private_key),
                    featured, True, True)

        cons = []
        resp = await self.fetch("/search/apps", method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 0)

        con = await self.websocket_connect(setup_data[0][2])
        cons.append(con)

        resp = await self.fetch("/search/apps", method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 1)

        for _, _, private_key, _ in setup_data[1:]:
            con = await self.websocket_connect(private_key)
            cons.append(con)

        resp = await self.fetch("/search/apps", method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 5)
    async def from_source_code(cls,
                               sourcecode,
                               contract_name,
                               constructor_data=None,
                               *,
                               address=None,
                               deployer_private_key=None,
                               import_mappings=None,
                               libraries=None,
                               optimize=False,
                               deploy=True,
                               cwd=None,
                               wait_for_confirmation=True):

        if deploy:
            ethurl = get_url()

            if address is None and deployer_private_key is None:
                raise TypeError(
                    "requires either address or deployer_private_key")
            if address is None and not isinstance(constructor_data,
                                                  (list, type(None))):
                raise TypeError(
                    "must supply constructor_data as a list (hint: use [] if args should be empty)"
                )

        args = ['solc', '--combined-json', 'bin,abi']
        if libraries:
            args.extend([
                '--libraries',
                ','.join(['{}:{}'.format(*library) for library in libraries])
            ])
        if optimize:
            args.append('--optimize')
        if import_mappings:
            args.extend([
                "{}={}".format(path, mapping)
                for path, mapping in import_mappings
            ])
        # check if sourcecode is actually a filename
        if cwd:
            filename = os.path.join(cwd, sourcecode)
        else:
            filename = sourcecode
        if os.path.exists(filename):
            args.append(filename)
            sourcecode = None
        else:
            filename = '<stdin>'
        process = subprocess.Popen(args,
                                   stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   cwd=cwd)
        output, stderrdata = process.communicate(input=sourcecode)
        try:
            output = json_decode(output)
        except json.JSONDecodeError:
            if output and stderrdata:
                output += b'\n' + stderrdata
            elif stderrdata:
                output = stderrdata
            raise Exception("Failed to compile source: {}\n{}\n{}".format(
                filename, ' '.join(args), output.decode('utf-8')))

        try:
            contract = output['contracts']['{}:{}'.format(
                filename, contract_name)]
        except KeyError:
            print(output)
            raise
        abi = json_decode(contract['abi'])

        # deploy contract
        translator = ContractTranslator(abi)
        # fix things that don't have a constructor

        if not deploy:
            return Contract(abi=abi, address=address, translator=translator)

        ethclient = JsonRPCClient(ethurl)

        if address is not None:
            # verify there is code at the given address
            for i in range(10):
                code = await ethclient.eth_getCode(address)
                if code == "0x":
                    await asyncio.sleep(1)
                    continue
                break
            else:
                raise Exception("No code found at given address")
            return Contract(abi=abi, address=address, translator=translator)

        try:
            bytecode = data_decoder(contract['bin'])
        except binascii.Error:
            print(contract['bin'])
            raise

        if constructor_data is not None:
            constructor_call = translator.encode_constructor_arguments(
                constructor_data)
            bytecode += constructor_call

        if isinstance(deployer_private_key, str):
            deployer_private_key = data_decoder(deployer_private_key)
        deployer_address = private_key_to_address(deployer_private_key)
        nonce = await ethclient.eth_getTransactionCount(deployer_address)
        balance = await ethclient.eth_getBalance(deployer_address)

        gasprice = 20000000000
        value = 0

        startgas = await ethclient.eth_estimateGas(deployer_address,
                                                   '',
                                                   data=bytecode,
                                                   nonce=nonce,
                                                   value=0,
                                                   gasprice=gasprice)

        if balance < (startgas * gasprice):
            raise Exception("Given account doesn't have enough funds")

        tx = Transaction(nonce, gasprice, startgas, '', value, bytecode, 0, 0,
                         0)
        tx.sign(deployer_private_key)

        tx_encoded = data_encoder(rlp.encode(tx, Transaction))

        contract_address = data_encoder(tx.creates)

        tx_hash = await ethclient.eth_sendRawTransaction(tx_encoded)

        # wait for the contract to be deployed
        while wait_for_confirmation:
            resp = await ethclient.eth_getTransactionByHash(tx_hash)
            if resp is None or resp['blockNumber'] is None:
                await asyncio.sleep(0.1)
            else:
                code = await ethclient.eth_getCode(contract_address)
                if code == '0x':
                    raise Exception(
                        "Failed to deploy contract: resulting address '{}' has no code"
                        .format(contract_address))
                break

        return Contract(abi=abi,
                        address=contract_address,
                        translator=translator,
                        creation_tx_hash=tx_hash)
    async def test_search_order_by_reputation_without_query(self):
        no_of_users_to_generate = 20
        insert_vals = []
        for i in range(0, no_of_users_to_generate):
            key = os.urandom(32)
            name = namegen.get_full_name()
            username = name.lower().replace(' ', '')
            insert_vals.append((private_key_to_address(key), username, name,
                                (i / (no_of_users_to_generate - 1)) * 5.0, 10,
                                True if i % 2 == 0 else False))
        for j in range(i + 1, i + 4):
            key = os.urandom(32)
            name = namegen.get_full_name()
            username = name.lower().replace(' ', '')
            insert_vals.append((private_key_to_address(key), username, name,
                                (i / (no_of_users_to_generate - 1)) * 5.0, j,
                                True if j % 2 == 0 else False))
        # add some users with no score to make sure
        # users who haven't been reviewed appear last
        for k in range(j + 1, j + 7):
            key = os.urandom(32)
            name = namegen.get_full_name()
            username = name.lower().replace(' ', '')
            insert_vals.append((private_key_to_address(key), username, name,
                                None, 0, True if k % 2 == 0 else False))
        async with self.pool.acquire() as con:
            await con.executemany(
                "INSERT INTO users (toshi_id, username, name, reputation_score, review_count, is_public) VALUES ($1, $2, $3, $4, $5, $6)",
                insert_vals)
        resp = await self.fetch("/search/user?top=true&limit={}".format(k + 1),
                                method="GET")
        self.assertEqual(resp.code, 200)
        results = json_decode(resp.body)['results']
        self.assertEqual(len(results), k + 1)
        # make sure that the highest rated is first
        previous_rating = 5.1
        previous_count = None
        for user in results:
            rep = 2.01 if user['reputation_score'] is None else user[
                'reputation_score']
            self.assertLessEqual(rep, previous_rating)
            if rep == previous_rating:
                self.assertLessEqual(user['review_count'], previous_count)
            previous_count = user['review_count']
            previous_rating = rep

        # check public search
        resp = await self.fetch(
            "/search/user?top=true&public=true&limit={}".format(k + 1),
            method="GET")
        self.assertEqual(resp.code, 200)
        results = json_decode(resp.body)['results']
        self.assertEqual(len(results), (k + (1 if k % 2 == 1 else 2)) // 2)
        # make sure that the highest rated is first
        previous_rating = 5.1
        previous_count = None
        for user in results:
            self.assertTrue(user['public'])
            rep = 2.01 if user['reputation_score'] is None else user[
                'reputation_score']
            self.assertLessEqual(rep, previous_rating)
            if rep == previous_rating:
                self.assertLessEqual(user['review_count'], previous_count)
            previous_count = user['review_count']
            previous_rating = rep
    async def test_get_app_index(self):
        resp = await self.fetch("/apps/", method="GET")
        self.assertResponseCodeEqual(resp, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 0)

        setup_data = [
            ("ToshiBotA", private_key_to_address(os.urandom(32)), False, True,
             True),
            ("ToshiBotB", private_key_to_address(os.urandom(32)), False, True,
             True),
            ("FeaturedBotA", private_key_to_address(os.urandom(32)), True,
             True, True),
            ("FeaturedBotB", private_key_to_address(os.urandom(32)), True,
             True, True),
            ("FeaturedBotC", private_key_to_address(os.urandom(32)), True,
             True, True),
            ("NotPublicBotA", private_key_to_address(os.urandom(32)), True,
             True, False),
            ("NotPublicBotB", private_key_to_address(os.urandom(32)), False,
             True, False),
            ("NotPublicBotC", private_key_to_address(os.urandom(32)), True,
             True, False),
            ("NormalUser1", private_key_to_address(os.urandom(32)), False,
             False, True),
            ("NormalUser2", private_key_to_address(os.urandom(32)), False,
             False, False),
            ("NormalUser3", private_key_to_address(os.urandom(32)), False,
             False, True),
        ]

        for username, addr, featured, is_bot, is_public in setup_data:
            async with self.pool.acquire() as con:
                await con.execute(
                    "INSERT INTO users (username, name, toshi_id, is_bot, featured, is_public) VALUES ($1, $2, $3, $4, $5, $6)",
                    username, username, addr, is_bot, featured, is_public)

        resp = await self.fetch("/apps", method="GET")
        self.assertResponseCodeEqual(resp, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 5)

        # test /apps/featured
        resp = await self.fetch("/apps/featured", method="GET")
        self.assertResponseCodeEqual(resp, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 3)

        # ensure we got a tracking event
        self.assertEqual((await self.next_tracking_event())[0], None)

        resp = await self.fetch("/apps?featured", method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 3)

        for true in ['', 'true', 'featured', 'TRUE', 'True']:

            resp = await self.fetch("/apps?featured={}".format(true),
                                    method="GET")
            self.assertEqual(resp.code, 200)
            body = json_decode(resp.body)
            self.assertEqual(len(body['results']), 3,
                             "Failed to map featured={} to true".format(true))

        for false in ['false', 'FALSE', 'False']:

            resp = await self.fetch("/apps?featured={}".format(false),
                                    method="GET")
            self.assertEqual(resp.code, 200)
            body = json_decode(resp.body)
            self.assertEqual(
                len(body['results']), 2,
                "Failed to map featured={} to false".format(false))
    async def test_featured_query(self):

        positive_query = 'bot'

        setup_data = [
            ("ToshiBotA", "toshi bot a", os.urandom(32), False),
            ("ToshiBotB", "toshi bot b", os.urandom(32), False),
            ("FeaturedBotA", "featured toshi bot a", os.urandom(32), True),
            ("FeaturedBotB", "featured toshi bot b", os.urandom(32), True),
            ("FeaturedBotC", "featured toshi bot c", os.urandom(32), True)
        ]

        cons = []
        for username, name, private_key, featured in setup_data:
            async with self.pool.acquire() as con:
                await con.execute(
                    "INSERT INTO users (username, name, toshi_id, featured, is_bot, is_public) VALUES ($1, $2, $3, $4, $5, $6)",
                    username, name, private_key_to_address(private_key),
                    featured, True, True)

            con = await self.websocket_connect(private_key)
            cons.append(con)

        resp = await self.fetch("/search/apps?query={}".format(positive_query),
                                method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 5)

        resp = await self.fetch(
            "/search/apps?query={}&featured".format(positive_query),
            method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 3)

        for con in cons[:3]:
            con.close()
        await asyncio.sleep(0.2)

        resp = await self.fetch(
            "/search/apps?query={}&featured".format(positive_query),
            method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 2)

        cons[3].close()
        await asyncio.sleep(0.2)

        resp = await self.fetch(
            "/search/apps?query={}&featured".format(positive_query),
            method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 1)

        cons[4].close()
        await asyncio.sleep(0.2)

        resp = await self.fetch(
            "/search/apps?query={}&featured".format(positive_query),
            method="GET")
        self.assertEqual(resp.code, 200)
        body = json_decode(resp.body)
        self.assertEqual(len(body['results']), 0)
from tornado.testing import gen_test

from toshieth.test.base import EthServiceBaseTest, requires_full_stack
from toshi.test.ethereum.faucet import FAUCET_PRIVATE_KEY, FAUCET_ADDRESS
from toshi.ethereum.utils import private_key_to_address, data_decoder

from toshi.ethereum.contract import Contract
from ethereum.utils import sha3

ABC_TOKEN_ADDRESS = "0x056db290f8ba3250ca64a45d16284d04bc6f5fbf"
YAC_TOKEN_ADDRESS = "0x9ab6c6111577c51da46e2c4c93a3622671578657"

ARTTOKEN_CONTRACT = open(os.path.join(os.path.dirname(__file__), "arttokencreator.sol")).read().encode('utf-8')
TEST_PRIVATE_KEY = data_decoder("0xe8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35")
TEST_PRIVATE_KEY_2 = data_decoder("0x8945608e66736aceb34a83f94689b4e98af497ffc9dc2004a93824096330fa77")
TEST_ADDRESS = private_key_to_address(TEST_PRIVATE_KEY)
TEST_ADDRESS_2 = private_key_to_address(TEST_PRIVATE_KEY_2)

TEST_APN_ID = "64be4fe95ba967bb533f0c240325942b9e1f881b5cd2982568a305dd4933e0bd"

class FakeIPFSHandler(tornado.web.RequestHandler):

    def get(self, key):
        self.write({"properties": {
            "image": {"description": "http://{}.png".format(key)}
        }})

class ERC721Test(EthServiceBaseTest):

    def get_urls(self):
        return super().get_urls() + [
Exemple #23
0
 def __init__(self, signing_key):
     self.address = private_key_to_address(signing_key)
     self.signing_key = signing_key