moved get_merkget_utxoset_merkle_root to dataaccessor and fixed test cases

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
This commit is contained in:
Lorenz Herzberger 2023-04-07 16:02:24 +02:00
parent a06a7f986f
commit e627eb899d
No known key found for this signature in database
GPG Key ID: FA5EE906EB55316A
4 changed files with 55 additions and 45 deletions

View File

@ -364,8 +364,8 @@ def delete_unspent_outputs(connection, unspent_outputs: list):
@register_query(TarantoolDBConnection)
@catch_db_exception
def get_unspent_outputs(connection, query=None): # for now we don't have implementation for 'query'.
_utxos = connection.connect().select(TARANT_TABLE_UTXOS, []).data
return [utx[3] for utx in _utxos]
utxos = connection.connect().select(TARANT_TABLE_UTXOS, []).data
return [{"transaction_id": utxo[5], "output_index": utxo[4]} for utxo in utxos]
@register_query(TarantoolDBConnection)

View File

@ -1,5 +1,6 @@
import rapidjson
from itertools import chain
from hashlib import sha3_256
from transactions import Transaction
from transactions.common.exceptions import DoubleSpend
@ -9,7 +10,7 @@ from transactions.common.exceptions import InputDoesNotExist
from planetmint import config_utils, backend
from planetmint.const import GOVERNANCE_TRANSACTION_TYPES
from planetmint.model.fastquery import FastQuery
from planetmint.abci.utils import key_from_base64
from planetmint.abci.utils import key_from_base64, merkleroot
from planetmint.backend.connection import Connection
from planetmint.backend.tarantool.const import TARANT_TABLE_TRANSACTION, TARANT_TABLE_GOVERNANCE, TARANT_TABLE_UTXOS, TARANT_TABLE_OUTPUT
from planetmint.backend.models.block import Block
@ -74,6 +75,7 @@ class DataAccessor:
:obj:`list` of TransactionLink: list of ``txid`` s and ``output`` s
pointing to another transaction's condition
"""
# TODO: adjust for new utxo handling, query and return outputs based on spent
outputs = self.fastquery.get_outputs_by_public_key(owner)
if spent is None:
return outputs
@ -290,6 +292,44 @@ class DataAccessor:
for index, output in enumerate(transaction["outputs"])
]
def 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.
print(utxoset)
hashes = [
sha3_256("{}{}".format(utxo["transaction_id"], utxo["output_index"]).encode()).digest() for utxo in utxoset
]
print(sorted(hashes))
# TODO Notice the sorted call!
return merkleroot(sorted(hashes))
@property
def fastquery(self):
return FastQuery(self.connection)

View File

@ -22,7 +22,6 @@ from ipld import marshal, multihash
from uuid import uuid4
from planetmint.abci.rpc import MODE_COMMIT, MODE_LIST
from tests.utils import get_utxoset_merkle_root
@pytest.mark.bdb
@ -239,19 +238,21 @@ def test_delete_many_unspent_outputs(b, alice):
def test_get_utxoset_merkle_root_when_no_utxo(b):
assert get_utxoset_merkle_root(b.models.connection) == sha3_256(b"").hexdigest()
assert b.models.get_utxoset_merkle_root() == sha3_256(b"").hexdigest()
@pytest.mark.bdb
def test_get_utxoset_merkle_root(b, dummy_unspent_outputs):
utxo_space = b.models.connection.get_space("utxos")
for utxo in dummy_unspent_outputs:
res = utxo_space.insert((uuid4().hex, utxo["transaction_id"], utxo["output_index"], utxo))
assert res
def test_get_utxoset_merkle_root(b, user_sk, user_pk):
tx = Create.generate(
[user_pk],
[([user_pk], 8), ([user_pk], 1), ([user_pk], 4)]
).sign([user_sk])
expected_merkle_root = "86d311c03115bf4d287f8449ca5828505432d69b82762d47077b1c00fe426eac"
merkle_root = get_utxoset_merkle_root(b.models.connection)
assert merkle_root == expected_merkle_root
b.models.store_bulk_transactions([tx])
expected_merkle_root = "e5fce6fed606b72744330b28b2f6d68f2eca570c4cf8e3c418b0c3150c75bfe2"
merkle_root = b.models.get_utxoset_merkle_root()
assert merkle_root in expected_merkle_root
@pytest.mark.bdb

View File

@ -3,7 +3,6 @@
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0
import multiprocessing
from hashlib import sha3_256
import base58
import base64
@ -20,7 +19,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.utils import merkleroot, key_to_base64
from planetmint.abci.utils import key_to_base64
from planetmint.abci.rpc import MODE_COMMIT, MODE_LIST
@ -127,37 +126,7 @@ def generate_election(b, cls, public_key, private_key, asset_data, voter_keys):
return election, votes
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))