mirror of
https://github.com/planetmint/planetmint.git
synced 2025-07-01 10:22:30 +00:00
moved methods used by testing to tests/utils.py
Signed-off-by: Jürgen Eckel <juergen@riddleandcode.com>
This commit is contained in:
parent
5f5a610cf1
commit
2cac403a1d
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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])
|
Loading…
x
Reference in New Issue
Block a user