Exemple #1
0
    def test_submission_prepended_with_con_succeeds(self):
        w = Wallet()
        expected_processor = secrets.token_bytes(32)

        balances_key = '{}{}{}{}{}'.format('currency',
                                           config.INDEX_SEPARATOR,
                                           'balances',
                                           config.DELIMITER,
                                           w.verifying_key().hex())

        self.nonce_manager.set(balances_key, 500000)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='submission',
                                function='submit_contract',
                                kwargs={'name': 'con_bad_name', 'code': 'blah'},
                                stamps=3000,
                                processor=expected_processor,
                                nonce=0)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
Exemple #2
0
    def test_all_valid_with_stamps_when_balance_is_set(self):
        w = Wallet()
        expected_processor = secrets.token_bytes(32)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=0)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        balances_key = '{}{}{}{}{}'.format('currency',
                                           config.INDEX_SEPARATOR,
                                           'balances',
                                           config.DELIMITER,
                                           tx.payload.sender.hex())

        self.nonce_manager.set(balances_key, 500000)

        transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
        balance = self.nonce_manager.get(balances_key) or 0

        self.assertEqual(balance, 500000)
Exemple #3
0
    def test_sending_transfer_of_most_money_doesnt_fail_if_enough_stamps(self):
        self.nonce_manager.set_var('stamp_cost', 'S', ['value'], value=3000)

        w = Wallet()
        expected_processor = secrets.token_bytes(32)

        balances_key = '{}{}{}{}{}'.format('currency',
                                           config.INDEX_SEPARATOR,
                                           'balances',
                                           config.DELIMITER,
                                           w.verifying_key().hex())

        self.nonce_manager.set(balances_key, 500000)
        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 499990, 'to': 'jeff'},
                                stamps=3000,
                                processor=expected_processor,
                                nonce=0)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
Exemple #4
0
    def test_nonce_minus_pending_nonce_equal_tx_per_block_fails(self):
        w = Wallet()
        expected_processor = secrets.token_bytes(32)

        balances_key = '{}{}{}{}{}'.format('currency',
                                           config.INDEX_SEPARATOR,
                                           'balances',
                                           config.DELIMITER,
                                           w.verifying_key().hex())

        self.nonce_manager.set(balances_key, 500000)

        self.nonce_manager.set_nonce(processor=expected_processor, sender=w.verifying_key(), nonce=1)
        self.nonce_manager.set_pending_nonce(processor=expected_processor, sender=w.verifying_key(), nonce=16)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=16)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        with self.assertRaises(transaction.TransactionTooManyPendingException):
            transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
Exemple #5
0
    def test_processor_and_nonce_correct_but_not_enough_stamps_returns_false(self):
        w = Wallet()
        expected_processor = secrets.token_bytes(32)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=0)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        with self.assertRaises(transaction.TransactionSenderTooFewStamps):
            transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)

        balances_key = '{}{}{}{}{}'.format('currency',
                                           config.INDEX_SEPARATOR,
                                           'balances',
                                           config.DELIMITER,
                                           tx.payload.sender.hex())

        balance = self.nonce_manager.get(balances_key) or 0

        self.assertEqual(balance, 0)
Exemple #6
0
    def test_processor_is_expected_but_nonce_is_incorrect_returns_false(self):
        w = Wallet()
        expected_processor = secrets.token_bytes(32)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=1)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        with self.assertRaises(transaction.TransactionNonceInvalid):
            transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
Exemple #7
0
    def test_non_strict_fails_if_same_nonce(self):
        w = Wallet()
        expected_processor = secrets.token_bytes(32)

        balances_key = '{}{}{}{}{}'.format('currency',
                                           config.INDEX_SEPARATOR,
                                           'balances',
                                           config.DELIMITER,
                                           w.verifying_key().hex())

        self.nonce_manager.set(balances_key, 500000)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=0)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager,
                             strict=False)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=0)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        with self.assertRaises(transaction.TransactionNonceInvalid):
            transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager,
                                 strict=False)
Exemple #8
0
    def test_processor_and_nonce_correct_increments_pending_nonce_by_one(self):
        w = Wallet()
        expected_processor = secrets.token_bytes(32)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=10000,
                                processor=expected_processor,
                                nonce=0)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)

        pending_nonce = self.nonce_manager.get_pending_nonce(expected_processor, w.verifying_key())

        self.assertEqual(pending_nonce, 1)
Exemple #9
0
def process_transaction(tx: transaction_capnp.Transaction):
    # Deserialize?
    try:
        transaction_is_valid(tx=tx,
                             expected_processor=conf.HOST_VK,
                             driver=driver,
                             strict=True)
    except TransactionNonceInvalid:
        return {'error': 'Transaction nonce is invalid.'}
    except TransactionProcessorInvalid:
        return {
            'error': 'Transaction processor does not match expected processor.'
        }
    except TransactionTooManyPendingException:
        return {
            'error': 'Too many pending transactions currently in the block.'
        }
    except TransactionSenderTooFewStamps:
        return {
            'error':
            'Transaction sender has too few stamps for this transaction.'
        }
    except TransactionPOWProofInvalid:
        return {'error': 'Transaction proof of work is invalid.'}
    except TransactionSignatureInvalid:
        return {'error': 'Transaction is not signed by the sender.'}
    except TransactionStampsNegative:
        return {'error': 'Transaction has negative stamps supplied.'}

    # Pass protocol level variables into environment so they are accessible at runtime in smart contracts
    block_hash = driver.latest_block_hash
    block_num = driver.latest_block_num

    dt = datetime.utcfromtimestamp(tx.metadata.timestamp)
    dt_object = Datetime(year=dt.year,
                         month=dt.month,
                         day=dt.day,
                         hour=dt.hour,
                         minute=dt.minute,
                         second=dt.second,
                         microsecond=dt.microsecond)

    environment = {
        'block_hash': block_hash,
        'block_num': block_num,
        'now': dt_object
    }

    tx_output = execution.execute_tx(executor=client.executor,
                                     transaction=tx,
                                     environment=environment)

    client.executor.driver.commit()

    store_block(tx, block_hash, block_num)

    driver.commit_nonces()
    driver.delete_pending_nonces()

    tx_dict = tx_output.to_dict()

    state_changes = {}
    for item in tx_dict['state']:
        state_changes[item['key'].decode("utf-8")] = item['value'].decode(
            "utf-8")

    results = {
        'state_changes': state_changes,
        'status_code': tx_output.status,
        'stamps_used': tx_output.stampsUsed
    }

    return results
Exemple #10
0
    def test_multiple_nonces_in_sequence_all_verify(self):
        w = Wallet()
        expected_processor = secrets.token_bytes(32)

        balances_key = '{}{}{}{}{}'.format('currency',
                                           config.INDEX_SEPARATOR,
                                           'balances',
                                           config.DELIMITER,
                                           w.verifying_key().hex())

        self.nonce_manager.set(balances_key, 500000)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=0)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=1)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=2)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)

        tx = TransactionBuilder(w.verifying_key(),
                                contract='currency',
                                function='transfer',
                                kwargs={'amount': 10, 'to': 'jeff'},
                                stamps=500000,
                                processor=expected_processor,
                                nonce=3)

        tx.sign(w.signing_key())
        tx_bytes = tx.serialize()
        tx_struct = transaction_capnp.NewTransaction.from_bytes_packed(tx_bytes)

        transaction_is_valid(tx=tx_struct, expected_processor=expected_processor, driver=self.nonce_manager)
    async def submit_transaction(self, request):
        log.info(f'Got req:{request}')
        if len(self.queue) >= self.max_queue_len:
            return response.json({'error': "Queue full. Resubmit shortly."},
                                 status=503)

        # Try to deserialize transaction.
        try:
            tx = transaction_capnp.NewTransaction.from_bytes_packed(
                request.body)

        except Exception as e:
            return response.json({'error': 'Malformed transaction.'.format(e)},
                                 status=400)

        error = False
        msg = {'error': 'Unknown Error'}
        try:
            transaction_is_valid(
                tx=tx,
                expected_processor=self.wallet.verifying_key(),
                driver=self.driver,
                strict=True)

        # These exceptions are tested to work in the transaction_is_valid tests
        except TransactionNonceInvalid:
            msg = {'error': 'Transaction nonce is invalid.'}
            error = True
        except TransactionProcessorInvalid:
            msg = {
                'error':
                'Transaction processor does not match expected processor.'
            }
            error = True
        except TransactionTooManyPendingException:
            msg = {
                'error':
                'Too many pending transactions currently in the block.'
            }
            error = True
        except TransactionSenderTooFewStamps:
            msg = {
                'error':
                'Transaction sender has too few stamps for this transaction.'
            }
            error = True
        except TransactionPOWProofInvalid:
            msg = {'error': 'Transaction proof of work is invalid.'}
            error = True
        except TransactionSignatureInvalid:
            msg = {'error': 'Transaction is not signed by the sender.'}
            error = True
        except TransactionStampsNegative:
            msg = {'error': 'Transaction has negative stamps supplied.'}
            error = True

        if error:
            log.error(msg)
            return response.json(msg)

        # Put it in the rate limiter queue.
        log.info('Q TIME')
        self.queue.append(tx)

        tx_hash = tx_hash_from_tx(tx)

        return response.json({
            'success': 'Transaction successfully submitted to the network.',
            'hash': tx_hash.hex()
        })