From aa762f8ac1183f89a5fa1812e5fe54ac9b75fd4b Mon Sep 17 00:00:00 2001 From: jowparks Date: Mon, 22 Jan 2024 16:37:40 -0800 Subject: [PATCH] Unsigned transaction napi (#4563) * unsigned transaction napi * adds unsigned transaction napi binding and test to verify ser/de works on JS side --- ironfish-rust-nodejs/index.d.ts | 5 ++++ ironfish-rust-nodejs/index.js | 3 +- .../src/structs/transaction.rs | 26 +++++++++++++++++ .../tests/unsigned.test.slow.ts | 28 +++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 ironfish-rust-nodejs/tests/unsigned.test.slow.ts diff --git a/ironfish-rust-nodejs/index.d.ts b/ironfish-rust-nodejs/index.d.ts index 4514adfd9a..23c6f0cc17 100644 --- a/ironfish-rust-nodejs/index.d.ts +++ b/ironfish-rust-nodejs/index.d.ts @@ -226,6 +226,11 @@ export class Transaction { build(proofGenerationKeyStr: string, viewKeyStr: string, outgoingViewKeyStr: string, publicAddressStr: string, intendedTransactionFee: bigint, changeGoesTo?: string | undefined | null): Buffer setExpiration(sequence: number): void } +export type NativeUnsignedTransaction = UnsignedTransaction +export class UnsignedTransaction { + constructor(jsBytes: Buffer) + serialize(): Buffer +} export class FoundBlockResult { randomness: string miningRequestId: number diff --git a/ironfish-rust-nodejs/index.js b/ironfish-rust-nodejs/index.js index df7b6811f1..8f88cd7828 100644 --- a/ironfish-rust-nodejs/index.js +++ b/ironfish-rust-nodejs/index.js @@ -252,7 +252,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { FishHashContext, roundOne, contribute, verifyTransform, KEY_LENGTH, NONCE_LENGTH, BoxKeyPair, randomBytes, boxMessage, unboxMessage, RollingFilter, initSignalHandler, triggerSegfault, ASSET_ID_LENGTH, ASSET_METADATA_LENGTH, ASSET_NAME_LENGTH, ASSET_LENGTH, Asset, NOTE_ENCRYPTION_KEY_LENGTH, MAC_LENGTH, ENCRYPTED_NOTE_PLAINTEXT_LENGTH, ENCRYPTED_NOTE_LENGTH, NoteEncrypted, PUBLIC_ADDRESS_LENGTH, RANDOMNESS_LENGTH, MEMO_LENGTH, AMOUNT_VALUE_LENGTH, DECRYPTED_NOTE_LENGTH, Note, PROOF_LENGTH, TRANSACTION_SIGNATURE_LENGTH, TRANSACTION_PUBLIC_KEY_RANDOMNESS_LENGTH, TRANSACTION_EXPIRATION_LENGTH, TRANSACTION_FEE_LENGTH, LATEST_TRANSACTION_VERSION, TransactionPosted, Transaction, verifyTransactions, LanguageCode, generateKey, spendingKeyToWords, wordsToSpendingKey, generateKeyFromPrivateKey, initializeSapling, FoundBlockResult, ThreadPoolHandler, isValidPublicAddress } = nativeBinding +const { FishHashContext, roundOne, contribute, verifyTransform, KEY_LENGTH, NONCE_LENGTH, BoxKeyPair, randomBytes, boxMessage, unboxMessage, RollingFilter, initSignalHandler, triggerSegfault, ASSET_ID_LENGTH, ASSET_METADATA_LENGTH, ASSET_NAME_LENGTH, ASSET_LENGTH, Asset, NOTE_ENCRYPTION_KEY_LENGTH, MAC_LENGTH, ENCRYPTED_NOTE_PLAINTEXT_LENGTH, ENCRYPTED_NOTE_LENGTH, NoteEncrypted, PUBLIC_ADDRESS_LENGTH, RANDOMNESS_LENGTH, MEMO_LENGTH, AMOUNT_VALUE_LENGTH, DECRYPTED_NOTE_LENGTH, Note, PROOF_LENGTH, TRANSACTION_SIGNATURE_LENGTH, TRANSACTION_PUBLIC_KEY_RANDOMNESS_LENGTH, TRANSACTION_EXPIRATION_LENGTH, TRANSACTION_FEE_LENGTH, LATEST_TRANSACTION_VERSION, TransactionPosted, Transaction, verifyTransactions, UnsignedTransaction, LanguageCode, generateKey, spendingKeyToWords, wordsToSpendingKey, generateKeyFromPrivateKey, initializeSapling, FoundBlockResult, ThreadPoolHandler, isValidPublicAddress } = nativeBinding module.exports.FishHashContext = FishHashContext module.exports.roundOne = roundOne @@ -292,6 +292,7 @@ module.exports.LATEST_TRANSACTION_VERSION = LATEST_TRANSACTION_VERSION module.exports.TransactionPosted = TransactionPosted module.exports.Transaction = Transaction module.exports.verifyTransactions = verifyTransactions +module.exports.UnsignedTransaction = UnsignedTransaction module.exports.LanguageCode = LanguageCode module.exports.generateKey = generateKey module.exports.spendingKeyToWords = spendingKeyToWords diff --git a/ironfish-rust-nodejs/src/structs/transaction.rs b/ironfish-rust-nodejs/src/structs/transaction.rs index 97d181fe01..6e1d30951d 100644 --- a/ironfish-rust-nodejs/src/structs/transaction.rs +++ b/ironfish-rust-nodejs/src/structs/transaction.rs @@ -7,6 +7,7 @@ use std::cell::RefCell; use std::convert::TryInto; use ironfish::assets::asset_identifier::AssetIdentifier; +use ironfish::transaction::unsigned::UnsignedTransaction; use ironfish::transaction::{ batch_verify_transactions, TransactionVersion, TRANSACTION_EXPIRATION_SIZE, TRANSACTION_FEE_SIZE, TRANSACTION_PUBLIC_KEY_SIZE, TRANSACTION_SIGNATURE_SIZE, @@ -371,3 +372,28 @@ pub fn verify_transactions(serialized_transactions: Vec) -> Result Result { + let bytes = js_bytes.into_value()?; + + let transaction = UnsignedTransaction::read(bytes.as_ref()).map_err(to_napi_err)?; + + Ok(NativeUnsignedTransaction { transaction }) + } + + #[napi] + pub fn serialize(&self) -> Result { + let mut vec: Vec = vec![]; + self.transaction.write(&mut vec).map_err(to_napi_err)?; + + Ok(Buffer::from(vec)) + } +} diff --git a/ironfish-rust-nodejs/tests/unsigned.test.slow.ts b/ironfish-rust-nodejs/tests/unsigned.test.slow.ts new file mode 100644 index 0000000000..59f4827b20 --- /dev/null +++ b/ironfish-rust-nodejs/tests/unsigned.test.slow.ts @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import { UnsignedTransaction } from ".." +import { Asset, Transaction, generateKey } from ".." + +describe('UnsignedTransaction', () => { + describe('ser/de', () => { + it('can create an unsigned tx and deserialize it', () => { + const key = generateKey() + const asset = new Asset(key.publicAddress, 'testcoin', '') + const proposedTx = new Transaction(2) + proposedTx.mint(asset, 5n) + const unsignedTxBuffer = proposedTx.build( + key.proofGenerationKey, + key.viewKey, + key.outgoingViewKey, + key.publicAddress, + 0n, + ) + + const unsignedTx = new UnsignedTransaction(unsignedTxBuffer) + expect(unsignedTx.serialize()).toEqual(unsignedTxBuffer) + + }) + }) +})