def do_POST(self):

        # TODO: figure out why read is blocking here
        data = self.rfile.read(len(self.rfile.peek()))
        data = data.decode('utf-8')
        data = json.loads(data)

        if self.path == "/v1/tx/skel":

            gas_price = parse_int(data['gas_price']) if 'gas_price' in data else DEFAULT_GASPRICE
            gas = parse_int(data['gas']) if 'gas' in data else DEFAULT_STARTGAS
            nonce = parse_int(data['nonce']) if 'nonce' in data else 0

            if 'value' not in data or 'from' not in data or 'to' not in data:
                self.write_data(400, {'errors': [{'id': 'bad_arguments', 'message': 'Bad Arguments'}]})
                return
            value = parse_int(data['value'])
            to_address = data['to']
            from_address = data['from']

            if not validate_address(to_address):
                self.write_data(400, {'errors': [{'id': 'invalid_to_address', 'message': 'Invalid To Address'}]})
                return
            if not validate_address(from_address):
                self.write_data(400, {'errors': [{'id': 'invalid_from_address', 'message': 'Invalid From Address'}]})
                return

            tx = create_transaction(nonce=nonce, gasprice=gas_price, startgas=gas,
                                    to=to_address, value=value)

            transaction = encode_transaction(tx)

            self.write_data(200, {
                "tx_data": {
                    "nonce": hex(nonce),
                    "from": from_address,
                    "to": to_address,
                    "value": hex(value),
                    "startGas": hex(gas),
                    "gasPrice": hex(gas_price)
                },
                "tx": transaction
            })

        elif self.path == "/v1/tx":

            tx = decode_transaction(data['tx'])

            if 'signature' in data:

                sig = data_decoder(data['signature'])

                add_signature_to_transaction(tx, sig)

            self.write_data(200, {"tx_hash": data_encoder(tx.hash)})

        else:

            self.write_data(404)
예제 #2
0
def generate_request_signature_data_string(method, path, timestamp, data):

    if isinstance(data, str_types):
        data = data.encode('utf-8')
    elif isinstance(data, dict):
        data = json.dumps(data).encode('utf-8')

    if data is not None and data != b"":
        datahash = base64.b64encode(sha3(data)).decode('utf-8')
    else:
        datahash = ""

    # make sure the timestamp is an integer
    timestamp = parse_int(timestamp)

    method = method.upper()

    return TOSHI_SIGNATURE_DATA_STRING.format(VERB=method, PATH=path, TIMESTAMP=timestamp, HASH=datahash).encode('utf-8')
예제 #3
0
async def check_account_nonces(conf, dryrun=False):
    async with conf.db.id.acquire() as con:
        users = await con.fetch("SELECT dgas_id, payment_address FROM users")

    last_percent = -1
    async with conf.db.eth.acquire() as con:
        tr = con.transaction()
        await tr.start()
        for i, user in enumerate(users):
            percent = int((i / len(users)) * 100)
            if percent != last_percent:
                print("Progress: {}/{} ({}%)".format(i, len(users), percent))
                last_percent = percent
            from_address = user['payment_address']
            resp = await app.http.post(
                conf.urls.node,
                headers={'Content-Type': 'application/json'},
                data=json.dumps({
                    "jsonrpc": "2.0",
                    "id": random.randint(0, 1000000),
                    "method": "eth_getTransactionCount",
                    "params": [from_address]
                }).encode('utf-8'))
            if resp.status == 200:
                data = await resp.json()
                if 'result' in data and data['result'] is not None:
                    nonce = parse_int(data['result'])

                    res = await con.execute(
                        "UPDATE transactions SET last_status = 'error' WHERE from_address = $1 AND nonce >= $2 AND last_status != 'error'",
                        from_address, nonce)
                    if res != "UPDATE 0":
                        print("{}|{}: {}".format(user['dgas_id'], from_address,
                                                 res))

        if dryrun:
            await tr.rollback()
        else:
            await tr.commit()
        def test_vector(name, vector):
            if 'transaction' not in vector:
                return  # TODO: process rlp tests
            transaction = vector['transaction']
            tx = create_transaction(
                nonce=parse_int(transaction['nonce']),
                gasprice=parse_int(transaction['gasPrice']),
                startgas=parse_int(transaction['gasLimit']),
                to=transaction['to'],
                value=parse_int(transaction['value']),
                data=data_decoder(transaction['data']),
                v=parse_int(transaction['v']),
                r=parse_int(transaction['r']),
                s=parse_int(transaction['s']))
            self.assertEqual(data_encoder(tx.sender),
                             "0x{}".format(vector['sender']), name)
            self.assertEqual(calculate_transaction_hash(tx),
                             "0x{}".format(vector['hash']), name)
            self.assertEqual(encode_transaction(tx), vector['rlp'], name)

            # test decode transaction -> encode transaction round trip
            tx = decode_transaction(vector['rlp'])
            self.assertEqual(encode_transaction(tx), vector['rlp'], name)
예제 #5
0
        def verify_request(self):
            """Verifies that the signature and the payload match the expected address
            raising a JSONHTTPError (400) if something is wrong with the request"""

            if TOSHI_ID_ADDRESS_HEADER in self.request.headers:
                expected_address = self.request.headers[TOSHI_ID_ADDRESS_HEADER]
            elif self.get_argument(TOSHI_ID_ADDRESS_QUERY_ARG, None):
                expected_address = self.get_argument(TOSHI_ID_ADDRESS_QUERY_ARG)
            elif TOKEN_ID_ADDRESS_HEADER in self.request.headers:
                expected_address = self.request.headers[TOKEN_ID_ADDRESS_HEADER]
            elif self.get_argument(TOKEN_ID_ADDRESS_QUERY_ARG, None):
                expected_address = self.get_argument(TOKEN_ID_ADDRESS_QUERY_ARG)
            else:
                raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Missing Dgas-ID-Address'}]})

            if TOSHI_SIGNATURE_HEADER in self.request.headers:
                signature = self.request.headers[TOSHI_SIGNATURE_HEADER]
            elif self.get_argument(TOSHI_SIGNATURE_QUERY_ARG, None):
                signature = self.get_argument(TOSHI_SIGNATURE_QUERY_ARG)
            elif TOKEN_SIGNATURE_HEADER in self.request.headers:
                signature = self.request.headers[TOKEN_SIGNATURE_HEADER]
            elif self.get_argument(TOKEN_SIGNATURE_QUERY_ARG, None):
                signature = self.get_argument(TOKEN_SIGNATURE_QUERY_ARG)
            else:
                raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Missing Dgas-Signature'}]})

            if TOSHI_TIMESTAMP_HEADER in self.request.headers:
                timestamp = self.request.headers[TOSHI_TIMESTAMP_HEADER]
            elif self.get_argument(TOSHI_TIMESTAMP_QUERY_ARG, None):
                timestamp = self.get_argument(TOSHI_TIMESTAMP_QUERY_ARG)
            elif TOKEN_TIMESTAMP_HEADER in self.request.headers:
                timestamp = self.request.headers[TOKEN_TIMESTAMP_HEADER]
            elif self.get_argument(TOKEN_TIMESTAMP_QUERY_ARG, None):
                timestamp = self.get_argument(TOKEN_TIMESTAMP_QUERY_ARG)
            else:
                raise JSONHTTPError(400, body={'errors': [{'id': 'bad_arguments', 'message': 'Missing Dgas-Timestamp'}]})

            timestamp = parse_int(timestamp)
            if timestamp is None:
                raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_timestamp',
                                                           'message': 'Given Dgas-Timestamp is invalid'}]})

            if not validate_address(expected_address):
                raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_id_address', 'message': 'Invalid Dgas-ID-Address'}]})

            if not validate_signature(signature):
                raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_signature', 'message': 'Invalid Dgas-Signature'}]})

            try:
                signature = data_decoder(signature)
            except Exception:
                raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_signature', 'message': 'Invalid Dgas-Signature'}]})

            verb = self.request.method
            uri = self.request.path

            if self.request.body:
                datahash = self.request.body
            else:
                datahash = ""

            data_string = generate_request_signature_data_string(verb, uri, timestamp, datahash)

            if not ecrecover(data_string, signature, expected_address):
                raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_signature', 'message': 'Invalid Dgas-Signature'}]})

            if abs(int(time.time()) - timestamp) > TIMESTAMP_EXPIRY:
                raise JSONHTTPError(400, body={'errors': [{'id': 'invalid_timestamp',
                                                           'message': 'The difference between the timestamp and the current time is too large'}]})

            return expected_address
예제 #6
0
    def test_parse_int_string(self):

        self.assertEqual(parse_int("12345"), 12345)
예제 #7
0
    def test_parse_unicode(self):

        self.assertEqual(parse_int(u'12345'), 12345)
예제 #8
0
    def test_parse_bytes(self):

        self.assertEqual(parse_int(b"12345"), 12345)
예제 #9
0
    def test_parse_misc(self):

        self.assertEqual(parse_int({}), None)
예제 #10
0
    def test_parse_decimal(self):

        self.assertEqual(parse_int(Decimal("12345.6787")), 12345)
예제 #11
0
    def test_parse_float(self):

        self.assertEqual(parse_int(12345.45675), 12345)
예제 #12
0
    def test_parse_hex_string(self):

        self.assertEqual(parse_int("0x12345"), 74565)
예제 #13
0
    def test_parse_float_string(self):

        self.assertEqual(parse_int("12345.567678"), 12345)
예제 #14
0
    def test_parse_int_no_leading_zeros_string(self):

        self.assertEqual(parse_int("0123"), None)
예제 #15
0
    def test_parse_zero_int_string(self):

        self.assertEqual(parse_int("0"), 0)
예제 #16
0
    def test_parse_negative_int_string(self):

        self.assertEqual(parse_int("-12345"), -12345)
예제 #17
0
    def test_parse_none(self):

        self.assertEqual(parse_int(None), None)
    def get_balance(self, address, **kwargs):

        resp = self._fetch("/v1/balance/{}".format(address), "GET", **kwargs)
        return parse_int(resp["confirmed_balance"]), parse_int(
            resp["unconfirmed_balance"])