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

feat!: upgrade shared components #1606

Merged

Conversation

genaris
Copy link
Contributor

@genaris genaris commented Oct 14, 2023

Upgrade aries-askar, anoncreds-rs and indy-vdr to their latest versions. This implies that we are dropping node 16 support.

@genaris genaris force-pushed the feat/update-shared-components branch from e7841e6 to 4d4fa24 Compare October 14, 2023 00:56
@codecov-commenter
Copy link

codecov-commenter commented Oct 14, 2023

Codecov Report

Merging #1606 (037f091) into main (b2ba7c7) will decrease coverage by 8.12%.
The diff coverage is 0.00%.

@@            Coverage Diff             @@
##             main    #1606      +/-   ##
==========================================
- Coverage   85.67%   77.55%   -8.12%     
==========================================
  Files         951      906      -45     
  Lines       22892    22013     -879     
  Branches     4024     3896     -128     
==========================================
- Hits        19613    17073    -2540     
- Misses       3095     4592    +1497     
- Partials      184      348     +164     
Files Coverage Δ
...ges/anoncreds-rs/src/services/__tests__/helpers.ts 100.00% <ø> (ø)
packages/askar/src/wallet/AskarWallet.ts 52.70% <0.00%> (-25.22%) ⬇️

... and 220 files with indirect coverage changes

Copy link
Contributor

@TimoGlastra TimoGlastra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!!

"@types/bn.js": "^5.1.0",
"@types/ref-array-di": "^1.2.6",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to add these types? Should they be added as deps to the shared components packages so we don't have to re-add them here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it seems that we should add them as dependency of either shared components of the patched ffi-napi/ref-napi (most likely these ones).

packages/indy-sdk-to-askar-migration/tests/migrate.test.ts Outdated Show resolved Hide resolved
@genaris
Copy link
Contributor Author

genaris commented Oct 15, 2023

When running the test suite locally, I was getting some A jest worker process was terminated by another process errors, which is something that rarely happened before, so I was hoping this would not happen in the CI (which of course it did as well), making me sad and terrified.

For example, this is a log I get:

Summary of all failing tests
 FAIL  tests/e2e-http.test.ts
  ● Test suite failed to run

    A jest worker process (pid=87704) was terminated by another process: signal=SIGABRT, exitCode=null. Operating system logs may contain more information on why this occurred.

      at ChildProcessWorker._onExit (../node_modules/jest-worker/build/workers/ChildProcessWorker.js:370:23)

 FAIL  packages/core/tests/wallet.test.ts
  ● Test suite failed to run

    A jest worker process (pid=87705) was terminated by another process: signal=SIGABRT, exitCode=null. Operating system logs may contain more information on why this occurred.

      at ChildProcessWorker._onExit (../../node_modules/jest-worker/build/workers/ChildProcessWorker.js:370:23)

 FAIL  packages/askar/src/wallet/__tests__/packing.test.ts
  ● Test suite failed to run

    A jest worker process (pid=87706) was terminated by another process: signal=SIGBUS, exitCode=null. Operating system logs may contain more information on why this occurred.

      at ChildProcessWorker._onExit (../../node_modules/jest-worker/build/workers/ChildProcessWorker.js:370:23)

 FAIL  packages/anoncreds/src/protocols/proofs/v1/__tests__/v1-indy-proof-proposal.e2e.test.ts
  ● Test suite failed to run

    A jest worker process (pid=87707) was terminated by another process: signal=SIGBUS, exitCode=null. Operating system logs may contain more information on why this occurred.

      at ChildProcessWorker._onExit (../../node_modules/jest-worker/build/workers/ChildProcessWorker.js:370:23)

 FAIL  packages/core/tests/oob.test.ts
  ● Test suite failed to run

    A jest worker process (pid=87703) was terminated by another process: signal=SIGABRT, exitCode=null. Operating system logs may contain more information on why this occurred.

      at ChildProcessWorker._onExit (../../node_modules/jest-worker/build/workers/ChildProcessWorker.js:370:23)


Test Suites: 5 failed, 3 skipped, 280 passed, 285 of 288 total
Tests:       22 skipped, 7 todo, 1407 passed, 1436 total
Snapshots:   15 passed, 15 total
Time:        162.651 s, estimated 270 s

Some notes about this:

  • I've upgraded to node 18.18.2 and jest 29.7.0 to see if it gets better (as there was a related issue fixed some time ago), with no luck
  • If I use an older version of node 18 (like 18.5) it feels a bit more stable, but getting some of these errors as well
  • I've tried using a fresh checkout of main branch and it sometimes also spawns these errors
  • Not sure why (and not related to this), but now when I do a fresh checkout or simply remove node_modules and run yarn install followed by yarn test, it always complains about the location of indy-sdk:
dlopen(/Users/genaris/dev/aries-framework-javascript/node_modules/indy-sdk/build/Release/indynodejs.node, 0x0001): Library not loaded: /Users/beri/developer/work/hyperledger/indy-sdk/libindy/target/release/deps/libindy.dylib
      Referenced from: <898333AD-4310-36C9-965A-89AB16B8E18F> /Users/genaris/dev/aries-framework-javascript/node_modules/indy-sdk/build/Release/indynodejs.node
      Reason: tried: '/Users/beri/developer/work/hyperledger/indy-sdk/libindy/target/release/deps/libindy.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Users/beri/developer/work/hyperledger/indy-sdk/libindy/target/release/deps/libindy.dylib' (no such file), '/Users/beri/developer/work/hyperledger/indy-sdk/libindy/target/release/deps/libindy.dylib' (no such file)

This never happened to me before (BTW I've recently upgraded to MacOS 14.0), or if it did, I fixed it permanently by running install_name_tool -change /Users/beri/developer/work/hyperledger/indy-sdk/libindy/target/release/deps/libindy.dylib /usr/local/lib/libindy.dylib node_modules/indy-sdk/build/Release/indynodejs.node only once.

@genaris
Copy link
Contributor Author

genaris commented Oct 17, 2023

Quick update: I've been digging a little bit on this and it seems that the issue comes from anoncreds-rs, in particular the changes introduced in hyperledger/anoncreds-rs#238 in regards of calling anoncreds_string_free.

While debugging I've added --detectOpenHandles CLI option to jest, which led me to see a malloc-double-free-error, which might be related to this issue, as it represents that somewhere in the code we are attempting to free the same memory address.

In https://docs.rs/ffi-support/latest/ffi_support/fn.destroy_c_string.html (pattern followed to define anoncreds_string_free in anoncreds-rs) it states:

This is inherently unsafe, since we’re deallocating memory. Be sure

  • Nobody can use the memory after it’s deallocated.
  • The memory was actually allocated on this heap (and it’s not a string from the other side of the FFI which was allocated on e.g. the C heap).

This makes me wonder if in this case we are allocating string buffer within Node.js, meaning that it will be in charge of freeing the data when necessary (i.e. there is no actual need to call anoncreds_string_free). I'll have to look at ref-napi code in order to understand it further, but considering that we call its alloc method, this reasoning could make sense? @berendsliedrecht I'm all ears to know your opinion on this 😄.

@TimoGlastra
Copy link
Contributor

but considering that we call its alloc method, this reasoning could make sense?

How is the string sent over the FFI layer? As a string, or as a reference to a string?

@TimoGlastra
Copy link
Contributor

BTW -- After thinking of it more, I'm supportive of already removing indy-sdk in 0.5.0 as well. It's causing issues and it's time it should go. If people want to keep using indy-sdk they can do so with 0.4.x. Not that it fixes the issues that are happening here. But it would help with simplifying this repo a bit

@berendsliedrecht
Copy link
Contributor

berendsliedrecht commented Oct 17, 2023

Quick update: I've been digging a little bit on this and it seems that the issue comes from anoncreds-rs, in particular the changes introduced in hyperledger/anoncreds-rs#238 in regards of calling anoncreds_string_free.

While debugging I've added --detectOpenHandles CLI option to jest, which led me to see a malloc-double-free-error, which might be related to this issue, as it represents that somewhere in the code we are attempting to free the same memory address.

In https://docs.rs/ffi-support/latest/ffi_support/fn.destroy_c_string.html (pattern followed to define anoncreds_string_free in anoncreds-rs) it states:

This is inherently unsafe, since we’re deallocating memory. Be sure

  • Nobody can use the memory after it’s deallocated.
  • The memory was actually allocated on this heap (and it’s not a string from the other side of the FFI which was allocated on e.g. the C heap).

This makes me wonder if in this case we are allocating string buffer within Node.js, meaning that it will be in charge of freeing the data when necessary (i.e. there is no actual need to call anoncreds_string_free). I'll have to look at ref-napi code in order to understand it further, but considering that we call its alloc method, this reasoning could make sense? @berendsliedrecht I'm all ears to know your opinion on this 😄.

Looking at this bit of code:

  public revocationRegistryDefinitionGetAttribute(options: { objectHandle: ObjectHandle; name: string }) {
    const { objectHandle, name } = serializeArguments(options)

    const ret = allocateStringBuffer() // IMPORTANT
    this.nativeAnoncreds.anoncreds_revocation_registry_definition_get_attribute(objectHandle, name, ret)
    this.handleError()

    return handleReturnPointer<string>(ret, this.nativeAnoncreds.anoncreds_string_free)
  }

with:

function handleReturnPointer<Return>(returnValue: Buffer, cleanupCallback?: (buffer: Buffer) => void): Return {
  if (returnValue.address() === 0) {
    throw AnoncredsError.customError({ message: 'Unexpected null pointer' })
  }

  const ret = returnValue.deref() as Return
  if (cleanupCallback) cleanupCallback(returnValue)

  return ret
}

And the anoncreds.h shows:

ErrorCode anoncreds_revocation_registry_definition_get_attribute(ObjectHandle handle,
                                                                 FfiStr name,
                                                                 const char **result_p);

and:

#[no_mangle]
pub extern "C" fn anoncreds_revocation_registry_definition_get_attribute(
    handle: ObjectHandle,
    name: FfiStr,
    result_p: *mut *const c_char,
) -> ErrorCode {
    catch_error(|| {
        check_useful_c_ptr!(result_p);
        let reg_def = handle.load()?;
        let reg_def = reg_def.cast_ref::<RevocationRegistryDefinition>()?;
        let val = match name.as_opt_str().unwrap_or_default() {
            "max_cred_num" => reg_def.value.max_cred_num.to_string(),
            "tails_hash" => reg_def.value.tails_hash.to_string(),
            "tails_location" => reg_def.value.tails_location.to_string(),
            s => return Err(err_msg!("Unsupported attribute: {}", s)),
        };
        unsafe { *result_p = rust_string_to_c(val) }; // IMPORTANT
        Ok(())
    })
}

We create a Buffer within Node.js which is passed in over FFI to Rust where the Rust library writes their value to it. Since allocation that happens within Node.js will be cleaned up by Node.js, we do not have to manually call string_free afterwards. To confirm this, we can create some small tests around this if that is needed.

@genaris
Copy link
Contributor Author

genaris commented Oct 17, 2023

We create a Buffer within Node.js which is passed in over FFI to Rust where the Rust library writes their value to it. Since allocation that happens within Node.js will be cleaned up by Node.js, we do not have to manually call string_free afterwards.

This is the same conclusion I got now. Before, I thought this allocation in JS was just about creating a pointer, and passing it to let Rust code to actually allocate memory. Just to confirm, do you think this is the right approach, or should Node.js wrapper actually use a regular pointer so it delegates its allocation to Rust part as in others?

@genaris
Copy link
Contributor Author

genaris commented Oct 17, 2023

BTW -- After thinking of it more, I'm supportive of already removing indy-sdk in 0.5.0 as well. It's causing issues and it's time it should go. If people want to keep using indy-sdk they can do so with 0.4.x. Not that it fixes the issues that are happening here. But it would help with simplifying this repo a bit

Agree! I guess it will not be part of this PR but just curious about what are your thoughts regarding where to put that module. Shall we completely remove it and just mention it is available in 0.4.x in case anyone needs it? Or move it somewhere else? I'd say the first option.

@TimoGlastra
Copy link
Contributor

I say we completely remove it. If someone wants to keep using it, it would be quite easy to create a separate repo where the update the indy-sdk package to 0.5.0. I think it's important we take some steps to reduce technical debts and make it easier to maintain the repo

@TimoGlastra
Copy link
Contributor

This is the same conclusion I got now. Before, I thought this allocation in JS was just about creating a pointer, and passing it to let Rust code to actually allocate memory. Just to confirm, do you think this is the right approach, or should Node.js wrapper actually use a regular pointer so it delegates its allocation to Rust part as in others?

I think having the pointer be managed in Node.JS is ideal right, as we then can leverage the GC from Node.JS instead of having to do it manually

@TimoGlastra
Copy link
Contributor

Created a PR: hyperledger/anoncreds-rs#253

@TimoGlastra
Copy link
Contributor

BTW -- currently working on removing indy-sdk. But it'd be easier if this PR is merged before I open that PR (lot of conflicts otherwise)

@genaris genaris marked this pull request as ready for review October 26, 2023 12:53
@genaris genaris requested a review from a team as a code owner October 26, 2023 12:53
@genaris
Copy link
Contributor Author

genaris commented Oct 30, 2023

It seems this PR is stuck because it needs to run "Integration Tests (16.x)", which is not available anymore since we dropped node 16 support. It should be replaced by "Integration Tests (20.x)" I think.

Does any other maintainer have permission to update this? @TimoGlastra @jakubkoci @berendsliedrecht @karimStekelenburg et al. 😄

@TimoGlastra
Copy link
Contributor

Removed 16, added 20

@TimoGlastra TimoGlastra merged commit 2f5d139 into openwallet-foundation:main Oct 30, 2023
8 checks passed
@genaris genaris deleted the feat/update-shared-components branch October 30, 2023 21:08
auer-martin pushed a commit to auer-martin/aries-framework-javascript that referenced this pull request Nov 15, 2023
auer-martin pushed a commit to auer-martin/aries-framework-javascript that referenced this pull request Dec 4, 2023
genaris added a commit to genaris/credo-ts that referenced this pull request Dec 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants