Skip to content

Commit

Permalink
Merge pull request #153 from input-output-hk/add-fragment-id-from-raw
Browse files Browse the repository at this point in the history
Add fragment id from raw
  • Loading branch information
ecioppettini authored May 14, 2021
2 parents 13a57b3 + c4d7ea9 commit b5a1b05
Show file tree
Hide file tree
Showing 18 changed files with 542 additions and 29 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- spending_counter
- settings_new
- settings_get
- fragment_from_raw
- fragment_id
- fragment_delete

### Changed

pending_transactions now returns transactions in order relative to the same
wallet type instead of arbitrary order. First starting with deadalus/yoroi/free
utxo keys (those are all exclusive) in order of creating, and then the account
transactions, also in order of creation (and signing).

## [0.6.0-pre1]

Expand Down
84 changes: 82 additions & 2 deletions bindings/wallet-c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ use std::{
};
pub use wallet::Settings as SettingsRust;
use wallet_core::c::{
fragment::{fragment_delete, fragment_from_raw, fragment_id},
symmetric_cipher_decrypt, vote, wallet_convert, wallet_convert_ignored,
wallet_convert_transactions_get, wallet_convert_transactions_size, wallet_delete_conversion,
wallet_delete_error, wallet_delete_proposal, wallet_delete_settings, wallet_delete_wallet,
wallet_id, wallet_import_keys, wallet_recover, wallet_retrieve_funds, wallet_set_state,
wallet_spending_counter, wallet_total_value, wallet_vote_cast,
};
use wallet_core::{
Conversion as ConversionRust, Error as ErrorRust, Proposal as ProposalRust,
Wallet as WalletRust,
Conversion as ConversionRust, Error as ErrorRust, Fragment as FragmentRust,
Proposal as ProposalRust, Wallet as WalletRust,
};

#[repr(C)]
Expand All @@ -26,6 +27,8 @@ pub struct Conversion {}
#[repr(C)]
pub struct Proposal {}
#[repr(C)]
pub struct Fragment;
#[repr(C)]
pub struct Error {}

#[repr(C)]
Expand All @@ -35,6 +38,7 @@ pub type WalletPtr = *mut Wallet;
pub type SettingsPtr = *mut Settings;
pub type ConversionPtr = *mut Conversion;
pub type ProposalPtr = *mut Proposal;
pub type FragmentPtr = *mut Fragment;
pub type ErrorPtr = *mut Error;
pub type EncryptingVoteKeyPtr = *mut EncryptingVoteKey;

Expand Down Expand Up @@ -657,6 +661,70 @@ pub unsafe extern "C" fn iohk_jormungandr_wallet_error_details(error: ErrorPtr)
}
}

/// deserialize a fragment from bytes
///
/// # Parameters
///
/// * `buffer` -- a pointer to the serialized fragment bytes.
/// * `buffer_length` -- the length of the serialized fragment bytes array.
/// * `fragment` -- the location of the pointer to the deserialized fragemnt.
///
/// # Errors
///
/// This functions may fail if:
///
/// * `buffer` is a null pointer.
/// * `fragment` is a null pointer.
/// * `buffer` contains invalid fragment bytes.
///
/// # Safety
///
/// This function dereference raw pointers. Even though
/// the function checks if the pointers are null. Mind not to put random values
/// in or you may see unexpected behaviors
///
/// Don't forget to delete the fragment object with `iohk_jormungandr_delete_fragment`.
#[no_mangle]
pub unsafe extern "C" fn iohk_jormungandr_fragment_from_raw(
buffer: *const u8,
buffer_length: usize,
fragment_out: *mut FragmentPtr,
) -> ErrorPtr {
fragment_from_raw(
buffer,
buffer_length,
fragment_out as *mut *mut FragmentRust,
)
.into_c_api() as ErrorPtr
}

/// get the ID of the provided fragment
///
/// # Parameters
///
/// * `fragment` -- a pointer to fragment.
/// * `fragment_id_out` -- a pointer to a pre-allocated 32 bytes array.
///
/// # Errors
///
/// This function would return an error if either of the provided pointers is null.
///
/// # Safety
///
/// This function dereference raw pointers. Even though
/// the function checks if the pointers are null. Mind not to put random values
/// in or you may see unexpected behaviors.
///
/// `fragment_id_out` is expected to be an already allocated 32 byte array. Doing otherwise may
/// potentially result into an undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn iohk_jormungandr_fragment_id(
fragment: FragmentPtr,
fragment_id_out: *mut u8,
) -> ErrorPtr {
fragment_id(fragment as *mut FragmentRust, fragment_id_out).into_c_api() as ErrorPtr
}

/// Delete a null terminated string that was allocated by this library
///
/// # Safety
Expand Down Expand Up @@ -754,3 +822,15 @@ pub extern "C" fn iohk_jormungandr_wallet_delete_conversion(conversion: Conversi
pub extern "C" fn iohk_jormungandr_wallet_delete_proposal(proposal: ProposalPtr) {
wallet_delete_proposal(proposal as *mut ProposalRust)
}

/// delete the pointer
///
/// # Safety
///
/// This function dereference raw pointers. Even though
/// the function checks if the pointers are null. Mind not to put random values
/// in or you may see unexpected behaviors
#[no_mangle]
pub unsafe extern "C" fn iohk_jormungandr_delete_fragment(fragment: FragmentPtr) {
fragment_delete(fragment as *mut FragmentRust);
}
73 changes: 72 additions & 1 deletion bindings/wallet-c/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#ifndef IOHK_CHAIN_WALLET_LIBC_
#define IOHK_CHAIN_WALLET_LIBC_

/* Generated with cbindgen:0.18.0 */
/* Generated with cbindgen:0.19.0 */

/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */

Expand All @@ -25,6 +25,13 @@ typedef enum Discrimination
Discrimination_Test,
} Discrimination;

typedef struct Fragment
{

} Fragment;

typedef struct Fragment *FragmentPtr;

typedef struct Error
{

Expand Down Expand Up @@ -86,6 +93,70 @@ typedef struct LinearFee
struct PerVoteCertificateFee per_vote_certificate_fees;
} LinearFee;

/**
* delete the pointer
*
* # Safety
*
* This function dereference raw pointers. Even though
* the function checks if the pointers are null. Mind not to put random values
* in or you may see unexpected behaviors
*/
void iohk_jormungandr_delete_fragment(FragmentPtr fragment);

/**
* deserialize a fragment from bytes
*
* # Parameters
*
* * `buffer` -- a pointer to the serialized fragment bytes.
* * `buffer_length` -- the length of the serialized fragment bytes array.
* * `fragment` -- the location of the pointer to the deserialized fragemnt.
*
* # Errors
*
* This functions may fail if:
*
* * `buffer` is a null pointer.
* * `fragment` is a null pointer.
* * `buffer` contains invalid fragment bytes.
*
* # Safety
*
* This function dereference raw pointers. Even though
* the function checks if the pointers are null. Mind not to put random values
* in or you may see unexpected behaviors
*
* Don't forget to delete the fragment object with `iohk_jormungandr_delete_fragment`.
*/
ErrorPtr iohk_jormungandr_fragment_from_raw(const uint8_t *buffer,
uintptr_t buffer_length,
FragmentPtr *fragment_out);

/**
* get the ID of the provided fragment
*
* # Parameters
*
* * `fragment` -- a pointer to fragment.
* * `fragment_id_out` -- a pointer to a pre-allocated 32 bytes array.
*
* # Errors
*
* This function would return an error if either of the provided pointers is null.
*
* # Safety
*
* This function dereference raw pointers. Even though
* the function checks if the pointers are null. Mind not to put random values
* in or you may see unexpected behaviors.
*
* `fragment_id_out` is expected to be an already allocated 32 byte array. Doing otherwise may
* potentially result into an undefined behavior.
*/
ErrorPtr iohk_jormungandr_fragment_id(FragmentPtr fragment,
uint8_t *fragment_id_out);

/**
* decrypt payload of the wallet transfer protocol
*
Expand Down
2 changes: 1 addition & 1 deletion bindings/wallet-cordova/build_jni.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

def run():
for rust_target, android_target in targets.items():
out = subprocess.run(["cargo", "rustc", "--release", "--target",
out = subprocess.run(["cross", "rustc", "--release", "--target",
rust_target, "-p" "wallet-jni", "--", "-C", "lto"])

if out.returncode != 0:
Expand Down
1 change: 1 addition & 0 deletions bindings/wallet-cordova/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<source-file src="src/android/jormungandrwallet/Proposal.java" target-dir="src/com/iohk/jormungandrwallet" />
<source-file src="src/android/jormungandrwallet/PendingTransactions.java" target-dir="src/com/iohk/jormungandrwallet" />
<source-file src="src/android/jormungandrwallet/SymmetricCipher.java" target-dir="src/com/iohk/jormungandrwallet" />
<source-file src="src/android/jormungandrwallet/Fragment.java" target-dir="src/com/iohk/jormungandrwallet" />

<source-file src="src/android/libs/x86/libwallet_jni.so" target-dir="libs/x86" />
<source-file src="src/android/libs/x86_64/libwallet_jni.so" target-dir="libs/x86_64" />
Expand Down
17 changes: 17 additions & 0 deletions bindings/wallet-cordova/src/android/WalletPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.iohk.jormungandrwallet.Conversion;
import com.iohk.jormungandrwallet.Proposal;
import com.iohk.jormungandrwallet.SymmetricCipher;
import com.iohk.jormungandrwallet.Fragment;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
Expand Down Expand Up @@ -120,6 +121,9 @@ public boolean execute(final String action, final CordovaArgs args, final Callba
case "SETTINGS_GET":
settingsGet(args, callbackContext);
break;
case "FRAGMENT_ID":
fragmentId(args, callbackContext);
break;
case "WALLET_DELETE":
walletDelete(args, callbackContext);
break;
Expand Down Expand Up @@ -467,6 +471,19 @@ private void walletId(final CordovaArgs args, final CallbackContext callbackCont
}
}

private void fragmentId(final CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
final byte[] transaction = args.getArrayBuffer(0);

try {
final long fragmentPtr = Fragment.fromBytes(transaction);
final byte[] id = Fragment.id(fragmentPtr);
Fragment.delete(fragmentPtr);
callbackContext.success(id);
} catch (final Exception e) {
callbackContext.error(e.getMessage());
}
}

private void walletDelete(final CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
final Long walletPtr = args.getLong(0);

Expand Down
2 changes: 2 additions & 0 deletions bindings/wallet-cordova/src/ios/WalletPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
- (void)SETTINGS_NEW:(CDVInvokedUrlCommand*)command;
- (void)SETTINGS_GET:(CDVInvokedUrlCommand*)command;

- (void)FRAGMENT_ID:(CDVInvokedUrlCommand*)command;

- (void)WALLET_DELETE:(CDVInvokedUrlCommand*)command;
- (void)SETTINGS_DELETE:(CDVInvokedUrlCommand*)command;
- (void)CONVERSION_DELETE:(CDVInvokedUrlCommand*)command;
Expand Down
37 changes: 37 additions & 0 deletions bindings/wallet-cordova/src/ios/WalletPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,43 @@ - (void)SETTINGS_GET:(CDVInvokedUrlCommand*)command
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void)FRAGMENT_ID:(CDVInvokedUrlCommand*)command
{
CDVPluginResult* pluginResult = nil;

NSData* fragment_raw = [command.arguments objectAtIndex:0];

if ([fragment_raw isEqual:[NSNull null]]) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
messageAsString:@"missing argument"];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

FragmentPtr fragment_ptr = nil;
ErrorPtr result_fragment_from_raw =
iohk_jormungandr_fragment_from_raw(fragment_raw.bytes, fragment_raw.length, &fragment_ptr);

if (result_fragment_from_raw != nil) {
pluginResult = jormungandr_error_to_plugin_result(result_fragment_from_raw);
} else {
uint8_t fragment_id[32];
ErrorPtr result_fragment_id = iohk_jormungandr_fragment_id(fragment_ptr, fragment_id);

if (result_fragment_id != nil) {
pluginResult = jormungandr_error_to_plugin_result(result_fragment_id);
} else {
NSData* returnValue = [NSData dataWithBytes:fragment_id length:32];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArrayBuffer:returnValue];
}

iohk_jormungandr_delete_fragment(fragment_ptr);
}

[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void)WALLET_DELETE:(CDVInvokedUrlCommand*)command
{
NSString* wallet_ptr_raw = [command.arguments objectAtIndex:0];
Expand Down
34 changes: 34 additions & 0 deletions bindings/wallet-cordova/tests/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const pendingTransactionsGet = promisifyP(primitives.pendingTransactionsGet);
const symmetricCipherDecrypt = promisifyP(primitives.symmetricCipherDecrypt);
const settingsGet = promisifyP(primitives.settingsGet);
const settingsNew = promisifyP(primitives.settingsNew);
const fragmentId = promisifyP(primitives.fragmentId);


const tests = [
Expand Down Expand Up @@ -159,6 +160,9 @@ const tests = [

expect(await spendingCounter(walletPtr)).toBe(1);

const pending = await getPendingTransactions(walletPtr);
expect(pending.length).toBe(1);

await deleteSettings(settingsPtr);
await deleteWallet(walletPtr);
await deleteProposal(proposalPtr);
Expand Down Expand Up @@ -295,6 +299,36 @@ const tests = [

await deleteSettings(settingsPtr);
}],
['get vote fragment id', async function () {
const array = new Array(32);
for (let index = 0; index < array.length; index++) {
array[index] = index;
}

const votePlanId = new Uint8Array(array);
const index = 0;
const numChoices = 3;

const proposalPtr = await proposalNewPublic(votePlanId, index, numChoices);
const walletPtr = await restoreWallet(YOROI_WALLET);
const settingsPtr = await retrieveFunds(walletPtr, hexStringToBytes(BLOCK0));
await walletSetState(walletPtr, 1000000, 0);

const tx1 = await walletVote(walletPtr, settingsPtr, proposalPtr, 1);
const tx2 = await walletVote(walletPtr, settingsPtr, proposalPtr, 2);

const id1 = await fragmentId(new Uint8Array(tx1));
const id2 = await fragmentId(new Uint8Array(tx2));

const pendingTransactions = await getPendingTransactions(walletPtr);

expect(uint8ArrayEquals(id1, pendingTransactions[0])).toBe(true);
expect(uint8ArrayEquals(id2, pendingTransactions[0])).toBe(true);

await deleteSettings(settingsPtr);
await deleteWallet(walletPtr);
await deleteProposal(proposalPtr);
}],
]

exports.defineAutoTests = function () {
Expand Down
Loading

0 comments on commit b5a1b05

Please sign in to comment.