def _apply_proposal(self, public_key, proposal_data, context): asset_proposal = AssetProposal() asset_proposal.ParseFromString(proposal_data) asset = Asset() asset.ParseFromString(asset_proposal.asset) proposal_id = self.asset_address(asset) approval_threshold = self._get_approval_threshold(context) if approval_threshold > 1: asset_candidates = self._get_candidates(context) existing_candidate = _first( asset_candidates.candidates, lambda candidate: candidate.proposal_id == proposal_id) if existing_candidate is not None: raise InvalidTransaction( 'Duplicate proposal for {}'.format( asset_proposal.type)) record = AssetCandidate.VoteRecord( public_key=public_key, vote=AssetCandidate.VoteRecord.VOTE_ACCEPT) asset_candidates.candidates.add( proposal_id=proposal_id, proposal=asset_proposal, votes=[record]) self._set_candidates(context, asset_candidates) else: _set_asset(context, proposal_id, asset) LOGGER.debug('Set asset {}'.format(proposal_id))
def _apply_vote(self, public_key, authorized_keys, vote_data, context): """Apply an ACCEPT or REJECT vote to a proposal""" asset_vote = AssetVote() asset_vote.ParseFromString(vote_data) proposal_id = asset_vote.proposal_id asset_candidates = self._get_candidates(context) candidate = _first( asset_candidates.candidates, lambda candidate: candidate.proposal_id == proposal_id) if candidate is None: raise InvalidTransaction( "Proposal {} does not exist.".format(proposal_id)) approval_threshold = self._get_approval_threshold(context) vote_record = _first(candidate.votes, lambda record: record.public_key == public_key) if vote_record is not None: raise InvalidTransaction( '{} has already voted'.format(public_key)) candidate_index = _index_of(asset_candidates.candidates, candidate) candidate.votes.add( public_key=public_key, vote=asset_vote.vote) accepted_count = 0 rejected_count = 0 for vote_record in candidate.votes: if vote_record.vote == AssetVote.VOTE_ACCEPT: accepted_count += 1 elif vote_record.vote == AssetVote.VOTE_REJECT: rejected_count += 1 LOGGER.debug( "Vote tally accepted {} rejected {}" .format(accepted_count, rejected_count)) asset = Asset() asset.ParseFromString(candidate.proposal.asset) if accepted_count >= approval_threshold: _set_asset(context, proposal_id, asset) LOGGER.debug("Consensus to create {}".format(proposal_id)) del asset_candidates.candidates[candidate_index] self._set_candidates(context, asset_candidates) elif rejected_count >= approval_threshold or \ (rejected_count + accepted_count) == len(authorized_keys): LOGGER.debug( 'Proposal for {} was rejected'.format(proposal_id)) del asset_candidates.candidates[candidate_index] self._set_candidates(context, asset_candidates) else: LOGGER.debug('Vote recorded for {}'.format(proposal_id)) self._set_candidates(context, asset_candidates)
def __asset_cache(prime): """Prime (value) lookup for resource asset""" res = __get_list_data(asset_addresser.family_ns_hash) resource = None for entry in res['data']: er = Asset() er.ParseFromString(entry['data']) if prime == er.value: resource = er break return resource
def apply(self, transaction, context): txn_header = transaction.header public_key = txn_header.signer_public_key asset_payload = AssetPayload() asset_payload.ParseFromString(transaction.payload) auth_keys = self._get_auth_keys(context) if auth_keys and public_key not in auth_keys: raise InvalidTransaction( '{} is not authorized to change asset'.format(public_key)) if asset_payload.action == AssetPayload.ACTION_GENESIS: asset = Asset() asset.ParseFromString(asset_payload.data) _set_asset(context, self.asset_address(asset), asset) elif asset_payload.action == AssetPayload.ACTION_DIRECT: asset = Asset() asset.ParseFromString(asset_payload.data) _set_asset(context, self.asset_address(asset), asset) elif asset_payload.action == AssetPayload.ACTION_PROPOSE: return self._apply_proposal( public_key, asset_payload.data, context) elif asset_payload.action == AssetPayload.ACTION_VOTE: return self._apply_vote( public_key, auth_keys, asset_payload.data, context) elif asset_payload.action == AssetPayload.ACTION_UNSET: return self._apply_unset_vote( public_key, auth_keys, asset_payload.data, context) else: raise InvalidTransaction( "'Payload action not recognized {}". format(asset_payload.action))
def __decode_asset_proposals(address, data): """Decode a proposals address""" proposals = AssetCandidates() proposals.ParseFromString(data) asset = Asset() data = [] for candidate in proposals.candidates: msg = MessageToDict(candidate) asset.ParseFromString(candidate.proposal.asset) msg['proposal']['asset'] = MessageToDict(asset) for voter in msg['votes']: voter['publicKey'] = key_owner(voter['publicKey']) data.append(msg) return {'family': 'asset', 'type': 'proposal', 'data': data}
def decode_asset_list(address=None): """List of assets not including proposals""" targetadd = address if address else asset_addresser.family_ns_hash results = __get_list_data(targetadd)['data'] data = [] for element in results: asset = Asset() asset.ParseFromString(element['data']) am = MessageToDict(asset) data.append({ 'link': element['address'], 'type': 'asset', 'system': asset.system, 'name': asset.key, 'value': asset.value, 'properties': am["properties"] if "properties" in am else [] }) return {'family': 'asset', 'data': data}
def decode_asset(address): """Decode a asset address""" data = __get_leaf_data(address)['data'] asset = Asset() asset.ParseFromString(data) return {'family': 'asset', 'data': MessageToDict(asset)}