mirror of
https://github.com/planetmint/planetmint.git
synced 2025-07-02 02:42:29 +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.backend.tarantool.const import TARANT_TABLE_TRANSACTION, TARANT_TABLE_GOVERNANCE
|
||||||
from planetmint.model.fastquery import FastQuery
|
from planetmint.model.fastquery import FastQuery
|
||||||
from planetmint.abci.tendermint_utils import key_from_base64
|
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.block import Block
|
||||||
from planetmint.backend.models.output import Output
|
from planetmint.backend.models.output import Output
|
||||||
from planetmint.backend.models.asset import Asset
|
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.metadata import MetaData
|
||||||
from planetmint.backend.models.dbtransaction import DbTransaction
|
from planetmint.backend.models.dbtransaction import DbTransaction
|
||||||
|
|
||||||
|
|
||||||
class Models:
|
class Models:
|
||||||
def __init__(self, database_connection = None):
|
def __init__(self, database_connection = None):
|
||||||
config_utils.autoconfigure()
|
config_utils.autoconfigure()
|
||||||
@ -142,77 +141,6 @@ class Models:
|
|||||||
|
|
||||||
return validators
|
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:
|
def get_spent(self, txid, output, current_transactions=[]) -> DbTransaction:
|
||||||
transactions = backend.query.get_spent(self.connection, txid, output)
|
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 ABCI_RPC
|
||||||
from planetmint.abci.rpc import MODE_COMMIT, MODE_LIST
|
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
|
@pytest.mark.bdb
|
||||||
def test_asset_is_separated_from_transaciton(b):
|
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
|
@pytest.mark.bdb
|
||||||
def test_update_utxoset(b, signed_create_tx, signed_transfer_tx, db_conn):
|
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")
|
utxoset = db_conn.get_space("utxos")
|
||||||
assert utxoset.select().rowcount == 1
|
assert utxoset.select().rowcount == 1
|
||||||
utxo = utxoset.select().data
|
utxo = utxoset.select().data
|
||||||
assert utxo[0][1] == signed_create_tx.id
|
assert utxo[0][1] == signed_create_tx.id
|
||||||
assert utxo[0][2] == 0
|
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
|
assert utxoset.select().rowcount == 1
|
||||||
utxo = utxoset.select().data
|
utxo = utxoset.select().data
|
||||||
assert utxo[0][1] == signed_transfer_tx.id
|
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):
|
def test_delete_zero_unspent_outputs(b, utxoset):
|
||||||
unspent_outputs, utxo_collection = utxoset
|
unspent_outputs, utxo_collection = utxoset
|
||||||
num_rows_before_operation = utxo_collection.select().rowcount
|
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
|
num_rows_after_operation = utxo_collection.select().rowcount
|
||||||
# assert delete_res is None
|
# assert delete_res is None
|
||||||
assert num_rows_before_operation == num_rows_after_operation
|
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))
|
res = utxo_space.insert((uuid4().hex, utxo["transaction_id"], utxo["output_index"], utxo))
|
||||||
assert res
|
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
|
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
|
res2 = utxo_space.select(["b", 0], index="utxo_by_transaction_id_and_output_index").data
|
||||||
assert len(res1) + len(res2) == 2
|
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))
|
res = utxo_space.insert((uuid4().hex, utxo["transaction_id"], utxo["output_index"], utxo))
|
||||||
assert res
|
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
|
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
|
res2 = utxo_space.select(["b", 0], index="utxo_by_transaction_id_and_output_index").data
|
||||||
assert len(res1) + len(res2) == 0
|
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):
|
def test_store_zero_unspent_output(b):
|
||||||
utxos = b.models.connection.get_space("utxos")
|
utxos = b.models.connection.get_space("utxos")
|
||||||
num_rows_before_operation = utxos.select().rowcount
|
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
|
num_rows_after_operation = utxos.select().rowcount
|
||||||
assert res is None
|
assert res is None
|
||||||
assert num_rows_before_operation == num_rows_after_operation
|
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):
|
def test_store_one_unspent_output(b, unspent_output_1, utxo_collection):
|
||||||
from planetmint.backend.tarantool.connection import TarantoolDBConnection
|
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):
|
if not isinstance(b.models.connection, TarantoolDBConnection):
|
||||||
assert res.acknowledged
|
assert res.acknowledged
|
||||||
assert len(list(res)) == 1
|
assert len(list(res)) == 1
|
||||||
@ -258,14 +261,14 @@ def test_store_one_unspent_output(b, unspent_output_1, utxo_collection):
|
|||||||
|
|
||||||
@pytest.mark.bdb
|
@pytest.mark.bdb
|
||||||
def test_store_many_unspent_outputs(b, unspent_outputs):
|
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")
|
utxo_space = b.models.connection.get_space("utxos")
|
||||||
res = utxo_space.select([unspent_outputs[0]["transaction_id"]], index="utxos_by_transaction_id")
|
res = utxo_space.select([unspent_outputs[0]["transaction_id"]], index="utxos_by_transaction_id")
|
||||||
assert len(res.data) == 3
|
assert len(res.data) == 3
|
||||||
|
|
||||||
|
|
||||||
def test_get_utxoset_merkle_root_when_no_utxo(b):
|
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
|
@pytest.mark.bdb
|
||||||
@ -276,7 +279,7 @@ def test_get_utxoset_merkle_root(b, dummy_unspent_outputs):
|
|||||||
assert res
|
assert res
|
||||||
|
|
||||||
expected_merkle_root = "86d311c03115bf4d287f8449ca5828505432d69b82762d47077b1c00fe426eac"
|
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
|
assert merkle_root == expected_merkle_root
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# Planetmint and IPDB software contributors.
|
# Planetmint and IPDB software contributors.
|
||||||
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
||||||
# Code is Apache-2.0 and docs are CC-BY-4.0
|
# Code is Apache-2.0 and docs are CC-BY-4.0
|
||||||
|
from hashlib import sha3_256
|
||||||
|
|
||||||
import base58
|
import base58
|
||||||
import base64
|
import base64
|
||||||
@ -9,6 +10,7 @@ import random
|
|||||||
|
|
||||||
from functools import singledispatch
|
from functools import singledispatch
|
||||||
|
|
||||||
|
from planetmint import backend
|
||||||
from planetmint.abci.rpc import ABCI_RPC
|
from planetmint.abci.rpc import ABCI_RPC
|
||||||
from planetmint.backend.localmongodb.connection import LocalMongoDBConnection
|
from planetmint.backend.localmongodb.connection import LocalMongoDBConnection
|
||||||
from planetmint.backend.tarantool.connection import TarantoolDBConnection
|
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.assets.create import Create
|
||||||
from transactions.types.elections.vote import Vote
|
from transactions.types.elections.vote import Vote
|
||||||
from transactions.types.elections.validator_utils import election_id_to_public_key
|
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
|
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])
|
v.sign([key])
|
||||||
|
|
||||||
return election, votes
|
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