Skip to content

Commit aabe361

Browse files
authored
Code cleanup and fixes (#300)
* remove cpp warning * code clean app * bump version * bug fix: call_sender_principal matches the device_principal * fix spelling errors
1 parent b1c4a91 commit aabe361

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+333
-348
lines changed

CMakeLists.txt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
#* See the License for the specific language governing permissions and
1414
#* limitations under the License.
1515
#********************************************************************************
16-
cmake_minimum_required(VERSION 3.0)
16+
cmake_minimum_required(VERSION 3.28)
1717
include("cmake/HunterGate.cmake")
1818
HunterGate(
19-
URL "https://github.com/cpp-pm/hunter/archive/v0.25.5.tar.gz"
20-
SHA1 "a20151e4c0740ee7d0f9994476856d813cdead29"
19+
URL "https://github.com/cpp-pm/hunter/archive/v0.26.1.tar.gz"
20+
SHA1 "e41ac7a18c49b35ebac99ff2b5244317b2638a65"
2121
LOCAL
2222
)
2323

@@ -42,8 +42,16 @@ add_definitions(-DAPP_STANDARD)
4242

4343
hunter_add_package(fmt)
4444
find_package(fmt CONFIG REQUIRED)
45-
hunter_add_package(jsoncpp)
46-
find_package(jsoncpp CONFIG REQUIRED)
45+
46+
# Use FetchContent to get nlohmann_json 3.12.0 since Hunter doesn't support this version
47+
include(FetchContent)
48+
FetchContent_Declare(
49+
nlohmann_json
50+
URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz
51+
URL_HASH SHA256=42f6e95cad6ec532fd372391373363b62a14af6d771056dbfc86160e6dfff7aa
52+
)
53+
FetchContent_MakeAvailable(nlohmann_json)
54+
4755
hunter_add_package(GTest)
4856
find_package(GTest CONFIG REQUIRED)
4957

@@ -165,7 +173,7 @@ target_link_libraries(unittests PRIVATE
165173
GTest::gtest_main
166174
app_lib
167175
fmt::fmt
168-
JsonCpp::JsonCpp)
176+
nlohmann_json::nlohmann_json)
169177

170178
add_compile_definitions(TESTVECTORS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/tests/")
171179
add_test(NAME unittests COMMAND unittests)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ cd zemu
156156
yarn test -t 'test name'
157157
```
158158

159-
This will run just the test maching the name provided
159+
This will run just the test matching the name provided
160160

161161
## How to debug a ledger app?
162162

@@ -199,7 +199,7 @@ There are a few things to take into account when enabling Ledger App debugging:
199199

200200
3. Launch the emulator in debug mode
201201

202-
> If you didnt install Zemu yet (previous section), then run `make zemu_install`
202+
> If you did not install Zemu yet (previous section), then run `make zemu_install`
203203

204204
```sh
205205
make zemu_debug

app/Makefile.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ APPVERSION_M=4
33
# This is the minor version of this release
44
APPVERSION_N=0
55
# This is the patch version of this release
6-
APPVERSION_P=9
6+
APPVERSION_P=10

app/rust/src/constants.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,6 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
********************************************************************************/
16-
17-
pub const MAX_PAGES: usize = 9;
18-
// Configuration constants based on target device
19-
// means max number of lines per page
20-
pub const MAX_LINES: usize = 3;
21-
// means max characteres per line
22-
// this is a limit of the device
23-
// intended to control the already formatted
24-
// message response comming
25-
// from canisters
26-
pub const MAX_CHARS_PER_LINE: usize = 35;
27-
2816
pub const BLS_PUBLIC_KEY_SIZE: usize = 96;
2917
pub const BLS_SIGNATURE_SIZE: usize = 48;
3018
pub const REPLY_PATH: &str = "reply";
@@ -33,8 +21,6 @@ pub const CANISTER_RANGES_PATH: &str = "canister_ranges";
3321
pub const CBOR_TAG: u64 = 55799;
3422
pub const BIG_NUM_TAG: u64 = 2;
3523
pub const CBOR_CERTIFICATE_TAG: u64 = CBOR_TAG;
36-
pub const CALL_REQUEST_TAG: u64 = CBOR_TAG;
37-
pub const CONSENT_MSG_REQUEST_TAG: u64 = CBOR_TAG;
3824
pub const CANISTER_RANGES_TAG: u64 = CBOR_TAG;
3925
pub const CANISTER_CALL_TAG: u64 = CBOR_TAG;
4026

@@ -43,17 +29,12 @@ pub const PRINCIPAL_MAX_LEN: usize = 29;
4329
pub const SENDER_MAX_LEN: usize = 32; // Principal is bech32(29 bytes + 4 bytes for CRC)
4430
pub const ARG_HASH_LEN: usize = 32;
4531
pub const CANISTER_MAX_LEN: usize = 10;
46-
pub const REQUEST_MAX_LEN: usize = 10;
4732
pub const METHOD_MAX_LEN: usize = 20;
48-
pub const NONCE_MAX_LEN: usize = 32;
4933
pub const SECONDS_PER_MINUTE: u64 = 60;
5034
pub const NANOSECONDS_PER_SECOND: u64 = 1_000_000_000;
5135
// The max offset between the certificate.time and the call message request ingress_expiry
5236
// otherwise, call request must be considered invalid/outdated and not processed at all
5337
pub const MAX_CERT_INGRESS_OFFSET: u64 = 15 * SECONDS_PER_MINUTE * NANOSECONDS_PER_SECOND;
54-
// The official root key for consent message verification
55-
// including certificate, provided by the ICP team
56-
pub const CANISTER_ROOT_KEY: &str = "814c0e6ec71fab583b08bd81373c255c3c371b2e84863c98a4f1e08b74235d14fb5d9c0cd546d9685f913a0c0b2cc5341583bf4b4392e467db96d65b9bb4cb717112f8472e0d5a4d14505ffd7484b01291091c5f87b98883463f98091a0baaae";
5738

5839
// Provided in testing data
5940
// indicating sender in there is the default one, whose value is 0x04

app/rust/src/ffi/c_api.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{constants::PRINCIPAL_MAX_LEN, Principal};
1+
use crate::{constants::PRINCIPAL_MAX_LEN, error::ParserError, Principal};
22

33
#[cfg(not(test))]
44
extern "C" {
@@ -27,15 +27,29 @@ fn c_fill_principal(output: *mut u8, output_len: u16, response_len: *mut u16) ->
2727
}
2828
}
2929

30-
// Get device principal, this is safe to use
31-
// because we ensure proper buffer sizes is passed to C
32-
pub fn device_principal() -> Principal {
30+
// Get device principal with proper error handling
31+
pub fn device_principal() -> Result<Principal, ParserError> {
3332
let mut data = [0u8; PRINCIPAL_MAX_LEN];
34-
let mut response_len = 0;
33+
let mut response_len = 0u16;
3534

36-
unsafe {
37-
c_fill_principal(data.as_mut_ptr(), data.len() as _, &mut response_len);
35+
let buffer_len = data.len();
36+
if buffer_len > u16::MAX as usize {
37+
return Err(ParserError::UnexpectedError);
3838
}
39-
40-
Principal::new(&data[..response_len as usize]).unwrap()
39+
let rc = unsafe { c_fill_principal(data.as_mut_ptr(), buffer_len as u16, &mut response_len) };
40+
41+
// Check return code for success
42+
if rc != 0 {
43+
return Err(ParserError::UnexpectedError);
44+
}
45+
46+
// Validate response_len is within valid range (1..=PRINCIPAL_MAX_LEN)
47+
let response_len_usize = response_len as usize;
48+
if response_len_usize == 0 || response_len_usize > PRINCIPAL_MAX_LEN {
49+
return Err(ParserError::UnexpectedBufferEnd);
50+
}
51+
52+
// Use Principal::new and propagate any error
53+
Principal::new(&data[..response_len_usize])
54+
.map_err(|_| ParserError::UnexpectedValue)
4155
}

app/rust/src/ffi/call_request.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
use core::mem::{size_of, MaybeUninit};
2323
use sha2::{Digest, Sha256};
2424

25-
use super::resources::MEMORY_CALL_REQUEST;
25+
use super::resources::get_call_request_memory;
2626

2727
#[repr(C)]
2828
#[derive(PartialEq, Default)]
@@ -166,12 +166,23 @@ fn fill_request(request: &CallRequest<'_>) -> Result<(), ParserError> {
166166
// Update our consent request
167167
call_request.fill_from(request)?;
168168

169-
MEMORY_CALL_REQUEST
170-
.write(0, &serialized)
169+
super::resources::write_call_request(&serialized)
171170
.map_err(|_| ParserError::UnexpectedError)?;
172171

173-
let consent2 = CanisterCallT::from_bytes(&**MEMORY_CALL_REQUEST)?;
174-
consent2.validate()?;
172+
// Verify the write succeeded by reading back and validating
173+
// Use a safe copy to avoid potential alignment issues
174+
let stored_memory = super::resources::get_call_request_memory();
175+
if stored_memory.len() != core::mem::size_of::<CanisterCallT>() {
176+
return Err(ParserError::UnexpectedBufferEnd);
177+
}
178+
179+
let mut stored_call = CanisterCallT::default();
180+
core::ptr::copy_nonoverlapping(
181+
stored_memory.as_ptr(),
182+
&mut stored_call as *mut CanisterCallT as *mut u8,
183+
core::mem::size_of::<CanisterCallT>(),
184+
);
185+
stored_call.validate()?;
175186
}
176187

177188
Ok(())
@@ -181,7 +192,7 @@ fn fill_request(request: &CallRequest<'_>) -> Result<(), ParserError> {
181192
pub unsafe extern "C" fn rs_get_signing_hash(data: *mut [u8; 32]) {
182193
let hash = unsafe { &mut *data };
183194

184-
let Ok(call) = CanisterCallT::from_bytes(&**MEMORY_CALL_REQUEST) else {
195+
let Ok(call) = CanisterCallT::from_bytes(get_call_request_memory()) else {
185196
return;
186197
};
187198

app/rust/src/ffi/consent_request.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::{
2525

2626
use core::mem::{size_of, MaybeUninit};
2727

28-
use super::resources::MEMORY_CONSENT_REQUEST;
28+
use super::resources::get_consent_request_memory;
2929

3030
#[repr(C)]
3131
#[derive(PartialEq, Default)]
@@ -188,19 +188,18 @@ fn fill_request(request: &ConsentMsgRequest<'_>) -> Result<(), ParserError> {
188188
let mut serialized = [0; core::mem::size_of::<ConsentRequestT>()];
189189
unsafe {
190190
{
191-
// Lets transmute the array in order to re-use serialized memory
191+
// Lets transmute the array in order to reuse serialized memory
192192
// saving a bunch of stack
193193
let consent_request = &mut *(serialized.as_mut_ptr() as *mut ConsentRequestT);
194194

195195
// Update our consent request
196196
consent_request.fill_from(request)?;
197197

198-
MEMORY_CONSENT_REQUEST
199-
.write(0, &serialized)
198+
super::resources::write_consent_request(&serialized)
200199
.map_err(|_| ParserError::UnexpectedError)?;
201200
}
202201

203-
let consent2 = ConsentRequestT::from_bytes(&**MEMORY_CONSENT_REQUEST)?;
202+
let consent2 = ConsentRequestT::from_bytes(get_consent_request_memory())?;
204203
consent2.validate()?;
205204
}
206205

app/rust/src/ffi/resources.rs

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
#![allow(static_mut_refs)]
2+
3+
use core::ptr::{addr_of_mut, addr_of};
14
use bolos::{lazy_static, pic::PIC};
25

36
use crate::{consent_message::msg_info::ConsentInfo, Certificate};
47

58
use super::{call_request::CanisterCallT, consent_request::ConsentRequestT};
69

7-
// NOTE: The call_request anc consent_request were initially defined as Optionals, identical to the
10+
// NOTE: The call_request and consent_request were initially defined as Optionals, identical to the
811
// certificate. But this approach consumes stacks, so we move it to flash, saving us 244 bytes of
912
// stack, unfortunately, this did not help.
1013
// it is better to keep them as optionals, but we can change it back overtime.
@@ -20,11 +23,79 @@ pub static mut CERTIFICATE: Option<Certificate<'static>> = None;
2023
#[lazy_static]
2124
pub static mut UI: Option<ConsentInfo<'static>> = None;
2225

26+
// Safe wrapper functions for static access
27+
pub(crate) unsafe fn clear_consent_request() {
28+
let ptr = addr_of_mut!(MEMORY_CONSENT_REQUEST);
29+
_ = (*ptr).write(0, &[0; core::mem::size_of::<ConsentRequestT>()]);
30+
}
31+
32+
pub(crate) unsafe fn clear_call_request() {
33+
let ptr = addr_of_mut!(MEMORY_CALL_REQUEST);
34+
_ = (*ptr).write(0, &[0; core::mem::size_of::<CanisterCallT>()]);
35+
}
36+
37+
pub(crate) unsafe fn write_call_request(data: &[u8]) -> Result<(), ()> {
38+
let ptr = addr_of_mut!(MEMORY_CALL_REQUEST);
39+
(*ptr).write(0, data).map_err(|_| ())
40+
}
41+
42+
pub(crate) unsafe fn get_call_request_memory(
43+
) -> &'static [u8; core::mem::size_of::<CanisterCallT>()] {
44+
let ptr = addr_of!(MEMORY_CALL_REQUEST);
45+
&*ptr
46+
}
47+
48+
pub(crate) unsafe fn write_consent_request(data: &[u8]) -> Result<(), ()> {
49+
let ptr = addr_of_mut!(MEMORY_CONSENT_REQUEST);
50+
(*ptr).write(0, data).map_err(|_| ())
51+
}
52+
53+
pub(crate) unsafe fn get_consent_request_memory(
54+
) -> &'static [u8; core::mem::size_of::<ConsentRequestT>()] {
55+
let ptr = addr_of!(MEMORY_CONSENT_REQUEST);
56+
&*ptr
57+
}
58+
59+
pub(crate) unsafe fn get_ui() -> Option<&'static ConsentInfo<'static>> {
60+
let ptr = addr_of!(UI);
61+
(*ptr).as_ref()
62+
}
63+
64+
pub(crate) unsafe fn set_ui(ui: ConsentInfo<'static>) {
65+
let ptr = addr_of_mut!(UI);
66+
(*ptr).replace(ui);
67+
}
68+
69+
pub(crate) unsafe fn take_ui() -> Option<ConsentInfo<'static>> {
70+
let ptr = addr_of_mut!(UI);
71+
(*ptr).take()
72+
}
73+
74+
pub(crate) unsafe fn set_certificate(cert: Certificate<'static>) {
75+
let ptr = addr_of_mut!(CERTIFICATE);
76+
(*ptr).replace(cert);
77+
}
78+
79+
pub(crate) unsafe fn take_certificate() -> Option<Certificate<'static>> {
80+
let ptr = addr_of_mut!(CERTIFICATE);
81+
(*ptr).take()
82+
}
83+
84+
pub(crate) unsafe fn certificate_is_some() -> bool {
85+
let ptr = addr_of!(CERTIFICATE);
86+
(*ptr).is_some()
87+
}
88+
89+
pub(crate) unsafe fn ui_is_some() -> bool {
90+
let ptr = addr_of!(UI);
91+
(*ptr).is_some()
92+
}
93+
2394
#[no_mangle]
2495
pub unsafe extern "C" fn rs_clear_resources() {
2596
// zeroize data
26-
_ = MEMORY_CONSENT_REQUEST.write(0, &[0; core::mem::size_of::<ConsentRequestT>()]);
27-
_ = MEMORY_CALL_REQUEST.write(0, &[0; core::mem::size_of::<CanisterCallT>()]);
28-
CERTIFICATE.take();
29-
UI.take();
97+
clear_consent_request();
98+
clear_call_request();
99+
take_certificate();
100+
take_ui();
30101
}

app/rust/src/ffi/ui.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@
1616

1717
use crate::{error::ParserError, DisplayableItem};
1818

19-
use super::resources::UI;
19+
use super::resources::{get_ui, ui_is_some};
2020

2121
#[no_mangle]
2222
pub unsafe extern "C" fn rs_getNumItems(num_items: *mut u8) -> u32 {
23-
if num_items.is_null() || !UI.is_some() {
23+
if num_items.is_null() || !ui_is_some() {
2424
return ParserError::ContextMismatch as u32;
2525
}
2626

2727
// Safe to unwrap due to previous check
28-
let ui = UI.as_ref().unwrap();
28+
let ui = get_ui().unwrap();
2929

3030
let Ok(num) = ui.num_items() else {
3131
return ParserError::NoData as _;
@@ -51,12 +51,12 @@ pub unsafe extern "C" fn rs_getItem(
5151
let key = core::slice::from_raw_parts_mut(out_key as *mut u8, key_len as usize);
5252
let value = core::slice::from_raw_parts_mut(out_value as *mut u8, out_len as usize);
5353

54-
if !UI.is_some() {
54+
if !ui_is_some() {
5555
return ParserError::ContextMismatch as _;
5656
}
5757

5858
// Safe to unwrap due to previous check
59-
let ui = UI.as_ref().unwrap();
59+
let ui = get_ui().unwrap();
6060

6161
match ui.render_item(display_idx, key, value, page_idx) {
6262
Ok(page) => {
@@ -77,12 +77,12 @@ pub unsafe extern "C" fn rs_get_intent(out_intent: *mut i8, intent_len: u16) ->
7777
let out_slice = core::slice::from_raw_parts_mut(out_intent as *mut u8, intent_len as usize);
7878
out_slice[0] = 0;
7979

80-
if !UI.is_some() {
80+
if !ui_is_some() {
8181
return ParserError::ContextMismatch as u32;
8282
}
8383

8484
// Safe to unwrap due to previous check
85-
let ui = UI.as_ref().unwrap();
85+
let ui = get_ui().unwrap();
8686

8787
// Access the intent using the public method
8888
if let Some(intent) = ui.message.get_intent() {

0 commit comments

Comments
 (0)