class ClientClaimDefSubmitOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(CLAIM_DEF)), (REF, TxnSeqNoField()), (DATA, ClaimDefField()), (SIGNATURE_TYPE, NonEmptyStringField()), )
class ClientClaimDefGetOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(GET_CLAIM_DEF)), (REF, TxnSeqNoField()), (ORIGIN, NonEmptyStringField()), (SIGNATURE_TYPE, NonEmptyStringField()), )
class ClientClaimDefGetOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(GET_CLAIM_DEF)), (REF, TxnSeqNoField()), (ORIGIN, IdentifierField()), (SIGNATURE_TYPE, LimitedLengthStringField(max_length=SIGNATURE_TYPE_FIELD_LIMIT)), )
class ClientClaimDefSubmitOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(CLAIM_DEF)), (REF, TxnSeqNoField()), (DATA, ClaimDefField()), (SIGNATURE_TYPE, LimitedLengthStringField(max_length=SIGNATURE_TYPE_FIELD_LIMIT)), )
class ClientClaimDefGetOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(GET_CLAIM_DEF)), (CLAIM_DEF_SCHEMA_REF, TxnSeqNoField()), (CLAIM_DEF_FROM, IdentifierField()), (CLAIM_DEF_SIGNATURE_TYPE, LimitedLengthStringField(max_length=SIGNATURE_TYPE_FIELD_LIMIT)), (CLAIM_DEF_TAG, LimitedLengthStringField(max_length=256, optional=True)), )
class ClientClaimDefSubmitOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(CLAIM_DEF)), (CLAIM_DEF_SCHEMA_REF, TxnSeqNoField()), (CLAIM_DEF_PUBLIC_KEYS, ClaimDefField()), (CLAIM_DEF_SIGNATURE_TYPE, LimitedLengthStringField(max_length=SIGNATURE_TYPE_FIELD_LIMIT)), (CLAIM_DEF_TAG, LimitedLengthStringField(max_length=256)), )
class PublicInputField(AnyMapField): public_address_field = PublicAddressField() seq_no_field = TxnSeqNoField() def _specific_validation(self, val): error = super()._specific_validation(val) if error: return error addr_error = self.public_address_field.validate(val["address"]) if addr_error: return addr_error amt_error = self.seq_no_field.validate(val["seqNo"]) if amt_error: return amt_error
class TokenWallet(Wallet): txn_seq_no_valdator = TxnSeqNoField() def __init__(self, name: str = None, supportedDidMethods: DidMethods = None): super().__init__(name, supportedDidMethods) self.addresses = OrderedDict() # type: OrderedDict[str, Address] self.reply_handlers = { GET_UTXO: self.handle_get_utxo_response, XFER_PUBLIC: self.handle_xfer } def add_new_address(self, address: Address = None, seed=None): assert address or seed if not address: address = Address(seed=seed) assert address.address not in self.addresses self.addresses[address.address] = address def sign_using_output(self, id, seq_no, op: Dict = None, request: Request = None): assert lxor(op, request) if op: request = Request(reqId=Request.gen_req_id(), operation=op, protocolVersion=CURRENT_PROTOCOL_VERSION) # existing_inputs = request.operation.get(INPUTS, []) # request.operation[INPUTS] = [[id, seq_no], ] # payload = deepcopy(request.signingState(id)) # # TEMPORARY # payload[OPERATION].pop(SIGS) # payload.pop(f.IDENTIFIER.nm) # # signature = self.addresses[id].signer.sign(payload) # request.operation[INPUTS] = existing_inputs + [[id, seq_no], ] # TODO: Account for `extra` field payload = [[ { "address": id, "seqNo": seq_no }, ], request.operation[OUTPUTS]] signature = self.addresses[id].signer.sign(payload) request.operation[INPUTS] = request.operation.get(INPUTS, []) + [ { "address": id, "seqNo": seq_no }, ] request.operation[SIGS].append(signature) return request def get_all_wallet_utxos(self): return { address: address.all_utxos for address in self.addresses.values() } def get_all_address_utxos(self, address): if address in self.addresses: return {self.addresses[address]: self.addresses[address].all_utxos} else: return {} def get_total_wallet_amount(self): return sum(addr.total_amount for addr in self.addresses.values()) def get_total_address_amount(self, address): if address in self.addresses: return self.addresses[address].total_amount else: return 0 def on_reply_from_network(self, observer_name, req_id, frm, result, num_replies): try: typ = get_type(result) except KeyError: # For queries typ = result[TXN_TYPE] if typ and typ in self.reply_handlers: self.reply_handlers[typ](result) def handle_get_utxo_response(self, response): self._update_outputs(response[OUTPUTS]) def handle_xfer(self, response): data = get_payload_data(response) seq_no = get_seq_no(response) self._update_inputs(data[INPUTS]) self._update_outputs(data[OUTPUTS], seq_no) def _update_inputs(self, inputs): for inp in inputs: addr = inp["address"] seq_no = inp["seqNo"] if addr in self.addresses: self.addresses[addr].spent(seq_no) def _update_outputs(self, outputs, txn_seq_no=None): for output in outputs: try: addr = output["address"] val = output["amount"] try: seq_no = output["seqNo"] except KeyError as ex: if txn_seq_no and isinstance(txn_seq_no, int): seq_no = txn_seq_no else: raise ex except Exception: raise ValueError('Cannot handle output {}'.format(output)) if addr in self.addresses: self.addresses[addr].add_utxo(seq_no, val) def get_min_utxo_ge(self, amount, address=None) -> Optional[Tuple]: # Get minimum utxo greater than or equal to `amount` def get_address_utxos(address): for (seq_no, amount) in address.all_utxos: yield { "address": address.address, "seqNo": seq_no, "amount": amount } if address: all_utxos = get_address_utxos(self.addresses[address]) else: all_utxos = [ utxo for address in self.addresses.values() for utxo in get_address_utxos(address) ] filtered = filter(lambda utxo: utxo["amount"] >= amount, all_utxos) return min(filtered, key=lambda utxo: utxo["amount"], default=None) def get_val(self, address, seq_no): # Get value of unspent output (address and seq_no), can raise KeyError return self.addresses[address].outputs[0][seq_no]
class ClientGetTxnOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(GET_TXN)), (f.LEDGER_ID.nm, LedgerIdField(optional=True)), (DATA, TxnSeqNoField()), )
from plenum.common.messages.fields import TxnSeqNoField validator = TxnSeqNoField() def test_valid_txn_seq_no(): assert validator.validate(-1) == "cannot be smaller than 1" assert validator.validate(0) == "cannot be smaller than 1" assert validator.validate(2.2) == "expected types 'int', got 'float'" assert validator.validate('') == "expected types 'int', got 'str'" assert validator.validate(1) is None assert validator.validate(200) is None
class ClientGetTxnOperation(MessageValidator): schema = ( (TXN_TYPE, ConstantField(GET_TXN)), (DATA, TxnSeqNoField()), )
from plenum.common.constants import TXN_TYPE from plenum.common.exceptions import InvalidClientRequest from plenum.common.messages.fields import IterableField, TxnSeqNoField from plenum.common.request import Request from sovtoken.constants import MINT_PUBLIC, XFER_PUBLIC, GET_UTXO, INPUTS, SIGS, ADDRESS, OUTPUTS, FROM_SEQNO from sovtoken.messages.fields import PublicOutputField, PublicOutputsField, PublicInputsField PUBLIC_OUTPUT_VALIDATOR = IterableField(PublicOutputField()) PUBLIC_OUTPUTS_VALIDATOR = PublicOutputsField() PUBLIC_INPUTS_VALIDATOR = PublicInputsField() FROM_VALIDATOR = TxnSeqNoField() def outputs_validate(request: Request): operation = request.operation if OUTPUTS not in operation: raise InvalidClientRequest(request.identifier, request.reqId, "{} needs to be present".format(OUTPUTS)) return PUBLIC_OUTPUTS_VALIDATOR.validate(operation[OUTPUTS]) def inputs_validate(request: Request): operation = request.operation if INPUTS not in operation: raise InvalidClientRequest(request.identifier, request.reqId, "{} needs to be present".format(INPUTS)) if SIGS not in operation: raise InvalidClientRequest(request.identifier, request.reqId, "{} needs to be present".format(SIGS)) # THIS IS TEMPORARY. The new format of requests will take an array of signatures