Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SET_FEES, GET_FEE and GET_FEES txns #1653

Open
wants to merge 7 commits into
base: ubuntu-16.04
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions indy_common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@
AUTH_RULES = IndyTransactions.AUTH_RULES.value
GET_AUTH_RULE = IndyTransactions.GET_AUTH_RULE.value

SET_FEES = IndyTransactions.SET_FEES.value
GET_FEES = IndyTransactions.GET_FEES.value
GET_FEE = IndyTransactions.GET_FEE.value

# client Rich Schema transaction types
JSON_LD_CONTEXT = IndyTransactions.JSON_LD_CONTEXT.value
RICH_SCHEMA = IndyTransactions.RICH_SCHEMA.value
Expand Down Expand Up @@ -235,3 +239,11 @@
RS_MAPPING_SCHEMA = "schema"
RS_MAPPING_ENC = "enc"
RS_MAPPING_RANK = "rank"

# FEES
FEE = "fee"
FEES = "fees"
FEES_ALIAS = "alias"
FEES_VALUE = "value"
FEE_ALIAS_LENGTH = 128
FEES_FIELD_NAME = "fees"
6 changes: 5 additions & 1 deletion indy_common/test/test_transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
GET_REVOC_REG_DEF, GET_REVOC_REG, GET_REVOC_REG_DELTA, POOL_RESTART, VALIDATOR_INFO, CHANGE_KEY, AUTH_RULE, \
GET_AUTH_RULE, AUTH_RULES, RICH_SCHEMA, RICH_SCHEMA_ENCODING, \
RICH_SCHEMA_MAPPING, RICH_SCHEMA_CRED_DEF, JSON_LD_CONTEXT, GET_RICH_SCHEMA_OBJECT_BY_METADATA, \
GET_RICH_SCHEMA_OBJECT_BY_ID, RICH_SCHEMA_PRES_DEF
GET_RICH_SCHEMA_OBJECT_BY_ID, RICH_SCHEMA_PRES_DEF, SET_FEES, GET_FEES, GET_FEE

from indy_common.transactions import IndyTransactions

Expand Down Expand Up @@ -48,6 +48,10 @@ def test_transactions_are_encoded():
assert GET_RICH_SCHEMA_OBJECT_BY_ID == "300"
assert GET_RICH_SCHEMA_OBJECT_BY_METADATA == "301"

assert SET_FEES == "20000"
assert GET_FEES == "20001"
assert GET_FEE == "20003"


def test_transaction_enum_decoded():
assert IndyTransactions.NODE.name == "NODE"
Expand Down
20 changes: 20 additions & 0 deletions indy_common/test/types/test_get_fee_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from collections import OrderedDict

from indy_common.types import ClientGetFeeOperation
from plenum.common.messages.fields import ConstantField, LimitedLengthStringField

EXPECTED_ORDERED_FIELDS = OrderedDict([
("type", ConstantField),
("alias", LimitedLengthStringField),
])


def test_has_expected_fields():
actual_field_names = OrderedDict(ClientGetFeeOperation.schema).keys()
assert actual_field_names == EXPECTED_ORDERED_FIELDS.keys()


def test_has_expected_validators():
schema = dict(ClientGetFeeOperation.schema)
for field, validator in EXPECTED_ORDERED_FIELDS.items():
assert isinstance(schema[field], validator)
19 changes: 19 additions & 0 deletions indy_common/test/types/test_get_fees_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from collections import OrderedDict

from indy_common.types import ClientGetFeesOperation
from plenum.common.messages.fields import ConstantField

EXPECTED_ORDERED_FIELDS = OrderedDict([
("type", ConstantField),
])


def test_has_expected_fields():
actual_field_names = OrderedDict(ClientGetFeesOperation.schema).keys()
assert actual_field_names == EXPECTED_ORDERED_FIELDS.keys()


def test_has_expected_validators():
schema = dict(ClientGetFeesOperation.schema)
for field, validator in EXPECTED_ORDERED_FIELDS.items():
assert isinstance(schema[field], validator)
20 changes: 20 additions & 0 deletions indy_common/test/types/test_set_fees_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from collections import OrderedDict

from indy_common.types import ClientSetFeesOperation, SetFeesField
from plenum.common.messages.fields import ConstantField

EXPECTED_ORDERED_FIELDS = OrderedDict([
("type", ConstantField),
("fees", SetFeesField),
])


def test_has_expected_fields():
actual_field_names = OrderedDict(ClientSetFeesOperation.schema).keys()
assert actual_field_names == EXPECTED_ORDERED_FIELDS.keys()


def test_has_expected_validators():
schema = dict(ClientSetFeesOperation.schema)
for field, validator in EXPECTED_ORDERED_FIELDS.items():
assert isinstance(schema[field], validator)
4 changes: 4 additions & 0 deletions indy_common/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class IndyTransactions(Transactions):
GET_RICH_SCHEMA_OBJECT_BY_ID = "300"
GET_RICH_SCHEMA_OBJECT_BY_METADATA = "301"

SET_FEES = "20000"
GET_FEES = "20001"
GET_FEE = "20003"

@staticmethod
def get_name_from_code(code: str):
try:
Expand Down
40 changes: 37 additions & 3 deletions indy_common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
Sha256HexField, JsonField, MapField, BooleanField, VersionField, \
ChooseField, IntegerField, IterableField, \
AnyMapField, NonEmptyStringField, DatetimeStringField, RoleField, AnyField, FieldBase
from plenum.common.messages.message_base import MessageValidator
from plenum.common.messages.message_base import MessageValidator, MessageBase
from plenum.common.messages.node_messages import NonNegativeNumberField
from plenum.common.request import Request as PRequest
from plenum.common.types import OPERATION
Expand Down Expand Up @@ -44,7 +44,7 @@
RS_NAME, RS_ID, RS_CONTENT, RS_CONTEXT_TYPE_VALUE, RICH_SCHEMA, RS_SCHEMA_TYPE_VALUE, RS_ENCODING_TYPE_VALUE, \
RICH_SCHEMA_ENCODING, RS_MAPPING_TYPE_VALUE, RICH_SCHEMA_MAPPING, RS_CRED_DEF_TYPE_VALUE, \
RICH_SCHEMA_CRED_DEF, GET_RICH_SCHEMA_OBJECT_BY_ID, GET_RICH_SCHEMA_OBJECT_BY_METADATA, \
RICH_SCHEMA_PRES_DEF, RS_PRES_DEF_TYPE_VALUE
RICH_SCHEMA_PRES_DEF, RS_PRES_DEF_TYPE_VALUE, GET_FEE, GET_FEES, SET_FEES, FEES_ALIAS, FEE_ALIAS_LENGTH, FEES
from indy_common.version import SchemaVersion


Expand Down Expand Up @@ -467,6 +467,37 @@ class ClientGetRichSchemaObjectByMetadataOperation(MessageValidator):
)


class ClientGetFeeOperation(MessageValidator):
schema = (
(TXN_TYPE, ConstantField(GET_FEE)),
(FEES_ALIAS, LimitedLengthStringField(max_length=FEE_ALIAS_LENGTH)),
)


class ClientGetFeesOperation(MessageValidator):
schema = (
(TXN_TYPE, ConstantField(GET_FEES)),
)


class SetFeesField(MapField):
def __init__(self, **kwargs):
super().__init__(NonEmptyStringField(), NonNegativeNumberField(),
**kwargs)

def _specific_validation(self, val):
error = super()._specific_validation(val)
if error:
return "set_fees -- " + error


class ClientSetFeesOperation(MessageValidator):
schema = (
(TXN_TYPE, ConstantField(SET_FEES)),
(FEES, SetFeesField()),
)


class ClientOperationField(PClientOperationField):
_specific_operations = {
SCHEMA: ClientSchemaOperation(),
Expand Down Expand Up @@ -496,7 +527,10 @@ class ClientOperationField(PClientOperationField):
RICH_SCHEMA_CRED_DEF: ClientRichSchemaCredDefOperation(),
RICH_SCHEMA_PRES_DEF: ClientRichSchemaPresDefOperation(),
GET_RICH_SCHEMA_OBJECT_BY_ID: ClientGetRichSchemaObjectByIdOperation(),
GET_RICH_SCHEMA_OBJECT_BY_METADATA: ClientGetRichSchemaObjectByMetadataOperation()
GET_RICH_SCHEMA_OBJECT_BY_METADATA: ClientGetRichSchemaObjectByMetadataOperation(),
GET_FEE: ClientGetFeeOperation(),
GET_FEES: ClientGetFeesOperation(),
SET_FEES: ClientSetFeesOperation(),
}

# TODO: it is a workaround because INDY-338, `operations` must be a class
Expand Down
15 changes: 15 additions & 0 deletions indy_node/server/node_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
from indy_node.server.request_handlers.config_req_handlers.auth_rule.auth_rule_handler import AuthRuleHandler
from indy_node.server.request_handlers.config_req_handlers.auth_rule.auth_rule_handler_1_9_1 import AuthRuleHandler191
from indy_node.server.request_handlers.config_req_handlers.auth_rule.auth_rules_handler import AuthRulesHandler
from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler_0_9_3 import SetFeesHandler093
from indy_node.server.request_handlers.config_req_handlers.ledgers_freeze_handler import LedgersFreezeHandler
from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler import SetFeesHandler
from indy_node.server.request_handlers.config_req_handlers.node_upgrade_handler import NodeUpgradeHandler
from indy_node.server.request_handlers.config_req_handlers.pool_config_handler import PoolConfigHandler
from indy_node.server.request_handlers.config_req_handlers.pool_upgrade_handler import PoolUpgradeHandler
Expand Down Expand Up @@ -46,6 +48,8 @@
from indy_node.server.request_handlers.read_req_handlers.get_attribute_handler import GetAttributeHandler
from indy_node.server.request_handlers.read_req_handlers.get_auth_rule_handler import GetAuthRuleHandler
from indy_node.server.request_handlers.read_req_handlers.get_claim_def_handler import GetClaimDefHandler
from indy_node.server.request_handlers.read_req_handlers.get_fee_handler import GetFeeHandler
from indy_node.server.request_handlers.read_req_handlers.get_fees_handler import GetFeesHandler
from plenum.server.request_handlers.ledgers_freeze.get_frozen_ledgers_handler import GetFrozenLedgersHandler
from indy_node.server.request_handlers.read_req_handlers.get_nym_handler import GetNymHandler
from indy_node.server.request_handlers.read_req_handlers.get_revoc_reg_def_handler import GetRevocRegDefHandler
Expand Down Expand Up @@ -202,6 +206,13 @@ def _register_config_req_handlers(self):
ledgers_freeze_handler = LedgersFreezeHandler(database_manager=self.node.db_manager,
write_req_validator=self.node.write_req_validator)
get_frozen_ledgers_handler = GetFrozenLedgersHandler(database_manager=self.node.db_manager)

set_fees_handler = SetFeesHandler(db_manager=self.node.db_manager,
write_req_validator=self.node.write_req_validator)
set_fees_handler_093 = SetFeesHandler093(db_manager=self.node.db_manager,
write_req_validator=self.node.write_req_validator)
get_fee_handler = GetFeeHandler(database_manager=self.node.db_manager)
get_fees_handler = GetFeesHandler(db_manager=self.node.db_manager)
# Register write handlers
self.node.write_manager.register_req_handler(auth_rule_handler)
self.node.write_manager.register_req_handler(auth_rules_handler)
Expand All @@ -212,6 +223,8 @@ def _register_config_req_handlers(self):
self.node.write_manager.register_req_handler(taa_disable_handler)
self.node.write_manager.register_req_handler(node_upgrade_handler)
self.node.write_manager.register_req_handler(ledgers_freeze_handler)
self.node.write_manager.register_req_handler(set_fees_handler)
self.node.write_manager.register_req_handler_with_version(set_fees_handler_093, "0.9.3")
# Register read handlers
self.node.read_manager.register_req_handler(get_auth_rule_handler)
self.node.read_manager.register_req_handler(get_taa_aml_handler)
Expand All @@ -222,6 +235,8 @@ def _register_config_req_handlers(self):
version="1.9.1")
self.node.write_manager.register_req_handler_with_version(taa_handler_v1,
version="1")
self.node.read_manager.register_req_handler(get_fee_handler)
self.node.read_manager.register_req_handler(get_fees_handler)

def _register_action_req_handlers(self):
# Action handlers
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from common.serializers.serialization import proof_nodes_serializer, state_roots_serializer, config_state_serializer
from plenum.common.constants import MULTI_SIGNATURE, ROOT_HASH, PROOF_NODES


class BatchFeesTracker:
def __init__(self):
self.fees_in_current_batch = 0
self._deducted_fees = {}

def add_deducted_fees(self, txn_type, seq_no, fees):
key = "{}#{}".format(txn_type, seq_no)
self._deducted_fees[key] = fees

def has_deducted_fees(self, txn_type, seq_no):
return "{}#{}".format(txn_type, seq_no) in self._deducted_fees


class FeesStaticHelper:

@staticmethod
def get_fee_from_state(state, fees_alias=None, is_committed=False, with_proof=False, bls_store=None):
fees = None
proof = None
try:
fees_key = FeesStaticHelper.build_path_for_set_fees(alias=fees_alias)
if with_proof:
root_hash = state.committedHeadHash if is_committed else state.headHash
proof, serz = state.generate_state_proof(fees_key,
root=state.get_head_by_hash(root_hash),
serialize=True,
get_value=True)
if serz:
serz = state.get_decoded(serz)
encoded_root_hash = state_roots_serializer.serialize(bytes(root_hash))
multi_sig = bls_store.get(encoded_root_hash)
if multi_sig:
encoded_proof = proof_nodes_serializer.serialize(proof)
proof = {
MULTI_SIGNATURE: multi_sig.as_dict(),
ROOT_HASH: encoded_root_hash,
PROOF_NODES: encoded_proof
}
else:
proof = {}
else:
serz = state.get(fees_key,
isCommitted=is_committed)
if serz:
fees = config_state_serializer.deserialize(serz)
except KeyError:
pass
if with_proof:
return fees, proof
return fees

FEES_STATE_PREFIX = '200'
FEES_KEY_DELIMITER = ':'
FEES_KEY_FOR_ALL = 'fees'

@staticmethod
def build_path_for_set_fees(alias=None):
if alias:
return FeesStaticHelper.FEES_KEY_DELIMITER.join([FeesStaticHelper.FEES_STATE_PREFIX, alias])
return FeesStaticHelper.FEES_KEY_DELIMITER.join([FeesStaticHelper.FEES_STATE_PREFIX, FeesStaticHelper.FEES_KEY_FOR_ALL])
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from typing import Optional

from common.serializers.serialization import config_state_serializer
from indy_common.constants import SET_FEES, FEES
from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper
from plenum.common.constants import CONFIG_LEDGER_ID
from plenum.common.exceptions import InvalidClientRequest
from plenum.common.request import Request
from plenum.common.txn_util import get_payload_data
from plenum.common.types import f
from plenum.server.database_manager import DatabaseManager
from plenum.server.request_handlers.handler_interfaces.write_request_handler import WriteRequestHandler


class SetFeesHandler(WriteRequestHandler):

def __init__(self, db_manager: DatabaseManager, write_req_validator):
super().__init__(db_manager, SET_FEES, CONFIG_LEDGER_ID)
self._write_req_validator = write_req_validator

def static_validation(self, request: Request):
raise InvalidClientRequest(request.identifier,
request.reqId,
"SET_FEES transactions are forbidden now.")

def additional_dynamic_validation(self, request: Request, req_pp_time: Optional[int]):
raise InvalidClientRequest(request.identifier,
request.reqId,
"SET_FEES transactions are forbidden now.")

def update_state(self, txn, prev_result, request, is_committed=False):
payload = get_payload_data(txn)
fees_from_req = payload.get(FEES)
current_fees = FeesStaticHelper.get_fee_from_state(self.state)
current_fees = current_fees if current_fees else {}
current_fees.update(fees_from_req)
for fees_alias, fees_value in fees_from_req.items():
self._set_to_state(FeesStaticHelper.build_path_for_set_fees(alias=fees_alias), fees_value)
self._set_to_state(FeesStaticHelper.build_path_for_set_fees(), current_fees)

def _set_to_state(self, key, val):
val = config_state_serializer.serialize(val)
key = key.encode()
self.state.set(key, val)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from indy_common.constants import FEES
from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper
from indy_node.server.request_handlers.config_req_handlers.fees.set_fees_handler import SetFeesHandler
from plenum.common.txn_util import get_payload_data
from plenum.common.types import f


class SetFeesHandler093(SetFeesHandler):
fees_state_key = 'fees'

def update_state(self, txn, prev_result, request, is_committed=False):
payload = get_payload_data(txn)
fees_from_req = payload.get(FEES)
current_fees = FeesStaticHelper.get_fee_from_state(self.state)
current_fees = current_fees if current_fees else {}
current_fees.update(fees_from_req)
self._set_to_state(self.fees_state_key, current_fees)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from indy_common.constants import GET_FEE, FEE
from indy_node.server.request_handlers.config_req_handlers.fees.fees_static_helper import FeesStaticHelper
from plenum.common.constants import ALIAS, STATE_PROOF, CONFIG_LEDGER_ID, BLS_LABEL
from plenum.common.exceptions import InvalidClientRequest
from plenum.common.request import Request
from plenum.common.types import f
from plenum.server.database_manager import DatabaseManager
from plenum.server.request_handlers.handler_interfaces.read_request_handler import ReadRequestHandler


class GetFeeHandler(ReadRequestHandler):

def __init__(self, database_manager: DatabaseManager):
super().__init__(database_manager, GET_FEE, CONFIG_LEDGER_ID)

def get_result(self, request: Request):
alias = request.operation.get(ALIAS)
fee, proof = FeesStaticHelper.get_fee_from_state(self.state, fees_alias=alias, is_committed=True,
with_proof=True,
bls_store=self.database_manager.get_store(BLS_LABEL))
result = {f.IDENTIFIER.nm: request.identifier,
f.REQ_ID.nm: request.reqId, FEE: fee}
if proof:
result[STATE_PROOF] = proof
result.update(request.operation)
return result
Loading