Пример #1
0
 def commit_batch(self, three_pc_batch, prev_handler_result=None):
     committed_txns = prev_handler_result
     token_state_root, token_txn_root, _ = self.token_tracker.commit_batch()
     committed_seq_nos_with_fees = [
         get_seq_no(t) for t in committed_txns
         if self._fees_tracker.has_deducted_fees(get_type(t), get_seq_no(t))
     ]
     if len(committed_seq_nos_with_fees) > 0:
         # This is a fake txn only for commit to token ledger
         token_fake_three_pc_batch = ThreePcBatch(
             ledger_id=TOKEN_LEDGER_ID,
             inst_id=three_pc_batch.inst_id,
             view_no=three_pc_batch.view_no,
             pp_seq_no=three_pc_batch.pp_seq_no,
             pp_time=three_pc_batch.pp_time,
             state_root=token_state_root,
             txn_root=txn_root_serializer.serialize(token_txn_root),
             primaries=three_pc_batch.primaries,
             valid_digests=[
                 i for i in range(len(committed_seq_nos_with_fees))
             ])
         committed_token_txns = super()._commit(self.token_ledger,
                                                self.token_state,
                                                token_fake_three_pc_batch)
         TokenStaticHelper.commit_to_utxo_cache(self.utxo_cache,
                                                token_state_root)
         i = 0
         # We are adding fees txn to the reply, so that client could get information about token transition
         for txn in committed_txns:
             if get_seq_no(txn) in committed_seq_nos_with_fees:
                 txn[FEES] = committed_token_txns[i]
                 i += 1
         self._fees_tracker.fees_in_current_batch = 0
     return committed_txns
Пример #2
0
def test_get_more_then_thousand_utxos(helpers, addresses,
                                      nodeSetWithIntegratedTokenPlugin):
    """
    test if we send more have more than a 1000 UTXO's we still receive a response.
    """

    _, address_2 = addresses

    states = [
        n.db_manager.get_state(TOKEN_LEDGER_ID)
        for n in nodeSetWithIntegratedTokenPlugin
    ]
    utxos = []

    for i in range(UTXO_LIMIT + 200):
        amount = randint(1, 5)
        key = TokenStaticHelper.create_state_key(
            libsovtoken_address_to_address(address_2), i + 5)
        utxos.append((key, amount))
        for state in states:
            state.set(key, str(amount).encode())

    request = helpers.request.get_utxo(address_2)
    responses = helpers.sdk.send_and_check_request_objects([request])
    for response in responses:
        result = response[1]['result']
        assert len(result[OUTPUTS]) == UTXO_LIMIT
        for output in result[OUTPUTS]:
            assert (TokenStaticHelper.create_state_key(output[ADDRESS],
                                                       output[SEQNO]),
                    output[AMOUNT]) in utxos
        assert result.get(NEXT_SEQNO, None)
Пример #3
0
    def _validate_fees_can_pay(self, request, inputs, outputs, required_fees):
        """
        Calculate and verify that inputs and outputs for fees can both be paid and change is properly specified

        This function ASSUMES that validation of the fees for the request has already been done.

        :param request:
        :param required_fees:
        :return:
        """

        try:
            sum_inputs = self.utxo_cache.sum_inputs(inputs, is_committed=False)
        except UTXOError as ex:
            raise InvalidFundsError(request.identifier, request.reqId,
                                    "{}".format(ex))
        except Exception as ex:
            error = 'Exception {} while processing inputs/outputs'.format(ex)
            raise UnauthorizedClientRequest(request.identifier, request.reqId,
                                            error)
        else:
            change_amount = sum([a[AMOUNT] for a in outputs])
            expected_amount = change_amount + required_fees
            TokenStaticHelper.validate_given_inputs_outputs(
                sum_inputs, change_amount, expected_amount, request,
                'fees: {}'.format(required_fees))
Пример #4
0
 def update_state(self, txn, prev_result, request, is_committed=False):
     try:
         payload = get_payload_data(txn)
         seq_no = get_seq_no(txn)
         for output in payload[OUTPUTS]:
             TokenStaticHelper.add_new_output(
                 self.state,
                 self.database_manager.get_store(UTXO_CACHE_LABEL),
                 Output(output["address"], seq_no, output["amount"]),
                 is_committed=is_committed)
     except UTXOError as ex:
         error = 'Exception {} while updating state'.format(ex)
         raise OperationError(error)
Пример #5
0
 def update_token_state(self, txn, request, is_committed=False):
     for utxo in txn[TXN_PAYLOAD][TXN_PAYLOAD_DATA][INPUTS]:
         TokenStaticHelper.spend_input(state=self.token_state,
                                       utxo_cache=self.utxo_cache,
                                       address=utxo[ADDRESS],
                                       seq_no=utxo[SEQNO],
                                       is_committed=is_committed)
     seq_no = get_seq_no(txn)
     for output in txn[TXN_PAYLOAD][TXN_PAYLOAD_DATA][OUTPUTS]:
         TokenStaticHelper.add_new_output(state=self.token_state,
                                          utxo_cache=self.utxo_cache,
                                          output=Output(
                                              output[ADDRESS], seq_no,
                                              output[AMOUNT]),
                                          is_committed=is_committed)
Пример #6
0
    def _do_validate_inputs_ouputs(self, request):
        try:
            sum_in = TokenStaticHelper.sum_inputs(self.utxo_cache,
                                                  request,
                                                  is_committed=False)

            sum_out = TokenStaticHelper.sum_outputs(request)
        except Exception as ex:
            if isinstance(ex, InvalidClientMessageException):
                raise ex
            error = 'Exception {} while processing inputs/outputs'.format(ex)
            raise InvalidClientMessageException(
                request.identifier, getattr(request, 'reqId', None), error)
        else:
            return TokenStaticHelper.validate_given_inputs_outputs(
                sum_in, sum_out, sum_out, request)
Пример #7
0
def insert_over_thousand_utxos(db_manager, payment_address):
    token_state = db_manager.get_state(TOKEN_LEDGER_ID)
    for i in range(1200):
        token_state.set(
            TokenStaticHelper.create_state_key(
                libsovtoken_address_to_address(payment_address), i),
            str(i).encode())
Пример #8
0
def insert_utxos_after_gap(db_manager, payment_address):
    token_state = db_manager.get_state(TOKEN_LEDGER_ID)
    for i in range(1300, 2400):
        token_state.set(
            TokenStaticHelper.create_state_key(
                libsovtoken_address_to_address(payment_address), i),
            str(i).encode())
    return 1300
Пример #9
0
    def get_result(self, request: Request):
        address = request.operation[ADDRESS]
        from_seqno = request.operation.get(FROM_SEQNO)
        encoded_root_hash = state_roots_serializer.serialize(
            bytes(self.state.committedHeadHash))
        proof, rv = self.state.generate_state_proof_for_keys_with_prefix(
            address, serialize=True, get_value=True)
        multi_sig = self.database_manager.bls_store.get(encoded_root_hash)
        if multi_sig:
            encoded_proof = proof_nodes_serializer.serialize(proof)
            proof = {
                MULTI_SIGNATURE: multi_sig.as_dict(),
                ROOT_HASH: encoded_root_hash,
                PROOF_NODES: encoded_proof
            }
        else:
            proof = {}

        # The outputs need to be returned in sorted order since each node's reply should be same.
        # Since no of outputs can be large, a concious choice to not use `operator.attrgetter` on an
        # already constructed list was made
        outputs = SortedItems()
        for k, v in rv.items():
            addr, seq_no = TokenStaticHelper.parse_state_key(k.decode())
            amount = rlp_decode(v)[0]
            if not amount:
                continue
            outputs.add(Output(addr, int(seq_no), int(amount)))

        utxos = outputs.sorted_list
        next_seqno = None
        if from_seqno:
            idx = next((idx for utxo, idx in zip(utxos, range(len(utxos)))
                        if utxo.seqNo >= from_seqno), None)
            if idx:
                utxos = utxos[idx:]
            else:
                utxos = []
        if len(utxos) > UTXO_LIMIT:
            next_seqno = utxos[UTXO_LIMIT].seqNo
            utxos = utxos[:UTXO_LIMIT]

        result = {
            f.IDENTIFIER.nm: request.identifier,
            f.REQ_ID.nm: request.reqId,
            OUTPUTS: utxos
        }

        result.update(request.operation)
        if next_seqno:
            result[NEXT_SEQNO] = next_seqno
        if proof:
            res_sub = deepcopy(result)
            res_sub[STATE_PROOF] = proof
            if len(json.dumps(res_sub)) <= self._msg_limit:
                result = res_sub
        return result
Пример #10
0
 def update_state(self, txn, prev_result, request, is_committed=False):
     try:
         payload = get_payload_data(txn)
         for inp in payload[INPUTS]:
             TokenStaticHelper.spend_input(self.state,
                                           self.utxo_cache,
                                           inp["address"],
                                           inp["seqNo"],
                                           is_committed=is_committed)
         for output in payload[OUTPUTS]:
             seq_no = get_seq_no(txn)
             TokenStaticHelper.add_new_output(self.state,
                                              self.utxo_cache,
                                              Output(
                                                  output["address"], seq_no,
                                                  output["amount"]),
                                              is_committed=is_committed)
     except UTXOError as ex:
         error = 'Exception {} while updating state'.format(ex)
         raise OperationError(error)
Пример #11
0
def test_get_more_then_thousand_utxos_with_from(
        helpers, addresses, nodeSetWithIntegratedTokenPlugin):
    """
    test if we send more have more than a thousand of UTXO's we will still receive a response.
    """

    address_1, address_2 = addresses

    states = [
        n.db_manager.get_state(TOKEN_LEDGER_ID)
        for n in nodeSetWithIntegratedTokenPlugin
    ]
    utxos = []

    for i in range(UTXO_LIMIT + 200):
        amount = randint(1, 5)
        seq_no = i + 5
        key = TokenStaticHelper.create_state_key(
            libsovtoken_address_to_address(address_2), seq_no)
        utxos.append((key, amount, seq_no))
        for state in states:
            state.set(key, str(amount).encode())

    # NB: this transaction is needed just to update bls_store with new root hash
    total = 1000
    outputs = [{"address": address_1, "amount": total}]
    mint_result = helpers.general.do_mint(outputs)

    shift = 50
    request = helpers.request.get_utxo(address_2, utxos[shift][2])
    responses = helpers.sdk.send_and_check_request_objects([request])
    utxos = utxos[shift:shift + UTXO_LIMIT]
    for response in responses:
        result = response[1]['result']
        assert result[STATE_PROOF]
        assert len(result[OUTPUTS]) == UTXO_LIMIT
        for output in result[OUTPUTS]:
            assert (TokenStaticHelper.create_state_key(output[ADDRESS],
                                                       output[SEQNO]),
                    output[AMOUNT], output[SEQNO]) in utxos
        assert result.get(NEXT_SEQNO)
def make_tokens(helpers, nodeSetWithIntegratedTokenPlugin, addresses):
    address, address_2 = addresses
    states = [n.db_manager.get_state(TOKEN_LEDGER_ID) for n in nodeSetWithIntegratedTokenPlugin]
    utxos = []

    for i in range(UTXO_LIMIT+200):
        amount = randint(1, 5)
        seq_no = i+5
        key = TokenStaticHelper.create_state_key(libsovtoken_address_to_address(address), seq_no)
        utxos.append((key, amount, seq_no))
        for state in states:
            state.set(key, str(amount).encode())

    total = 1000
    outputs = [{"address": address_2, "amount": total}]
    helpers.general.do_mint(outputs)
Пример #13
0
def test_xfer_public_txn_inputs_not_greater():
    with pytest.raises(ExtraFundsError):
        TokenStaticHelper.validate_given_inputs_outputs(2, 1, 1, None)

    with pytest.raises(InvalidClientMessageException):
        TokenStaticHelper.validate_given_inputs_outputs(1, 2, 2, None)

    with pytest.raises(InvalidClientMessageException):
        TokenStaticHelper.validate_given_inputs_outputs(
            100000000000000000000000, 100000000000000000000001,
            100000000000000000000001, None)
Пример #14
0
def test_state_after_xfer(helpers, initial_mint, addresses,
                          nodeSetWithIntegratedTokenPlugin):

    mint_seq_no = get_seq_no(initial_mint)
    [address1, address2, *_] = addresses

    inputs = helpers.general.get_utxo_addresses([address1])
    inputs = [utxo for utxos in inputs for utxo in utxos]
    outputs = [{"address": address2, "amount": 100}]

    helpers.general.do_transfer(inputs, outputs)
    key = TokenStaticHelper.create_state_key(
        libsovtoken_address_to_address(address1), mint_seq_no)

    for n in nodeSetWithIntegratedTokenPlugin:
        res = n.db_manager.get_state(TOKEN_LEDGER_ID).get(key)
        assert not res
Пример #15
0
def test_state_proof(public_minting, looper,  # noqa
                     sdk_pool_handle, sdk_wallet_client,
                     seller_token_wallet, seller_address,
                     user1_token_wallet, user1_address):
    res = send_get_utxo(looper, seller_address, sdk_wallet_client, sdk_pool_handle)
    update_token_wallet_with_result(seller_token_wallet, res)

    # Do 20 XFER txns
    for _ in range(20):
        utxos = [_ for lst in
                 seller_token_wallet.get_all_wallet_utxos().values()
                 for _ in lst]
        seq_no, amount = utxos[0]
        inputs = [[seller_token_wallet, seller_address, seq_no]]
        outputs = [{"address": user1_address, "amount": 1}, {"address": seller_address, "amount": amount-1}]
        res = send_xfer(looper, inputs, outputs, sdk_pool_handle)
        update_token_wallet_with_result(seller_token_wallet, res)
        res = send_get_utxo(looper, seller_address, sdk_wallet_client,
                            sdk_pool_handle)
        update_token_wallet_with_result(seller_token_wallet, res)
        res = send_get_utxo(looper, user1_address, sdk_wallet_client,
                            sdk_pool_handle)
        update_token_wallet_with_result(user1_token_wallet, res)

    res = send_get_utxo(looper, user1_address, sdk_wallet_client,
                        sdk_pool_handle)

    # Check presence of state proof
    assert res[STATE_PROOF]
    encoded = {}
    outputs = res[OUTPUTS]
    for out in outputs:
        state_key = TokenStaticHelper.create_state_key(out["address"], out["seqNo"])
        encoded[state_key] = rlp_encode([str(out["amount"])])
    proof_nodes = decode_proof(res[STATE_PROOF][PROOF_NODES])
    client_trie = Trie(PersistentDB(KeyValueStorageInMemory()))
    assert client_trie.verify_spv_proof_multi(
        state_roots_serializer.deserialize(res[STATE_PROOF][ROOT_HASH]),
        encoded, proof_nodes)
Пример #16
0
def test_token_req_handler_update_state_XFER_PUBLIC_success(
        helpers, addresses, xfer_handler_a):
    [address1, address2] = addresses
    seq_no = 1

    inputs = [{"source": utxo_from_addr_and_seq_no(address1, seq_no)}]
    outputs = [{"address": address2, "amount": 40}]
    request = helpers.request.transfer(inputs, outputs)
    txn = reqToTxn(request)
    append_txn_metadata(txn, seq_no=seq_no)

    xfer_handler_a.dynamic_validation(request)
    xfer_handler_a.update_state(txn, None, request)

    state_key = TokenStaticHelper.create_state_key(
        libsovtoken_address_to_address(address1), seq_no)
    utxo_cache = xfer_handler_a.database_manager.get_store(UTXO_CACHE_LABEL)
    key = utxo_cache._create_key(
        Output(libsovtoken_address_to_address(address1), seq_no, 60))
    assert utxo_cache._store._has_key(key)
    try:
        xfer_handler_a.state.get(state_key, False)
    except Exception:
        pytest.fail("This state key isn't in the state")
Пример #17
0
def test_token_req_handler_commit_batch_different_state_root(xfer_handler_a):
    utxo_cache = xfer_handler_a.database_manager.get_store(UTXO_CACHE_LABEL)
    with pytest.raises(TokenValueError):
        TokenStaticHelper.commit_to_utxo_cache(utxo_cache, 1)
def add_utxo(payment_address, get_utxo_handler):
    get_utxo_handler.state.set(
        TokenStaticHelper.create_state_key(
            libsovtoken_address_to_address(payment_address), 1), "3".encode())
 def commit_batch(self, three_pc_batch, prev_handler_result=None):
     TokenStaticHelper.commit_to_utxo_cache(self.utxo_cache,
                                            three_pc_batch.state_root)
Пример #20
0
 def create_state_key(address: str, seq_no: int) -> bytes:
     return TokenStaticHelper.create_state_key(address=address,
                                               seq_no=seq_no)
Пример #21
0
def test_xfer_public_txn_equal():
    TokenStaticHelper.validate_given_inputs_outputs(1, 1, 1, None)
    TokenStaticHelper.validate_given_inputs_outputs(10, 10, 10, None)
    TokenStaticHelper.validate_given_inputs_outputs(100, 100, 100, None)
    TokenStaticHelper.validate_given_inputs_outputs(100000000000000,
                                                    100000000000000,
                                                    100000000000000, None)
    TokenStaticHelper.validate_given_inputs_outputs(9223372036854775807,
                                                    9223372036854775807,
                                                    9223372036854775807, None)
    TokenStaticHelper.validate_given_inputs_outputs(9223372036854775807000,
                                                    9223372036854775807000,
                                                    9223372036854775807000,
                                                    None)