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

Problem issuing an ACDC with 2 edges #775

Closed
pSchlarb opened this issue May 3, 2024 · 13 comments
Closed

Problem issuing an ACDC with 2 edges #775

pSchlarb opened this issue May 3, 2024 · 13 comments
Assignees
Labels
bug Something isn't working triage

Comments

@pSchlarb
Copy link
Contributor

pSchlarb commented May 3, 2024

Version

1.2.0-dev2

Environment

Docker mcr.microsoft.com/devcontainers/python:1-3.12-bullseye, python 3.12.3, Development Container

Expected behavior

The ACDC with 2 edges should be created in a reasonable time.

Actual behavior

The kli vc create command for the ACDC with the 2 edges (Attestation ACDC in the sample script) is hanging with the following output and not finishing (i let it run for over 30 minutes):

Waiting for TEL event witness receipts
Sending TEL events to witnesses

Steps to reproduce

Sample Script to reproduce, Devcontainer setup, ACDC schemas and witness log outputs are hosted here:

https://github.com/pSchlarb/keriTest

@pSchlarb pSchlarb added bug Something isn't working triage labels May 3, 2024
@kentbull
Copy link
Contributor

I haven't used dev containers before. Will you add a step-by-step guide to the README.md document, or a Bash script, that reproduces what you are experiencing. Conceptually I get it, though I would need to see what OOBI resolutions are happening for AIDs and ACDC schemas to narrow down potential sources of failures.

@pSchlarb
Copy link
Contributor Author

Dev Containers are basically just docker containers with all your project related dependencies and some for vscode to attach to. You basically start it, mount your workspace and work inside the container.
That being said, i used the basic python devcontainer base image and just installed keripy(1.2.0-dev2) and the vlei-server.

The bash script workshop.sh in my repo is the full walkthrough(commented with regions and the logical echo output commands).

Regarding the script if used outside of a dev-container (which is also provided within that repo(.devcontainer/Dockerfile)) it should be fine if keripy and the vlei-server are installed.

@m00sey m00sey self-assigned this Sep 17, 2024
@kentbull kentbull self-assigned this Oct 19, 2024
@kentbull
Copy link
Contributor

I have been able to reproduce this issue with an updated version of the Abydos Tutorial, what this Devcontainer setup was based on.

My current guess is there was a regression of functionality moving from the original Mark I implementation in KERIpy back in version 0.6.7 during the upgrade to v1.1.0 of KERIpy.

During the upgrade to version 1.1.0 the old API for credential issuance and presentation was deprecated in favor of the new Issuance and Presentation Exchange protocol, or IPEX. It appears that in the upgrade to IPEX that support for an edge operator providing multi edge support was missed.

I could be wrong here.

The next step towards issue resolution is to compare the old 0.6.7 (or 1.0.0) issuance and presentation logic to the new IPEX logic as of version 1.1.0 or newer (up to 1.1.20).

@kentbull
Copy link
Contributor

As of commit 6ed24cf in the abydos-tutorial repository the code works to reproduce the bug by issuing the credential chain outlined in the blog post. This includes issuing the following sequence of credentials:

[TreasureHuntingJourney] issued by Ramiel to Richard
   ↑   ↑ [JourneyMarkRequest] credential                     (1 edge)
   |   | `journey` edge pointing to TreasureHuntingJourney     (1)
   |         ↑ [JourneyMark] credential                      (1 edge)
   |         | `request` edge pointing to JourneyMarkRequest   (1)
   |               ↑ [JourneyCharter] credential             (2 edges)
   |               | `mark` edge pointing to JourneyMark       (1)
 `journey` edge pointing to TreasureHuntingJourney             (2)

@kentbull
Copy link
Contributor

kentbull commented Oct 27, 2024

@pSchlarb As of commit 53e3edd I have working code in the Abydos Tutorial that successfully issues a credential with two edges.

Short Answer

Short answer, use the NI2I operator for your edges, like shown in that commit, and your issuance will succeed.

Long Answer

It is likely that your issuance was failing on line 346 in the keri.vdr.verifying.Verifier class as shown below:

class Verifier:
  ...
  def verifyChain(self, nodeSaid, op, issuer):
    """ Verifies the node credential at the end of an edge..."""
    said = self.reger.saved.get(keys=nodeSaid)
    if said is None:
        return None

    creder = self.reger.creds.get(keys=nodeSaid)

    if op not in ['I2I', 'DI2I', 'NI2I']:
        op = 'I2I' if 'i' in creder.attrib else 'NI2I'

    if op != 'NI2I':
        if 'i' not in creder.attrib:
            return None

        iss = self.reger.subjs.get(keys=creder.attrib['i'])
        if iss is None:
            return None

        if op == 'I2I' and issuer != creder.attrib['i']:  # <-- CODE FAILS HERE
            return None

        if op == "DI2I":
            raise NotImplementedError()

    if creder.regi not in self.tevers:
        return None

    tever = self.tevers[creder.regi]

    state = tever.vcState(nodeSaid)
    if state is None:
        return None

    return state

The I2I operator is the default operator used when no other operator is specified. Since your code is based off of my Abydos Tutorial code then you likely did not upgrade your code, as I did not until recently, then your code was using the I2I operator because the operator argument to the Verifier.verifyChain() function was "None" since no operator was specified in your ACDC schema nor edge.

When you specify an operator in your edge it looks like this:

{
  "d": "",
  "mark": {
    "n": "ECvekotoiso4Zc9QwhvIR2vkiemIcKTHUi50iIJv5we_",
    "s": "EBEefH4LNQswHSrXanb-3GbjCZK7I_UCL6BdD-zwJ4my",
    "o": "NI2I"  // <-- note the use of the NI2I operator here
  },
  "journey": {
    "n": "EMZipCYYHkLX-JegdulwcvG6-N8pI462vGYmPXRGNvE0",
    "s": "EIxAox3KEhiQ_yCwXWeriQ3ruPWbgK94NDDkHAZCuP9l",
    "o": "NI2I"  // <-- note the use of the NI2I operator here
  }
}

Background

With the addition of the operators to KERIpy, which happened about the same time that IPEX landed, then the default rules for ACDC edge validation became more restrictive as the rules defaulted to I2I operator. The I2I operator assumes that every other credential in a credential chain will alternate between the original issuee and issuer, kind of like an SMS message chain between two parties. This works for some of the credentials in the vLEI ecosystem, yet is not natural mapping to other use cases.

I just so happened in the Abydos Tutorial to pick a different kind of use case, more of a credential fact aggregation use case, so it turned out the NI2I operator was the most appropriate. The NI2I operator pretty much says that your credentials are not a back and forth chain between two parties. In my opinion the NI2I operator is a better default as it is a relaxed set of constraints. Unless you know that you need the I2I ACDC edge operator (the current default) then just use the NI2I operator.

Remember, you have to specify this operator in your ACDC schema like shown below:

// other parts of schema
                          // edge properties section
                               "o": {
                                    "description": "Edge operator type - I2I, NI2I, or NOT",
                                    "type": "string",
                                    "const": "NI2I"
                                }
// other parts of schema

Conclusion

  • Use the NI2I operator as your default edge operator unless you know you need one of the others.
  • Issuing ACDCs with two or more edges still works. Just use the correct operator for your use case.

I will leave this issue open until we get a positive confirmation from you that this works for you.

@kentbull
Copy link
Contributor

One last note, to debug the Sending TEL events to witnesses error message you can turn the debug logs on for your installation by doing the following two things:

# Make sure your import of the `help` package from the `hio` package, not the `keri` package
from hio import help
logger = help.ogler.getLogger()
help.ogler.level = logging.getLevelName('DEBUG')

@pSchlarb
Copy link
Contributor Author

pSchlarb commented Nov 4, 2024

Thank you for the detailed explanation. It works now.

@pSchlarb pSchlarb closed this as completed Nov 4, 2024
@SmithSamuelM
Copy link
Collaborator

@kentbull The reason the I2I and AND are the default edge operators is because KERI/ACDC is security first. This means locked down by default, i.e. the most restictive constraint by default. Which will force things to fail that are looser. So the user must explicitly know what they are doing inorder to be weaker and explicitly set them to be weaker.

@kentbull
Copy link
Contributor

kentbull commented Nov 4, 2024

@SmithSamuelM thank you for the explanation. That makes sense. It was not at first intuitive to me since I had my mindset thinking of what would be easiest to use rather than what would be most secure. It has taken effort to train my mind to start thinking of security first, so thank you for the explanation.

To ease the learning path for those that come after me it does seem like it would be nice to have a descriptive error that occurs on edge validation failure so that when the appropriate log level is turned on that the failure reason is obvious. I will make an issue for this rich validation failure error message.

@kentbull
Copy link
Contributor

kentbull commented Nov 4, 2024

the I2I and AND are the default edge operators

And as a follow up, are you saying @SmithSamuelM that the AND operator is the default behavior? I did not see an explicit AND operator in the codebase so I am wondering if the AND logic is implicit at this point.

@SmithSamuelM
Copy link
Collaborator

SmithSamuelM commented Nov 4, 2024 via email

@kentbull
Copy link
Contributor

kentbull commented Nov 4, 2024

Thank you, I understand now.

As a wrap up of the discussion here I added an issue for adding an edge operator-specific error and logging around this here: #885

@SmithSamuelM
Copy link
Collaborator

SmithSamuelM commented Nov 4, 2024

See section 11.3.3 of ACDC spec M-ary operator table. and Section 11.3.4 for Unary operator table.

When the Operator, o, field is missing in an Edge-group block, the default value for the Operator, o, field MUST be the AND Operator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage
Projects
None yet
Development

No branches or pull requests

4 participants