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

wallet-core: expose staking capabilities via FFI #2956

Merged
merged 1 commit into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 200 additions & 5 deletions wallet-core/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,16 @@ use alloc::vec::Vec;
use core::{ptr, slice};
use dusk_bytes::{DeserializableSlice, Serializable};
use execution_core::signatures::bls::PublicKey as BlsPublicKey;
use execution_core::transfer::data::TransactionData;
use execution_core::transfer::data::{ContractCall, TransactionData};
use execution_core::transfer::moonlight::Transaction as MoonlightTransaction;
use execution_core::transfer::phoenix;
use execution_core::transfer::phoenix::{
ArchivedNoteLeaf, Note, NoteLeaf, NoteOpening, Prove,
PublicKey as PhoenixPublicKey,
};

use execution_core::stake::{Stake, Withdraw as StakeWithdraw, STAKE_CONTRACT};
use execution_core::transfer::withdraw::WithdrawReplayToken;
use execution_core::transfer::Transaction;
use execution_core::BlsScalar;

Expand All @@ -56,6 +58,9 @@ static KEY_SIZE: usize = BlsScalar::SIZE;
#[no_mangle]
static ITEM_SIZE: usize = core::mem::size_of::<ArchivedNoteLeaf>();

#[no_mangle]
static MINIMUM_STAKE: u64 = execution_core::stake::MINIMUM_STAKE;

/// The size of the scratch buffer used for parsing the notes.
const NOTES_BUFFER_SIZE: usize = 96 * 1024;

Expand Down Expand Up @@ -434,7 +439,7 @@ pub unsafe fn phoenix(
pub unsafe fn moonlight(
seed: &Seed,
sender_index: u8,
receiver: &[u8; BlsPublicKey::SIZE],
receiver: *const [u8; BlsPublicKey::SIZE],
transfer_value: *const u64,
deposit: *const u64,
gas_limit: *const u64,
Expand All @@ -447,8 +452,14 @@ pub unsafe fn moonlight(
) -> ErrorCode {
let sender_sk = derive_bls_sk(&seed, sender_index);

let receiver_pk = BlsPublicKey::from_bytes(receiver)
.or(Err(ErrorCode::DeserializationError))?;
let receiver_pk = if receiver.is_null() {
None
} else {
Some(
BlsPublicKey::from_bytes(&*receiver)
.or(Err(ErrorCode::DeserializationError))?,
)
};

let data: Option<TransactionData> = if data.is_null() {
None
Expand All @@ -460,7 +471,7 @@ pub unsafe fn moonlight(

let tx = MoonlightTransaction::new(
&sender_sk,
Some(receiver_pk),
receiver_pk,
*transfer_value,
*deposit,
*gas_limit,
Expand Down Expand Up @@ -619,3 +630,187 @@ pub unsafe fn moonlight_to_phoenix(

ErrorCode::Ok
}

#[no_mangle]
pub unsafe fn moonlight_stake(
seed: &Seed,
sender_index: u8,
stake_value: *const u64,
gas_limit: *const u64,
gas_price: *const u64,
nonce: *const u64,
moCello marked this conversation as resolved.
Show resolved Hide resolved
chain_id: u8,
stake_nonce: *const u64,
tx_ptr: *mut *mut u8,
hash_ptr: &mut [u8; 64],
) -> ErrorCode {
let transfer_value = 0;
let deposit = *stake_value;

let sender_sk = derive_bls_sk(&seed, sender_index);
let stake_sk = sender_sk.clone();

let stake = Stake::new(&stake_sk, *stake_value, *stake_nonce, chain_id);

let contract_call = ContractCall::new(STAKE_CONTRACT, "stake", &stake)
.or(Err(ErrorCode::ContractCallError))?;

let tx = crate::transaction::moonlight(
&sender_sk,
None,
transfer_value,
deposit,
*gas_limit,
*gas_price,
*nonce,
chain_id,
Some(contract_call),
)
.or(Err(ErrorCode::MoonlightTransactionError))?;

let bytes = tx.to_var_bytes();
let len = bytes.len().to_le_bytes();

let ptr = mem::malloc(4 + bytes.len() as u32);
let ptr = ptr as *mut u8;

*tx_ptr = ptr;

ptr::copy_nonoverlapping(len.as_ptr(), ptr, 4);
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr.add(4), bytes.len());

let displayed = revert(&tx.hash());
let bytes = displayed.as_bytes();

ptr::copy_nonoverlapping(bytes.as_ptr(), hash_ptr.as_mut_ptr(), 64);

ErrorCode::Ok
ZER0 marked this conversation as resolved.
Show resolved Hide resolved
}

#[no_mangle]
pub unsafe fn moonlight_unstake(
rng: &[u8; 32],
seed: &Seed,
sender_index: u8,
unstake_value: *const u64,
gas_limit: *const u64,
gas_price: *const u64,
nonce: *const u64,
chain_id: u8,
tx_ptr: *mut *mut u8,
hash_ptr: &mut [u8; 64],
) -> ErrorCode {
let mut rng = ChaCha12Rng::from_seed(*rng);

let sender_sk = derive_bls_sk(&seed, sender_index);
let stake_sk = sender_sk.clone();

let transfer_value = 0;
let deposit = 0;

let gas_payment_token = WithdrawReplayToken::Moonlight(*nonce);

let contract_call = crate::transaction::unstake_to_moonlight(
&mut rng,
&sender_sk,
&stake_sk,
gas_payment_token,
*unstake_value,
)
.or(Err(ErrorCode::ContractCallError))?;

let tx = crate::transaction::moonlight(
&sender_sk,
None,
transfer_value,
deposit,
*gas_limit,
*gas_price,
*nonce,
chain_id,
Some(contract_call),
)
.or(Err(ErrorCode::MoonlightTransactionError))?;

let bytes = tx.to_var_bytes();
let len = bytes.len().to_le_bytes();

let ptr = mem::malloc(4 + bytes.len() as u32);
let ptr = ptr as *mut u8;

*tx_ptr = ptr;

ptr::copy_nonoverlapping(len.as_ptr(), ptr, 4);
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr.add(4), bytes.len());

let displayed = revert(&tx.hash());
let bytes = displayed.as_bytes();

ptr::copy_nonoverlapping(bytes.as_ptr(), hash_ptr.as_mut_ptr(), 64);

ErrorCode::Ok
}

#[no_mangle]
pub unsafe fn moonlight_stake_reward(
rng: &[u8; 32],
seed: &Seed,
sender_index: u8,
reward_amount: *const u64,
gas_limit: *const u64,
gas_price: *const u64,
nonce: *const u64,
chain_id: u8,
tx_ptr: *mut *mut u8,
hash_ptr: &mut [u8; 64],
) -> ErrorCode {
let mut rng = ChaCha12Rng::from_seed(*rng);

let sender_sk = derive_bls_sk(&seed, sender_index);
let stake_sk = sender_sk.clone();

let transfer_value = 0;
let deposit = 0;

let gas_payment_token = WithdrawReplayToken::Moonlight(*nonce);

let contract_call = crate::transaction::stake_reward_to_moonlight(
&mut rng,
&sender_sk,
&stake_sk,
gas_payment_token,
*reward_amount,
)
.or(Err(ErrorCode::ContractCallError))?;

let tx = crate::transaction::moonlight(
&sender_sk,
None,
transfer_value,
deposit,
*gas_limit,
*gas_price,
*nonce,
chain_id,
Some(contract_call),
)
.or(Err(ErrorCode::MoonlightTransactionError))?;

let bytes = tx.to_var_bytes();
let len = bytes.len().to_le_bytes();

let ptr = mem::malloc(4 + bytes.len() as u32);
let ptr = ptr as *mut u8;

*tx_ptr = ptr;

ptr::copy_nonoverlapping(len.as_ptr(), ptr, 4);
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr.add(4), bytes.len());

let displayed = revert(&tx.hash());
let bytes = displayed.as_bytes();

ptr::copy_nonoverlapping(bytes.as_ptr(), hash_ptr.as_mut_ptr(), 64);

ErrorCode::Ok
}
2 changes: 2 additions & 0 deletions wallet-core/src/ffi/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub enum ErrorCode {
PhoenixTransactionError = 252,
// Moonlight Transaction error
MoonlightTransactionError = 251,
// Contract Call Error
ContractCallError = 250,
// Success
Ok = 0,
}
Expand Down
4 changes: 2 additions & 2 deletions wallet-core/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ fn stake_reward_to_phoenix<R: RngCore + CryptoRng>(
ContractCall::new(STAKE_CONTRACT, "withdraw", &reward_withdraw)
}

fn stake_reward_to_moonlight<R: RngCore + CryptoRng>(
pub(crate) fn stake_reward_to_moonlight<R: RngCore + CryptoRng>(
rng: &mut R,
moonlight_receiver_sk: &BlsSecretKey,
stake_sk: &BlsSecretKey,
Expand Down Expand Up @@ -763,7 +763,7 @@ fn unstake_to_phoenix<R: RngCore + CryptoRng>(
ContractCall::new(STAKE_CONTRACT, "unstake", &unstake)
}

fn unstake_to_moonlight<R: RngCore + CryptoRng>(
pub(crate) fn unstake_to_moonlight<R: RngCore + CryptoRng>(
rng: &mut R,
moonlight_receiver_sk: &BlsSecretKey,
stake_sk: &BlsSecretKey,
Expand Down
Loading