From 5fa3d45d05af3d8e00f6494ff76eb8cd47525d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Palmer?= Date: Sat, 16 Mar 2024 22:19:07 +0100 Subject: [PATCH 1/2] Bagl: use standard app ui flow Instead of the ux_variable_display hack to display a dynamic number of screens --- src/globals.h | 44 +------ src/to_string.c | 2 - src/to_string.h | 2 + src/types.h | 17 --- src/ui.h | 42 +++--- src/ui_bagl.c | 271 ++++++--------------------------------- src/ui_delegation_bagl.c | 38 ++++-- src/ui_delegation_nbgl.c | 4 + src/ui_pubkey_bagl.c | 45 ++++--- src/ui_reset_bagl.c | 28 +++- src/ui_setup_bagl.c | 58 +++++++-- 11 files changed, 199 insertions(+), 352 deletions(-) diff --git a/src/globals.h b/src/globals.h index 0a8da867..33628a62 100644 --- a/src/globals.h +++ b/src/globals.h @@ -38,7 +38,7 @@ void clear_apdu_globals(void); /** - * @brief string_generation_callback for chains + * @brief Converts a chain id to string * * @param out: output buffer * @param out_size: output size @@ -47,7 +47,9 @@ void clear_apdu_globals(void); void copy_chain(char *out, size_t out_size, chain_id_t *chain_id); /** - * @brief string_generation_callback for keys + * @brief Converts a baking key to string + * + * if the baking is empty, copies "No Key Authorized" in the output * * @param out: output buffer * @param out_size: output size @@ -56,7 +58,7 @@ void copy_chain(char *out, size_t out_size, chain_id_t *chain_id); void copy_key(char *out, size_t out_size, bip32_path_with_curve_t *baking_key); /** - * @brief string_generation_callback for high watermarks + * @brief Converts a high watermark to string * * @param out: output buffer * @param out_size: output size @@ -126,28 +128,6 @@ typedef struct { struct parse_state parse_state; ///< current parser state } apdu_sign_state_t; -/** - * @brief This structure represents data used to compute what we need to display on the screen. - * - */ -struct screen_data { - char *title; ///< title of the screen - string_generation_callback callback_fn; ///< callback to convert the data to string - void *data; ///< value to display on the screen -}; - -/** - * @brief State of the dynamic display - * - * Used to keep track on whether we are displaying screens inside the stack, or outside the - * stack (for example confirmation screens) - * - */ -enum e_state { - STATIC_SCREEN, - DYNAMIC_SCREEN, -}; - /** * @brief This structure holds all structure needed * @@ -155,24 +135,10 @@ enum e_state { typedef struct { /// dynamic display state struct { - struct screen_data screen_stack[MAX_SCREEN_STACK_SIZE]; - enum e_state current_state; ///< State of the dynamic display - - /// Size of the screen stack - uint8_t screen_stack_size; - - /// Current index in the screen_stack. - uint8_t formatter_index; - /// Callback function if user accepted prompt. ui_callback_t ok_callback; /// Callback function if user rejected prompt. ui_callback_t cxl_callback; - - /// Title to be displayed on the screen. - char screen_title[PROMPT_WIDTH + 1u]; - /// Value to be displayed on the screen. - char screen_value[VALUE_WIDTH + 1u]; /// Screensaver is on/off. bool is_blank_screen; } dynamic_display; diff --git a/src/to_string.c b/src/to_string.c index dfb5f959..af1b0979 100644 --- a/src/to_string.c +++ b/src/to_string.c @@ -30,8 +30,6 @@ #define TEZOS_HASH_CHECKSUM_SIZE 4u -#define TICKER_WITH_SPACE " XTZ" - static void pkh_to_string(char *const buff, size_t const buff_size, signature_type_t const signature_type, diff --git a/src/to_string.h b/src/to_string.h index dd0dbee5..6ec26dda 100644 --- a/src/to_string.h +++ b/src/to_string.h @@ -30,6 +30,8 @@ #include "types.h" #include "ui.h" +#define TICKER_WITH_SPACE " XTZ" + /** * @brief Converts a key to a public key hash string using its public key * diff --git a/src/types.h b/src/types.h index af466f58..0a1db19c 100644 --- a/src/types.h +++ b/src/types.h @@ -99,19 +99,6 @@ static chain_id_t const mainnet_chain_id = {.v = 0x7A06A770}; */ typedef bool (*ui_callback_t)(void); -/** - * @brief String generator callback - * - * Uses K&R style declaration to avoid being stuck on const - * void *, to avoid having to cast the function pointers - * - * @param buffer: output buffer - * @param buffer_size: output size - * @param data: data - */ -typedef void (*string_generation_callback)( - /* char *buffer, size_t buffer_size, const void *data */); - /** * @brief Pair of public and private key * @@ -232,10 +219,6 @@ typedef struct { #define PROTOCOL_HASH_BASE58_STRING_SIZE \ sizeof("ProtoBetaBetaBetaBetaBetaBetaBetaBetaBet11111a5ug96") -#define MAX_SCREEN_STACK_SIZE 7u // Maximum number of screens in a flow. -#define PROMPT_WIDTH 16u -#define VALUE_WIDTH PROTOCOL_HASH_BASE58_STRING_SIZE - // TODO: Rename to KEY_HASH_SIZE #define HASH_SIZE 20u diff --git a/src/ui.h b/src/ui.h index 34ef01cd..7e2dffbf 100644 --- a/src/ui.h +++ b/src/ui.h @@ -28,25 +28,6 @@ #include "keys.h" -/** - * @brief Initializes the formatter stack - * - * Must be called once before calling `push_ui_callback()` for the first time - * - */ -void init_screen_stack(void); - -/** - * @brief Pushes a new screen to the flow - * - * Must call `init_screen_stack()` before calling this function for the first time - * - * @param title: title of the screen - * @param cb: callback to generate the string version of the data - * @param data: data to display on the screen - */ -void push_ui_callback(const char *title, string_generation_callback cb, const void *data); - /** * @brief Starts the idle flow * @@ -68,11 +49,30 @@ void exit_app(void); void update_baking_idle_screens(void); /** - * @brief Prepare confirmation screens + * @brief Prepare confirmation screens callbacks * * @param ok_c: accept callback * @param cxl_c: cancel callback */ -void ux_confirm_screen(ui_callback_t ok_c, ui_callback_t cxl_c); +void ux_prepare_confirm_callbacks(ui_callback_t ok_c, ui_callback_t cxl_c); + +/** + * @brief Confirmation flow + * + * - Initial screen + * - Values + * - Reject screen + * - Accept screen + * + */ +extern const ux_flow_step_t ux_eye_step; +extern const ux_flow_step_t ux_prompt_flow_reject_step; +extern const ux_flow_step_t ux_prompt_flow_accept_step; +#define UX_CONFIRM_FLOW(flow_name, ...) \ + UX_FLOW(flow_name, \ + &ux_eye_step, \ + __VA_ARGS__, \ + &ux_prompt_flow_reject_step, \ + &ux_prompt_flow_accept_step) #endif // HAVE_BAGL diff --git a/src/ui_bagl.c b/src/ui_bagl.c index ecd2d102..d0be1cea 100644 --- a/src/ui_bagl.c +++ b/src/ui_bagl.c @@ -37,187 +37,20 @@ #include #include -#define G global.ui - #define G_display global.dynamic_display -void init_screen_stack(void) { - explicit_bzero(&G_display.screen_stack, sizeof(G_display.screen_stack)); - G_display.formatter_index = 0; - G_display.screen_stack_size = 0; - G_display.current_state = STATIC_SCREEN; -} - /** - * @brief Prepare the display + * @brief This structure represents a context needed for home screens navigation * - * @param ok_c: accept callback - * @param cxl_c: cancel callback */ -static void ux_prepare_display(ui_callback_t ok_c, ui_callback_t cxl_c) { - G_display.screen_stack_size = G_display.formatter_index; - G_display.formatter_index = 0; - G_display.current_state = STATIC_SCREEN; +typedef struct { + char chain_id[CHAIN_ID_BASE58_STRING_SIZE]; + char authorized_key[PKH_STRING_SIZE]; + char hwm[MAX_INT_DIGITS + 1u + MAX_INT_DIGITS + 1u]; +} HomeContext_t; - if (ok_c) { - G_display.ok_callback = ok_c; - } - if (cxl_c) { - G_display.cxl_callback = cxl_c; - } -} - -void push_ui_callback(const char *title, string_generation_callback cb, const void *data) { - if ((G_display.formatter_index + 1u) >= MAX_SCREEN_STACK_SIZE) { - THROW(0x6124); - } - struct screen_data *fmt = &G_display.screen_stack[G_display.formatter_index]; - - fmt->title = title; - fmt->callback_fn = cb; - fmt->data = data; - G_display.formatter_index++; - G_display.screen_stack_size++; -} - -/** - * @brief Clear screen related values - * - */ -static void clear_data(void) { - explicit_bzero(&G_display.screen_title, sizeof(G_display.screen_title)); - explicit_bzero(&G_display.screen_value, sizeof(G_display.screen_value)); -} - -/** - * @brief Fills the screen with the data in the `screen_stack` pointed - * by the index `G_display.formatter_index`. Fills the - * `screen_title` by copying the `.title` field and fills the - * `screen_value` by computing `callback_fn` with the `.data` - * field as a parameter - * - */ -static void set_screen_data(void) { - struct screen_data *fmt = &G_display.screen_stack[G_display.formatter_index]; - if (fmt->title == NULL) { - // Avoid seg faulting for bad reasons... - G_display.formatter_index = 0; - fmt = &G_display.screen_stack[0]; - } - clear_data(); - copy_string((char *) G_display.screen_title, sizeof(G_display.screen_title), fmt->title); - fmt->callback_fn(G_display.screen_value, sizeof(G_display.screen_value), fmt->data); -} - -/** - * @brief Enables coherent behavior on bnnn_paging when there are - * multiple screens. - * - */ -static void update_layout(void) { - G_ux.flow_stack[G_ux.stack_count - 1].prev_index = - G_ux.flow_stack[G_ux.stack_count - 1].index - 2; - G_ux.flow_stack[G_ux.stack_count - 1].index--; - ux_flow_relayout(); -} - -/** - * @brief Selects the next screen to display - * - * It allows to navigate through the screens in the order in - * which they were pushed. - * - * The left-hand side shows the first screens pushed, the - * right-hand side the last. - * - * Goes back to standard navigation by leaving the boundaries. - * - * @param is_left_ux_step: if come from the left screen - */ -static void display_next_state(bool is_left_ux_step) { - if (is_left_ux_step) { // We're called from the LEFT ux step - if (G_display.current_state == STATIC_SCREEN) { - // The previous screen was a static screen, so we're now entering the stack (from the - // start of the stack). - - // Since we're in the stack, set the state to DYNAMIC_SCREEN. - G_display.current_state = DYNAMIC_SCREEN; - // We're just entering the stack so the `formatter_index` is set to 0. - G_display.formatter_index = 0; - // Update the screen data. - set_screen_data(); - // Move to the next step, which will display the screen. - ux_flow_next(); - } else { - // The previous screen was NOT a static screen, so we were already in the stack. - if (G_display.formatter_index == 0u) { - // If `formatter_index` is 0 then we need to exit the dynamic display. - - // Update the current_state accordingly. - G_display.current_state = STATIC_SCREEN; - // Don't need to update the screen data, simply display the ux_flow_prev() which - // will be a static screen. - ux_flow_prev(); - } else { - // The user is still browsing the stack: simply decrement `formatter_index` and - // update `screen_data`. - G_display.formatter_index--; - set_screen_data(); - ux_flow_next(); - } - } - } else { - // We're called from the RIGHT ux step. - if (G_display.current_state == STATIC_SCREEN) { - // We're called from a static screen, so we're now entering the stack (from the end of - // the stack). - - // Update the current_state. - G_display.current_state = DYNAMIC_SCREEN; - // We're starting the stack from the end, so the index is the size - 1. - G_display.formatter_index = G_display.screen_stack_size - 1u; - // Update the screen data. - set_screen_data(); - // Since we're called from the RIGHT ux step, if we wish to display - // the data we need to call ux_flow_PREV and not `ux_flow_NEXT`. - ux_flow_prev(); - } else { - // We're being called from a dynamic screen, so the user was already browsing the stack. - // The user wants to go to the next screen so increment the index. - G_display.formatter_index++; - if (G_display.formatter_index == G_display.screen_stack_size) { - // Index is equal to stack size, so time to exit the stack and display the static - // screens. - - // Make sure we update the state accordingly. - G_display.current_state = STATIC_SCREEN; - ux_flow_next(); - } else { - // We're just browsing the stack so update the screen and display it. - set_screen_data(); - // Similar to `ux_flow_prev()` but updates layout to account for `bnnn_paging`'s - // weird behaviour. - update_layout(); - } - } - } -} - -/** - * @brief Generic way to display screens - * - * The border helps to stay in the variable_display page - * See `display_next_state(is_left_ux_step)` - * - */ -UX_STEP_INIT(ux_init_upper_border, NULL, NULL, { display_next_state(true); }); -UX_STEP_NOCB(ux_variable_display, - bnnn_paging, - (const ux_layout_bnnn_paging_params_t){ - .title = G_display.screen_title, - .text = G_display.screen_value, - }); -UX_STEP_INIT(ux_init_lower_border, NULL, NULL, { display_next_state(false); }); +/// Current home context +static HomeContext_t home_context; /** * @brief Idle flow @@ -230,39 +63,34 @@ UX_STEP_INIT(ux_init_lower_border, NULL, NULL, { display_next_state(false); }); * - Exit screen * */ -UX_STEP_CB(ux_app_is_ready_step, - nn, - ux_empty_screen(), - { - "Application", - "is ready", - }); -UX_STEP_CB(ux_idle_quit_step, - pb, - exit_app(), - { - &C_icon_dashboard_x, - "Quit", - }); +UX_STEP_CB(ux_app_is_ready_step, nn, ux_empty_screen(), {"Application", "is ready"}); +UX_STEP_NOCB(ux_version_step, bnnn_paging, {"Tezos Baking", VERSION}); +UX_STEP_NOCB(ux_chain_id_step, bnnn_paging, {"Chain", home_context.chain_id}); +UX_STEP_NOCB(ux_authorized_key_step, bnnn_paging, {"Public Key Hash", home_context.authorized_key}); +UX_STEP_NOCB(ux_hwm_step, bnnn_paging, {"High Watermark", home_context.hwm}); +UX_STEP_CB(ux_idle_quit_step, pb, exit_app(), {&C_icon_dashboard_x, "Quit"}); + UX_FLOW(ux_idle_flow, &ux_app_is_ready_step, - - &ux_init_upper_border, - &ux_variable_display, - &ux_init_lower_border, - + &ux_version_step, + &ux_chain_id_step, + &ux_authorized_key_step, + &ux_hwm_step, &ux_idle_quit_step, FLOW_LOOP); /** - * @brief Pushes the baking screens + * @brief Calculates baking values for the idle screens * */ static void calculate_baking_idle_screens_data(void) { - push_ui_callback("Tezos Baking", copy_string, VERSION); - push_ui_callback("Chain", copy_chain, &N_data.main_chain_id); - push_ui_callback("Public Key Hash", copy_key, &N_data.baking_key); - push_ui_callback("High Watermark", copy_hwm, &N_data.hwm.main); + memset(&home_context, 0, sizeof(home_context)); + + copy_chain(home_context.chain_id, sizeof(home_context.chain_id), &N_data.main_chain_id); + + copy_key(home_context.authorized_key, sizeof(home_context.authorized_key), &N_data.baking_key); + + copy_hwm(home_context.hwm, sizeof(home_context.hwm), &N_data.hwm.main); } void ui_initial_screen(void) { @@ -271,65 +99,42 @@ void ui_initial_screen(void) { ux_stack_push(); } - init_screen_stack(); calculate_baking_idle_screens_data(); - ux_prepare_display(NULL, NULL); ux_flow_init(0, ux_idle_flow, NULL); } void update_baking_idle_screens(void) { - init_screen_stack(); calculate_baking_idle_screens_data(); /// refresh ux_stack_display(0); } +void ux_prepare_confirm_callbacks(ui_callback_t ok_c, ui_callback_t cxl_c) { + if (ok_c) { + G_display.ok_callback = ok_c; + } + if (cxl_c) { + G_display.cxl_callback = cxl_c; + } +} + /** * @brief Callback called on accept or cancel * * @param accepted: true if accepted, false if cancelled */ static void prompt_response(bool const accepted) { - ui_initial_screen(); if (accepted) { G_display.ok_callback(); } else { G_display.cxl_callback(); } + ui_initial_screen(); } -/** - * @brief Confirmation flow - * - * - Initial screen - * - Values - * - Reject screen - * - Accept screen - * - */ UX_STEP_CB(ux_prompt_flow_reject_step, pb, prompt_response(false), {&C_icon_crossmark, "Reject"}); UX_STEP_CB(ux_prompt_flow_accept_step, pb, prompt_response(true), {&C_icon_validate_14, "Accept"}); -UX_STEP_NOCB(ux_eye_step, - nn, - { - "Review", - "Request", - }); -UX_FLOW(ux_confirm_flow, - &ux_eye_step, - - &ux_init_upper_border, - &ux_variable_display, - &ux_init_lower_border, - - &ux_prompt_flow_reject_step, - &ux_prompt_flow_accept_step); - -void ux_confirm_screen(ui_callback_t ok_c, ui_callback_t cxl_c) { - ux_prepare_display(ok_c, cxl_c); - ux_flow_init(0, ux_confirm_flow, NULL); - THROW(ASYNC_EXCEPTION); -} +UX_STEP_NOCB(ux_eye_step, nn, {"Review", "Request"}); #endif // HAVE_BAGL diff --git a/src/ui_delegation_bagl.c b/src/ui_delegation_bagl.c index a04c8850..00c6d905 100644 --- a/src/ui_delegation_bagl.c +++ b/src/ui_delegation_bagl.c @@ -37,23 +37,41 @@ #define G global.apdu.u.sign -#define PARSE_ERROR() THROW(EXC_PARSE_ERROR) +/** + * @brief This structure represents a context needed for delegation screens navigation + * + */ +typedef struct { + char address[PKH_STRING_SIZE]; + char fee[MAX_INT_DIGITS + sizeof(TICKER_WITH_SPACE) + 1u]; +} DelegationContext_t; -#define B2B_BLOCKBYTES 128 +/// Current delegation context +static DelegationContext_t delegation_context; -__attribute__((noreturn)) void prompt_delegation(ui_callback_t const ok_cb, - ui_callback_t const cxl_cb) { +UX_STEP_NOCB(ux_register_step, bnnn_paging, {"Register", "as delegate?"}); +UX_STEP_NOCB(ux_delegate_step, bnnn_paging, {"Address", delegation_context.address}); +UX_STEP_NOCB(ux_fee_step, bnnn_paging, {"Fee", delegation_context.fee}); + +UX_CONFIRM_FLOW(ux_delegation_flow, &ux_register_step, &ux_delegate_step, &ux_fee_step); + +void prompt_delegation(ui_callback_t const ok_cb, ui_callback_t const cxl_cb) { if (!G.maybe_ops.is_valid) { THROW(EXC_MEMORY_ERROR); } - init_screen_stack(); - push_ui_callback("Register", copy_string, "as delegate?"); - push_ui_callback("Address", bip32_path_with_curve_to_pkh_string, &global.path_with_curve); - push_ui_callback("Fee", microtez_to_string_indirect, &G.maybe_ops.v.total_fee); + memset(&delegation_context, 0, sizeof(delegation_context)); + + bip32_path_with_curve_to_pkh_string(delegation_context.address, + sizeof(delegation_context.address), + &global.path_with_curve); + + microtez_to_string_indirect(delegation_context.fee, + sizeof(delegation_context.fee), + &G.maybe_ops.v.total_fee); - ux_confirm_screen(ok_cb, cxl_cb); - __builtin_unreachable(); + ux_prepare_confirm_callbacks(ok_cb, cxl_cb); + ux_flow_init(0, ux_delegation_flow, NULL); } #endif // HAVE_BAGL diff --git a/src/ui_delegation_nbgl.c b/src/ui_delegation_nbgl.c index a82d89ca..89262d6e 100644 --- a/src/ui_delegation_nbgl.c +++ b/src/ui_delegation_nbgl.c @@ -41,6 +41,10 @@ #define PARSE_ERROR() THROW(EXC_PARSE_ERROR) +/** + * @brief This structure represents a context needed for delegation screens navigation + * + */ typedef struct { ui_callback_t ok_cb; /// accept callback ui_callback_t cxl_cb; /// cancel callback diff --git a/src/ui_pubkey_bagl.c b/src/ui_pubkey_bagl.c index e4adb48e..273a4fdb 100644 --- a/src/ui_pubkey_bagl.c +++ b/src/ui_pubkey_bagl.c @@ -34,24 +34,39 @@ #include -__attribute__((noreturn)) void prompt_pubkey(bool authorize, - ui_callback_t ok_cb, - ui_callback_t cxl_cb) { - init_screen_stack(); +/** + * @brief This structure represents a context needed for address screens navigation + * + */ +typedef struct { + char public_key_hash[PKH_STRING_SIZE]; +} AddressContext_t; +/// Current address context +static AddressContext_t address_context; + +UX_STEP_NOCB(ux_authorize_step, bnnn_paging, {"Authorize Baking", "With Public Key?"}); +UX_STEP_NOCB(ux_provide_step, bnnn_paging, {"Provide", "Public Key"}); +UX_STEP_NOCB(ux_public_key_hash_step, + bnnn_paging, + {"Public Key Hash", address_context.public_key_hash}); + +UX_CONFIRM_FLOW(ux_authorize_flow, &ux_authorize_step, &ux_public_key_hash_step); +UX_CONFIRM_FLOW(ux_provide_flow, &ux_provide_step, &ux_public_key_hash_step); + +void prompt_pubkey(bool authorize, ui_callback_t ok_cb, ui_callback_t cxl_cb) { + memset(&address_context, 0, sizeof(address_context)); + + bip32_path_with_curve_to_pkh_string(address_context.public_key_hash, + sizeof(address_context.public_key_hash), + &global.path_with_curve); + + ux_prepare_confirm_callbacks(ok_cb, cxl_cb); if (authorize) { - push_ui_callback("Authorize Baking", copy_string, "With Public Key?"); - push_ui_callback("Public Key Hash", - bip32_path_with_curve_to_pkh_string, - &global.path_with_curve); + ux_flow_init(0, ux_authorize_flow, NULL); } else { - push_ui_callback("Provide", copy_string, "Public Key"); - push_ui_callback("Public Key Hash", - bip32_path_with_curve_to_pkh_string, - &global.path_with_curve); + ux_flow_init(0, ux_provide_flow, NULL); } - - ux_confirm_screen(ok_cb, cxl_cb); - __builtin_unreachable(); } + #endif // HAVE_BAGL diff --git a/src/ui_reset_bagl.c b/src/ui_reset_bagl.c index 7d5e35c7..53a7aa42 100644 --- a/src/ui_reset_bagl.c +++ b/src/ui_reset_bagl.c @@ -36,12 +36,30 @@ #define G global.apdu.u.baking -__attribute__((noreturn)) void prompt_reset(ui_callback_t const ok_cb, ui_callback_t const cxl_cb) { - init_screen_stack(); - push_ui_callback("Reset HWM", number_to_string_indirect32, &G.reset_level); +/** + * @brief This structure represents a context needed for reset screens navigation + * + */ +typedef struct { + char reset_level[MAX_INT_DIGITS + 1u]; +} ResetContext_t; - ux_confirm_screen(ok_cb, cxl_cb); - __builtin_unreachable(); +/// Current reset context +static ResetContext_t reset_context; + +UX_STEP_NOCB(ux_reset_level_step, bnnn_paging, {"Reset HWM", reset_context.reset_level}); + +UX_CONFIRM_FLOW(ux_reset_flow, &ux_reset_level_step); + +void prompt_reset(ui_callback_t const ok_cb, ui_callback_t const cxl_cb) { + memset(&reset_context, 0, sizeof(reset_context)); + + number_to_string_indirect32(reset_context.reset_level, + sizeof(reset_context.reset_level), + &G.reset_level); + + ux_prepare_confirm_callbacks(ok_cb, cxl_cb); + ux_flow_init(0, ux_reset_flow, NULL); } #endif // HAVE_BAGL diff --git a/src/ui_setup_bagl.c b/src/ui_setup_bagl.c index 1446e1ce..a3cdb305 100644 --- a/src/ui_setup_bagl.c +++ b/src/ui_setup_bagl.c @@ -35,16 +35,54 @@ #define G global.apdu.u.setup -__attribute__((noreturn)) void prompt_setup(ui_callback_t const ok_cb, ui_callback_t const cxl_cb) { - init_screen_stack(); - push_ui_callback("Setup", copy_string, "Baking?"); - push_ui_callback("Address", bip32_path_with_curve_to_pkh_string, &global.path_with_curve); - push_ui_callback("Chain", chain_id_to_string_with_aliases, &G.main_chain_id); - push_ui_callback("Main Chain HWM", number_to_string_indirect32, &G.hwm.main); - push_ui_callback("Test Chain HWM", number_to_string_indirect32, &G.hwm.test); - - ux_confirm_screen(ok_cb, cxl_cb); - __builtin_unreachable(); +/** + * @brief This structure represents a context needed for setup screens navigation + * + */ +typedef struct { + char address[PKH_STRING_SIZE]; + char chain[CHAIN_ID_BASE58_STRING_SIZE]; + char main_hwm[MAX_INT_DIGITS + 1u]; + char test_hwm[MAX_INT_DIGITS + 1u]; +} SetupContext_t; + +/// Current setup context +static SetupContext_t setup_context; + +UX_STEP_NOCB(ux_setup_step, bnnn_paging, {"Setup", "Baking?"}); +UX_STEP_NOCB(ux_address_step, bnnn_paging, {"Address", setup_context.address}); +UX_STEP_NOCB(ux_chain_step, bnnn_paging, {"Chain", setup_context.chain}); +UX_STEP_NOCB(ux_main_hwm_step, bnnn_paging, {"Main Chain HWM", setup_context.main_hwm}); +UX_STEP_NOCB(ux_test_hwm_step, bnnn_paging, {"Test Chain HWM", setup_context.test_hwm}); + +UX_CONFIRM_FLOW(ux_setup_flow, + &ux_setup_step, + &ux_address_step, + &ux_chain_step, + &ux_main_hwm_step, + &ux_test_hwm_step); + +void prompt_setup(ui_callback_t const ok_cb, ui_callback_t const cxl_cb) { + memset(&setup_context, 0, sizeof(setup_context)); + + bip32_path_with_curve_to_pkh_string(setup_context.address, + sizeof(setup_context.address), + &global.path_with_curve); + + chain_id_to_string_with_aliases(setup_context.chain, + sizeof(setup_context.chain), + &G.main_chain_id); + + number_to_string_indirect32(setup_context.main_hwm, + sizeof(setup_context.main_hwm), + &G.hwm.main); + + number_to_string_indirect32(setup_context.test_hwm, + sizeof(setup_context.test_hwm), + &G.hwm.test); + + ux_prepare_confirm_callbacks(ok_cb, cxl_cb); + ux_flow_init(0, ux_setup_flow, NULL); } #endif // HAVE_BAGL From 7d900fb7696b7621b35be745891c174924c2c378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Palmer?= Date: Sat, 16 Mar 2024 22:21:11 +0100 Subject: [PATCH 2/2] Test: fix home authorized key display Since, with this change, showing the authorized public_key_hash from left show the last screen (and not the first as it was before the change) --- test/test_instructions.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test/test_instructions.py b/test/test_instructions.py index a38a0b99..f9ee4a4d 100644 --- a/test/test_instructions.py +++ b/test/test_instructions.py @@ -121,15 +121,13 @@ def both(): left() screen("high_watermark") left() - if account is not None and tezos_navigator.firmware.device == "nanos": - screen("public_key_hash_1") - right() - screen("public_key_hash_2") - left() - screen("public_key_hash_1") + if account is not None and firmware.device == "nanos": + for i in reversed(range(1, account.nanos_screens + 1)): + screen("public_key_hash_" + str(i)) + left() else: screen("public_key_hash") - left() + left() screen("chain_id") left() screen("version")