예제 #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)