moved methods used by testing to tests/utils.py

Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
This commit is contained in:
Jürgen Eckel 2023-02-27 13:07:34 +01:00
parent 5f5a610cf1
commit 2cac403a1d
No known key found for this signature in database
3 changed files with 90 additions and 85 deletions

View File

@ -12,15 +12,14 @@ from planetmint.backend.connection import Connection
from planetmint.backend.tarantool.const import TARANT_TABLE_TRANSACTION, TARANT_TABLE_GOVERNANCE
from planetmint.model.fastquery import FastQuery
from planetmint.abci.tendermint_utils import key_from_base64
from planetmint.abci.tendermint_utils import merkleroot
from hashlib import sha3_256
from planetmint.backend.models.block import Block
from planetmint.backend.models.output import Output
from planetmint.backend.models.asset import Asset
from planetmint.backend.models.input import Input
from planetmint.backend.models.metadata import MetaData
from planetmint.backend.models.dbtransaction import DbTransaction
class Models:
def __init__(self, database_connection = None):
config_utils.autoconfigure()
@ -142,77 +141,6 @@ class Models:
return validators
def tests_update_utxoset(self, transaction):
self.updated__ = """Update the UTXO set given ``transaction``. That is, remove
the outputs that the given ``transaction`` spends, and add the
outputs that the given ``transaction`` creates.
Args:
transaction (:obj:`~planetmint.models.Transaction`): A new
transaction incoming into the system for which the UTXOF
set needs to be updated.
"""
spent_outputs = [spent_output for spent_output in transaction.spent_outputs]
if spent_outputs:
self.tests_delete_unspent_outputs(*spent_outputs)
self.tests_store_unspent_outputs(*[utxo._asdict() for utxo in transaction.unspent_outputs])
def tests_store_unspent_outputs(self, *unspent_outputs):
"""Store the given ``unspent_outputs`` (utxos).
Args:
*unspent_outputs (:obj:`tuple` of :obj:`dict`): Variable
length tuple or list of unspent outputs.
"""
if unspent_outputs:
return backend.query.store_unspent_outputs(self.connection, *unspent_outputs)
def tests_get_utxoset_merkle_root(self):
"""Returns the merkle root of the utxoset. This implies that
the utxoset is first put into a merkle tree.
For now, the merkle tree and its root will be computed each
time. This obviously is not efficient and a better approach
that limits the repetition of the same computation when
unnecesary should be sought. For instance, future optimizations
could simply re-compute the branches of the tree that were
affected by a change.
The transaction hash (id) and output index should be sufficient
to uniquely identify a utxo, and consequently only that
information from a utxo record is needed to compute the merkle
root. Hence, each node of the merkle tree should contain the
tuple (txid, output_index).
.. important:: The leaves of the tree will need to be sorted in
some kind of lexicographical order.
Returns:
str: Merkle root in hexadecimal form.
"""
utxoset = backend.query.get_unspent_outputs(self.connection)
# TODO Once ready, use the already pre-computed utxo_hash field.
# See common/transactions.py for details.
hashes = [
sha3_256("{}{}".format(utxo["transaction_id"], utxo["output_index"]).encode()).digest() for utxo in utxoset
]
# TODO Notice the sorted call!
return merkleroot(sorted(hashes))
def tests_delete_unspent_outputs(self, *unspent_outputs):
"""Deletes the given ``unspent_outputs`` (utxos).
Args:
*unspent_outputs (:obj:`tuple` of :obj:`dict`): Variable
length tuple or list of unspent outputs.
"""
if unspent_outputs:
return backend.query.delete_unspent_outputs(self.connection, *unspent_outputs)
def get_spent(self, txid, output, current_transactions=[]) -> DbTransaction:
transactions = backend.query.get_spent(self.connection, txid, output)

View File

@ -23,6 +23,9 @@ from uuid import uuid4
from planetmint.abci.rpc import ABCI_RPC
from planetmint.abci.rpc import MODE_COMMIT, MODE_LIST
from tests.utils import delete_unspent_outputs, get_utxoset_merkle_root, store_unspent_outputs, \
update_utxoset
@pytest.mark.bdb
def test_asset_is_separated_from_transaciton(b):
@ -149,13 +152,13 @@ def test_post_transaction_invalid_mode(b, test_abci_rpc):
@pytest.mark.bdb
def test_update_utxoset(b, signed_create_tx, signed_transfer_tx, db_conn):
b.models.tests_update_utxoset(signed_create_tx)
update_utxoset(b.models.connection, signed_create_tx)
utxoset = db_conn.get_space("utxos")
assert utxoset.select().rowcount == 1
utxo = utxoset.select().data
assert utxo[0][1] == signed_create_tx.id
assert utxo[0][2] == 0
b.models.tests_update_utxoset(signed_transfer_tx)
update_utxoset(b.models.connection, signed_transfer_tx)
assert utxoset.select().rowcount == 1
utxo = utxoset.select().data
assert utxo[0][1] == signed_transfer_tx.id
@ -184,7 +187,7 @@ def test_store_bulk_transaction(mocker, b, signed_create_tx, signed_transfer_tx)
def test_delete_zero_unspent_outputs(b, utxoset):
unspent_outputs, utxo_collection = utxoset
num_rows_before_operation = utxo_collection.select().rowcount
delete_res = b.models.tests_delete_unspent_outputs() # noqa: F841
delete_res = delete_unspent_outputs(b.models.connection) # noqa: F841
num_rows_after_operation = utxo_collection.select().rowcount
# assert delete_res is None
assert num_rows_before_operation == num_rows_after_operation
@ -197,7 +200,7 @@ def test_delete_one_unspent_outputs(b, dummy_unspent_outputs):
res = utxo_space.insert((uuid4().hex, utxo["transaction_id"], utxo["output_index"], utxo))
assert res
b.models.tests_delete_unspent_outputs(dummy_unspent_outputs[0])
delete_unspent_outputs(b.models.connection, dummy_unspent_outputs[0])
res1 = utxo_space.select(["a", 1], index="utxo_by_transaction_id_and_output_index").data
res2 = utxo_space.select(["b", 0], index="utxo_by_transaction_id_and_output_index").data
assert len(res1) + len(res2) == 2
@ -212,7 +215,7 @@ def test_delete_many_unspent_outputs(b, dummy_unspent_outputs):
res = utxo_space.insert((uuid4().hex, utxo["transaction_id"], utxo["output_index"], utxo))
assert res
b.models.tests_delete_unspent_outputs(*dummy_unspent_outputs[::2])
delete_unspent_outputs(b.models.connection, *dummy_unspent_outputs[::2])
res1 = utxo_space.select(["a", 0], index="utxo_by_transaction_id_and_output_index").data
res2 = utxo_space.select(["b", 0], index="utxo_by_transaction_id_and_output_index").data
assert len(res1) + len(res2) == 0
@ -224,7 +227,7 @@ def test_delete_many_unspent_outputs(b, dummy_unspent_outputs):
def test_store_zero_unspent_output(b):
utxos = b.models.connection.get_space("utxos")
num_rows_before_operation = utxos.select().rowcount
res = b.models.tests_store_unspent_outputs()
res = store_unspent_outputs(b.models.connection)
num_rows_after_operation = utxos.select().rowcount
assert res is None
assert num_rows_before_operation == num_rows_after_operation
@ -234,7 +237,7 @@ def test_store_zero_unspent_output(b):
def test_store_one_unspent_output(b, unspent_output_1, utxo_collection):
from planetmint.backend.tarantool.connection import TarantoolDBConnection
res = b.models.tests_store_unspent_outputs(unspent_output_1)
res = store_unspent_outputs(b.models.connection, unspent_output_1)
if not isinstance(b.models.connection, TarantoolDBConnection):
assert res.acknowledged
assert len(list(res)) == 1
@ -258,14 +261,14 @@ def test_store_one_unspent_output(b, unspent_output_1, utxo_collection):
@pytest.mark.bdb
def test_store_many_unspent_outputs(b, unspent_outputs):
b.models.tests_store_unspent_outputs(*unspent_outputs)
store_unspent_outputs(b.models.connection, *unspent_outputs)
utxo_space = b.models.connection.get_space("utxos")
res = utxo_space.select([unspent_outputs[0]["transaction_id"]], index="utxos_by_transaction_id")
assert len(res.data) == 3
def test_get_utxoset_merkle_root_when_no_utxo(b):
assert b.models.tests_get_utxoset_merkle_root() == sha3_256(b"").hexdigest()
assert get_utxoset_merkle_root(b.models.connection) == sha3_256(b"").hexdigest()
@pytest.mark.bdb
@ -276,7 +279,7 @@ def test_get_utxoset_merkle_root(b, dummy_unspent_outputs):
assert res
expected_merkle_root = "86d311c03115bf4d287f8449ca5828505432d69b82762d47077b1c00fe426eac"
merkle_root = b.models.tests_get_utxoset_merkle_root()
merkle_root = get_utxoset_merkle_root(b.models.connection)
assert merkle_root == expected_merkle_root

View File

@ -2,6 +2,7 @@
# Planetmint and IPDB software contributors.
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
from hashlib import sha3_256
import base58
import base64
@ -9,6 +10,7 @@ import random
from functools import singledispatch
from planetmint import backend
from planetmint.abci.rpc import ABCI_RPC
from planetmint.backend.localmongodb.connection import LocalMongoDBConnection
from planetmint.backend.tarantool.connection import TarantoolDBConnection
@ -18,7 +20,7 @@ from transactions.common.transaction_mode_types import BROADCAST_TX_COMMIT
from transactions.types.assets.create import Create
from transactions.types.elections.vote import Vote
from transactions.types.elections.validator_utils import election_id_to_public_key
from planetmint.abci.tendermint_utils import key_to_base64
from planetmint.abci.tendermint_utils import key_to_base64, merkleroot
from planetmint.abci.rpc import MODE_COMMIT, MODE_LIST
@ -123,3 +125,75 @@ def generate_election(b, cls, public_key, private_key, asset_data, voter_keys):
v.sign([key])
return election, votes
def delete_unspent_outputs(connection, *unspent_outputs):
"""Deletes the given ``unspent_outputs`` (utxos).
Args:
*unspent_outputs (:obj:`tuple` of :obj:`dict`): Variable
length tuple or list of unspent outputs.
"""
if unspent_outputs:
return backend.query.delete_unspent_outputs(connection, *unspent_outputs)
def get_utxoset_merkle_root(connection):
"""Returns the merkle root of the utxoset. This implies that
the utxoset is first put into a merkle tree.
For now, the merkle tree and its root will be computed each
time. This obviously is not efficient and a better approach
that limits the repetition of the same computation when
unnecesary should be sought. For instance, future optimizations
could simply re-compute the branches of the tree that were
affected by a change.
The transaction hash (id) and output index should be sufficient
to uniquely identify a utxo, and consequently only that
information from a utxo record is needed to compute the merkle
root. Hence, each node of the merkle tree should contain the
tuple (txid, output_index).
.. important:: The leaves of the tree will need to be sorted in
some kind of lexicographical order.
Returns:
str: Merkle root in hexadecimal form.
"""
utxoset = backend.query.get_unspent_outputs(connection)
# TODO Once ready, use the already pre-computed utxo_hash field.
# See common/transactions.py for details.
hashes = [
sha3_256("{}{}".format(utxo["transaction_id"], utxo["output_index"]).encode()).digest() for utxo in utxoset
]
# TODO Notice the sorted call!
return merkleroot(sorted(hashes))
def store_unspent_outputs(connection, *unspent_outputs):
"""Store the given ``unspent_outputs`` (utxos).
Args:
*unspent_outputs (:obj:`tuple` of :obj:`dict`): Variable
length tuple or list of unspent outputs.
"""
if unspent_outputs:
return backend.query.store_unspent_outputs(connection, *unspent_outputs)
def update_utxoset(connection, transaction):
"""
Update the UTXO set given ``transaction``. That is, remove
the outputs that the given ``transaction`` spends, and add the
outputs that the given ``transaction`` creates.
Args:
transaction (:obj:`~planetmint.models.Transaction`): A new
transaction incoming into the system for which the UTXOF
set needs to be updated.
"""
spent_outputs = [spent_output for spent_output in transaction.spent_outputs]
if spent_outputs:
delete_unspent_outputs(connection, *spent_outputs)
store_unspent_outputs(connection, *[utxo._asdict() for utxo in transaction.unspent_outputs])