Пример #1
0
    def flatten_delta_crdt(self, receiver_id, sender_ids, sequence, wait=None):
        addresses = [make_entity_address(receiver_id)]
        for sender in sender_ids:
            addresses.append(make_entity_address(sender))

        message = {'entity_id': receiver_id, 'sqn': sequence}

        return self._send_transaction(ActionTypes.FLATTEN_DELTA_CRDT.value,
                                      cbor2.dumps(message),
                                      addresses,
                                      wait=wait)
Пример #2
0
    def add_crdt_record(self,
                        receive_entity,
                        send_entity,
                        crdt_record,
                        wait=None):
        crdt_address = make_crdt_address(receive_entity)
        receiver_address = make_entity_address(receive_entity)
        sender_address = make_entity_address(send_entity)

        return self._send_transaction(ActionTypes.ADD_LEDGER_CRDT.value,
                                      crdt_record, [
                                          crdt_address,
                                          receiver_address,
                                          sender_address,
                                      ],
                                      wait=wait)
Пример #3
0
def _add_user(serialized_payload, context):
    home_id, blob_sig, user_id, user_blob = _parse_add_user(serialized_payload)
    # TODO(matt9j) Validate the network signature against the known home network key!

    address = make_entity_address(user_id)
    data = _get_state_data(address, context)
    if data:
        raise InvalidTransaction('The user {} already exists'.format(user_id))

    _set_state_data(address, user_blob, context)
Пример #4
0
def _add_net(action_payload, context):
    # TODO(matt9j) Do a more safe deserialization.
    # Parse the outer data layer from wire format
    anchor_id, message_sig, community_id, new_community_blob = \
        _parse_add_community(action_payload)

    # TODO(matt9j) Validate the anchor and signature
    verified = True
    #     key = nacl.signing.VerifyKey(message['key'],
    #     encoder=nacl.encoding.RawEncoder)
    #     verified = key.verify(raw_message, signature,
    #     encoder=nacl.encoding.RawEncoder)
    if not verified:
        raise InvalidTransaction('Message failed network key validation')

    address = make_entity_address(community_id)
    data = _get_state_data(address, context)
    if data:
        raise InvalidTransaction(
            'The community {} already exists'.format(community_id))

    _set_state_data(address, new_community_blob, context)
Пример #5
0
def _add_ledger_crdt(action_payload, context):
    """Add a crdt record to the on-chain crdt implementation."""

    exchange = asterales_parsers.parse_exchange_record(action_payload)

    # TODO(matt9j) handle gaps in the receive SQN?
    # TODO(matt9j) Validate that the sequence number has indeed progressed
    receive_sqn = exchange.receiver_sequence_number_msb * (2 ** 64) + \
                  exchange.receiver_sequence_number_lsb
    LOG.debug("Processing id: %d, sqn: %d to the ledger crdt",
              exchange.receiver_id, receive_sqn)

    # Validate the exchange signatures
    receiver_blob = _get_state_data(make_entity_address(exchange.receiver_id),
                                    context)
    receiver_data = storage_pb2.Entity()
    receiver_data.ParseFromString(receiver_blob)
    receive_verify_key = nacl.signing.VerifyKey(
        receiver_data.verify_key, encoder=nacl.encoding.RawEncoder)
    try:
        receive_verify_key.verify(exchange.receiver_signed_blob,
                                  exchange.receiver_signature,
                                  encoder=nacl.encoding.RawEncoder)
    except nacl.exceptions.BadSignatureError as e:
        LOG.error(e)
        raise InvalidTransaction(
            'Exchange receive signature invalid sqn:{}'.format(receive_sqn))

    sender_blob = _get_state_data(make_entity_address(exchange.sender_id),
                                  context)
    sender_data = storage_pb2.Entity()
    sender_data.ParseFromString(sender_blob)
    sender_verify_key = nacl.signing.VerifyKey(
        sender_data.verify_key, encoder=nacl.encoding.RawEncoder)
    try:
        sender_verify_key.verify(exchange.sender_signed_blob,
                                 exchange.sender_signature,
                                 encoder=nacl.encoding.RawEncoder)
    except nacl.exceptions.BadSignatureError:
        raise InvalidTransaction(
            'Exchange send signature invalid sqn:{}'.format(receive_sqn))

    crdt_address = make_crdt_address(exchange.receiver_id)
    current_crdt_blob = _get_state_data(crdt_address, context)

    if current_crdt_blob is not None:
        crdt_history = cbor.loads(current_crdt_blob)
    else:
        crdt_history = []

    if receive_sqn in crdt_history:
        LOG.info("Discarding duplicate upload sqn: %d", receive_sqn)
        return

    LOG.info("Record is new, adding id: %d, sqn: %d to the ledger crdt",
             exchange.receiver_id, receive_sqn)

    crdt_history.append(receive_sqn)
    _set_state_data(crdt_address, cbor.dumps(crdt_history), context)

    receiver_data.balance += exchange.amount
    _set_state_data(make_entity_address(exchange.receiver_id),
                    receiver_data.SerializeToString(), context)

    sender_data.balance -= exchange.amount
    _set_state_data(make_entity_address(exchange.sender_id),
                    sender_data.SerializeToString(), context)
Пример #6
0
def _flatten_delta_crdt(action_payload, context, crdt_endpoint):
    """Flattens contiguous local CRDT records into the entity state"""
    # Parse the request.
    flatten_request = cbor2.loads(action_payload)
    # TODO(matt9j) Use the origin as a fallback if deltas are missing.
    # request_origin = flatten_request['origin']
    entity_id = flatten_request['entity_id']
    proposed_frontier = flatten_request['sqn']
    LOG.info("Attempting to flatten delta crdt for id: %d to frontier_sqn: %d",
             entity_id, proposed_frontier)

    # Lookup the current frontier sqn.
    entity_blob = _get_state_data(make_entity_address(entity_id), context)
    entity_pb = storage_pb2.Entity()
    entity_pb.ParseFromString(entity_blob)
    current_frontier = entity_pb.frontier_sequence_number
    LOG.debug('requesting endorsement for (%d, %d] for entity %d',
              current_frontier, proposed_frontier, entity_id)

    # ask the local CRDT for exchanges up to the new proposed frontier SQN
    crdt_request = {
        'receive_id': entity_id,
        'current_frontier': current_frontier,
        'proposed_frontier': proposed_frontier,
    }

    response = CRDT_SESSION.post(
        url=crdt_endpoint + "/crdt/endorsingRecords",
        data=cbor2.dumps(crdt_request),
        headers={'Content-Type': 'application/octet-stream'})
    if not response.ok:
        LOG.error("Unable to request endorsing crdt records %s", response)
        raise InvalidTransaction("Unable to request endorsement from CRDT")

    # Set aside the receiver information
    receiver_blob = _get_state_data(make_entity_address(entity_id), context)
    receiver_data = storage_pb2.Entity()
    receiver_data.ParseFromString(receiver_blob)
    receive_verify_key = nacl.signing.VerifyKey(
        receiver_data.verify_key, encoder=nacl.encoding.RawEncoder)

    # exchanges must be sorted already in ascending order by sequence number
    exchanges = cbor2.loads(response.content)
    frontier = current_frontier

    # TODO(matt9j) Possibly speedup by re-using exchange protobufs
    # validate all the exchanges
    for exchange_blob in exchanges:
        if frontier >= proposed_frontier:
            LOG.warning("Got too many exchange records or bad frontier req?!")
            break

        exchange = asterales_parsers.parse_exchange_record(exchange_blob)
        receive_sqn = exchange.receiver_sequence_number_msb * (2 ** 64) + \
                      exchange.receiver_sequence_number_lsb
        last_valid_receive_sqn = exchange.last_valid_sequence_number_msb * (2**64) + \
                                 exchange.last_valid_sequence_number_lsb
        # Validate signatures
        try:
            receive_verify_key.verify(exchange.receiver_signed_blob,
                                      exchange.receiver_signature,
                                      encoder=nacl.encoding.RawEncoder)
        except nacl.exceptions.BadSignatureError as e:
            LOG.error(e)
            raise InvalidTransaction(
                'Exchange receive signature invalid sqn:{}'.format(
                    receive_sqn))

        sender_blob = _get_state_data(make_entity_address(exchange.sender_id),
                                      context)
        sender_data = storage_pb2.Entity()
        sender_data.ParseFromString(sender_blob)
        sender_verify_key = nacl.signing.VerifyKey(
            sender_data.verify_key, encoder=nacl.encoding.RawEncoder)
        try:
            sender_verify_key.verify(exchange.sender_signed_blob,
                                     exchange.sender_signature,
                                     encoder=nacl.encoding.RawEncoder)
        except nacl.exceptions.BadSignatureError:
            raise InvalidTransaction(
                'Exchange send signature invalid sqn:{}'.format(receive_sqn))

        if last_valid_receive_sqn != frontier:
            LOG.warning("Gap discovered-- in this hacky initial implementation"
                        " state may now be corrupted.")
            raise InvalidTransaction()

        receiver_data.balance += exchange.amount

        # TODO(matt9j) Don't serialize all the send messages until done! Some
        #  may be repeated...
        sender_data.balance -= exchange.amount
        _set_state_data(make_entity_address(exchange.sender_id),
                        sender_data.SerializeToString(), context)

        frontier = receive_sqn

    # Serialize the common receive buffer at the end of processing.
    # TODO(matt9j) Fix LSB/MSB precision laziness.
    frontier_sequence_number_lsb = frontier & 0xFFFFFFFFFFFFFFFF
    frontier_sequence_number_msb = frontier >> 64
    receiver_data.frontier_sequence_number = frontier_sequence_number_lsb
    _set_state_data(make_entity_address(exchange.receiver_id),
                    receiver_data.SerializeToString(), context)
Пример #7
0
 def add_user(self, user_id, payload, wait=None):
     address = make_entity_address(user_id)
     return self._send_transaction(ActionTypes.ADD_USER.value,
                                   payload, [address],
                                   wait=wait)
Пример #8
0
 def add_community(self, network_id, payload, wait=None):
     address = make_entity_address(network_id)
     return self._send_transaction(ActionTypes.ADD_NET.value,
                                   payload, [address],
                                   wait=wait)