Skip to content

Commit 48f6e4f

Browse files
authored
Merge pull request #268 from KitHat/master
ST-600 & ST-601 -- remove utxo from state and limit the number of utxo's returned
2 parents a536a4c + 00a541a commit 48f6e4f

18 files changed

Lines changed: 144 additions & 33 deletions

sovtoken/sovtoken/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@
2424
TokenTransactions.XFER_PUBLIC.value}
2525
ACCEPTABLE_QUERY_TYPES = {TokenTransactions.GET_UTXO.value, }
2626
ACCEPTABLE_ACTION_TYPES = {}
27+
28+
UTXO_LIMIT = 1000
29+
NEXT_SEQNO = "next"

sovtoken/sovtoken/request_handlers/read_req_handler/get_utxo_handler.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
try:
2+
import ujson as json
3+
except ImportError:
4+
import json
5+
from copy import deepcopy
6+
17
from sovtoken import TokenTransactions
2-
from sovtoken.constants import ADDRESS, OUTPUTS, TOKEN_LEDGER_ID
8+
from sovtoken.constants import ADDRESS, OUTPUTS, TOKEN_LEDGER_ID, NEXT_SEQNO, UTXO_LIMIT
39
from sovtoken.messages.txn_validator import txt_get_utxo_validate
410
from sovtoken.request_handlers.token_utils import parse_state_key
511
from sovtoken.types import Output
@@ -13,6 +19,7 @@
1319
from plenum.server.database_manager import DatabaseManager
1420
from plenum.server.request_handlers.handler_interfaces.read_request_handler import ReadRequestHandler
1521
from state.trie.pruning_trie import rlp_decode
22+
from stp_core.config import MSG_LEN_LIMIT
1623

1724

1825
class GetUtxoHandler(ReadRequestHandler):
@@ -56,10 +63,21 @@ def get_result(self, request: Request):
5663
continue
5764
outputs.add(Output(addr, int(seq_no), int(amount)))
5865

66+
utxos = outputs.sorted_list
67+
next_seqno = None
68+
if len(utxos) > UTXO_LIMIT:
69+
next_seqno = utxos[UTXO_LIMIT].seqNo
70+
utxos = utxos[:UTXO_LIMIT]
71+
5972
result = {f.IDENTIFIER.nm: request.identifier,
60-
f.REQ_ID.nm: request.reqId, OUTPUTS: outputs.sorted_list}
61-
if proof:
62-
result[STATE_PROOF] = proof
73+
f.REQ_ID.nm: request.reqId, OUTPUTS: utxos}
6374

6475
result.update(request.operation)
76+
if next_seqno:
77+
result[NEXT_SEQNO] = next_seqno
78+
if proof:
79+
res_sub = deepcopy(result)
80+
res_sub[STATE_PROOF] = proof
81+
if len(json.dumps(res_sub)) <= MSG_LEN_LIMIT:
82+
result = res_sub
6583
return result

sovtoken/sovtoken/request_handlers/token_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
def spend_input(state, utxo_cache: UTXOCache, address, seq_no, is_committed=False):
1515
state_key = create_state_key(address, seq_no)
16-
state.set(state_key, b'')
16+
state.remove(state_key)
1717
utxo_cache.spend_output(Output(address, seq_no, None),
1818
is_committed=is_committed)
1919

sovtoken/sovtoken/test/helper.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
from sovtoken.test.wallet import TokenWallet
1414

1515

16+
def libsovtoken_address_to_address(addr):
17+
return addr[8:]
18+
19+
1620
def xfer_request(inputs, outputs, extra_data=None):
1721
payload = {
1822
TXN_TYPE: XFER_PUBLIC,

sovtoken/sovtoken/test/req_handlers/get_utxo_req_handler/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
from sovtoken import TOKEN_LEDGER_ID, TokenTransactions
66
from sovtoken.request_handlers.read_req_handler.get_utxo_handler import GetUtxoHandler
7+
from sovtoken.request_handlers.token_utils import create_state_key
8+
from sovtoken.test.helper import libsovtoken_address_to_address
79

810
from plenum.test.helper import sdk_json_to_request_object
911

@@ -22,3 +24,10 @@ def get_utxo_request(looper, payment_address, wallet):
2224
get_utxo_request = json.loads(get_utxo_request)
2325
get_utxo_request = sdk_json_to_request_object(get_utxo_request)
2426
return get_utxo_request
27+
28+
29+
@pytest.fixture(scope="module")
30+
def insert_over_thousand_utxos(db_manager, payment_address):
31+
token_state = db_manager.get_state(TOKEN_LEDGER_ID)
32+
for i in range(1200):
33+
token_state.set(create_state_key(libsovtoken_address_to_address(payment_address), i), str(i).encode())
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
import pytest
22
from sovtoken.constants import OUTPUTS, ADDRESS
33
from sovtoken.request_handlers.token_utils import create_state_key
4+
from sovtoken.test.helper import libsovtoken_address_to_address
45

56
from plenum.common.constants import STATE_PROOF
67

78

89
@pytest.fixture(scope="module", autouse=True)
910
def add_utxo(payment_address, get_utxo_handler):
10-
get_utxo_handler.state.set(create_state_key(payment_address.replace("pay:sov:", ""), 1), "3".encode())
11+
get_utxo_handler.state.set(create_state_key(libsovtoken_address_to_address(payment_address), 1), "3".encode())
1112

1213

1314
def test_get_utxo_request_has_utxos(get_utxo_request, get_utxo_handler, payment_address, add_utxo):
1415
result = get_utxo_handler.get_result(get_utxo_request)
1516
assert result[STATE_PROOF]
1617
assert result[OUTPUTS]
1718
assert len(result[OUTPUTS]) == 1
18-
assert result[OUTPUTS][0].address == payment_address.replace("pay:sov:", "")
19+
assert result[OUTPUTS][0].address == libsovtoken_address_to_address(payment_address)
1920
assert result[OUTPUTS][0].amount == 3
2021
assert result[OUTPUTS][0].seqNo == 1
2122

2223

2324
def test_get_utxo_request_no_utxos(get_utxo_request, get_utxo_handler, payment_address_2, add_utxo):
24-
get_utxo_request.operation[ADDRESS] = payment_address_2.replace("pay:sov:", "")
25+
get_utxo_request.operation[ADDRESS] = libsovtoken_address_to_address(payment_address_2)
2526
result = get_utxo_handler.get_result(get_utxo_request)
2627
assert result[STATE_PROOF]
2728
assert len(result[OUTPUTS]) == 0
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from sovtoken.constants import OUTPUTS
2+
from sovtoken.test.helper import libsovtoken_address_to_address
3+
4+
from plenum.common.constants import STATE_PROOF
5+
6+
7+
def test_get_utxo_request_has_utxos(get_utxo_request, get_utxo_handler, payment_address, insert_over_thousand_utxos):
8+
result = get_utxo_handler.get_result(get_utxo_request)
9+
assert result[STATE_PROOF]
10+
assert result[OUTPUTS]
11+
assert len(result[OUTPUTS]) == 1000
12+
for i in range(1000):
13+
assert result[OUTPUTS][i].address == libsovtoken_address_to_address(payment_address)
14+
assert result[OUTPUTS][i].seqNo == i
15+
assert result[OUTPUTS][i].amount == i
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
from sovtoken.test.helper import libsovtoken_address_to_address
2+
13

24
def test_mint_handler_update_state_valid_txn(mint_txn, mint_handler, payment_address):
35
mint_handler.update_state(mint_txn, None, None, is_committed=True)
46

57
token_state = mint_handler.state
68
utxo_cache = mint_handler.database_manager.get_store("utxo_cache")
79

8-
assert int(token_state.get((payment_address[8:] + ":1").encode(), isCommitted=False)) == 10
9-
assert utxo_cache.get(payment_address[8:].encode()).decode() == '1:10'
10+
assert int(token_state.get((libsovtoken_address_to_address(payment_address) + ":1").encode(), isCommitted=False)) == 10
11+
assert utxo_cache.get(libsovtoken_address_to_address(payment_address).encode()).decode() == '1:10'
1012

1113

sovtoken/sovtoken/test/req_handlers/xfer_req_handler/conftest.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from sovtoken.sovtoken_auth_map import sovtoken_auth_map
77
from base58 import b58encode_check
88
from indy.payment import build_payment_req
9+
from sovtoken.test.helper import libsovtoken_address_to_address
10+
911
from indy_common.test.auth.conftest import write_auth_req_validator, constraint_serializer, config_state, idr_cache
1012
from plenum.common.txn_util import append_txn_metadata
1113
from plenum.test.helper import sdk_json_to_request_object
@@ -20,7 +22,7 @@ def xfer_handler(utxo_cache, db_manager, write_auth_req_validator, mint_tokens):
2022

2123
@pytest.fixture(scope="module")
2224
def mint_tokens(payment_address, utxo_cache, db_manager):
23-
addr = payment_address[8:]
25+
addr = libsovtoken_address_to_address(payment_address)
2426
utxo_cache.set(addr, "1:10".encode())
2527
db_manager.get_state(TOKEN_LEDGER_ID).set((addr + ":1").encode(), "10".encode())
2628

sovtoken/sovtoken/test/req_handlers/xfer_req_handler/test_xfer_handler_dynamic_validation.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22
from sovtoken.exceptions import InsufficientFundsError, ExtraFundsError, InvalidFundsError
3+
from sovtoken.test.helper import libsovtoken_address_to_address
34

45

56
def test_xfer_handler_dynamic_validation_valid(xfer_handler, xfer_request):
@@ -22,5 +23,5 @@ def test_xfer_handler_dynamic_validation_utxo_not_exists(xfer_handler, invalid_a
2223
payment_address):
2324
with pytest.raises(InvalidFundsError,
2425
message="InvalidFundsError(\"seq_nos {{2}} are not found in list of seq_nos_amounts for "
25-
"address {} -- current list: ['1', '10']\",)".format(payment_address[8:])):
26+
"address {} -- current list: ['1', '10']\",)".format(libsovtoken_address_to_address(payment_address))):
2627
xfer_handler.dynamic_validation(invalid_amount_xfer_request_utxo_does_not_exist)

0 commit comments

Comments
 (0)