1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-26 09:28:13 +00:00

refactor(core): generate trezorproto module straight from Rust

This commit is contained in:
matejcik 2023-06-26 14:12:22 +02:00 committed by matejcik
parent 69bea5cff4
commit 78a8b48f1e
11 changed files with 113 additions and 154 deletions

View File

@ -206,8 +206,7 @@ SOURCE_MOD += [
# rust mods
SOURCE_MOD += [
'embed/extmod/rustmods/modtrezorproto.c',
'embed/extmod/rustmods/modtrezorui2.c',
'embed/extmod/rustmods.c',
]
# modutime

View File

@ -215,8 +215,7 @@ SOURCE_MOD += [
# rust mods
SOURCE_MOD += [
'embed/extmod/rustmods/modtrezorproto.c',
'embed/extmod/rustmods/modtrezorui2.c',
'embed/extmod/rustmods.c',
]
# modutime

View File

@ -17,12 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "librust.h"
#include "py/runtime.h"
#if MICROPY_PY_TREZORUI2
#include "librust.h"
MP_REGISTER_MODULE(MP_QSTR_trezorui2, mp_module_trezorui2);
#endif
#endif // MICROPY_PY_TREZORUI2
#if MICROPY_PY_TREZORPROTO
MP_REGISTER_MODULE(MP_QSTR_trezorproto, mp_module_trezorproto);
#endif

View File

@ -1,85 +0,0 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "py/runtime.h"
#if MICROPY_PY_TREZORPROTO
#include "librust.h"
/// from trezor.protobuf import MessageType
/// T = TypeVar("T", bound=MessageType)
/// def type_for_name(name: str) -> type[T]:
/// """Find the message definition for the given protobuf name."""
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorutils_protobuf_type_for_name_obj,
protobuf_type_for_name);
/// def type_for_wire(wire_type: int) -> type[T]:
/// """Find the message definition for the given wire type (numeric
/// identifier)."""
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorutils_protobuf_type_for_wire_obj,
protobuf_type_for_wire);
/// def decode(
/// buffer: bytes,
/// msg_type: Type[T],
/// enable_experimental: bool,
/// ) -> T:
/// """Decode data in the buffer into the specified message type."""
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorutils_protobuf_decode_obj,
protobuf_decode);
/// def encoded_length(msg: MessageType) -> int:
/// """Calculate length of encoding of the specified message."""
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorutils_protobuf_encoded_length_obj,
protobuf_len);
/// def encode(buffer: bytearray, msg: MessageType) -> int:
/// """Encode the message into the specified buffer. Return length of
/// encoding."""
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorutils_protobuf_encode_obj,
protobuf_encode);
STATIC const mp_rom_map_elem_t mp_module_trezorproto_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorproto)},
{MP_ROM_QSTR(MP_QSTR_type_for_name),
MP_ROM_PTR(&mod_trezorutils_protobuf_type_for_name_obj)},
{MP_ROM_QSTR(MP_QSTR_type_for_wire),
MP_ROM_PTR(&mod_trezorutils_protobuf_type_for_wire_obj)},
{MP_ROM_QSTR(MP_QSTR_decode),
MP_ROM_PTR(&mod_trezorutils_protobuf_decode_obj)},
{MP_ROM_QSTR(MP_QSTR_encoded_length),
MP_ROM_PTR(&mod_trezorutils_protobuf_encoded_length_obj)},
{MP_ROM_QSTR(MP_QSTR_encode),
MP_ROM_PTR(&mod_trezorutils_protobuf_encode_obj)},
};
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorproto_globals,
mp_module_trezorproto_globals_table);
const mp_obj_module_t mp_module_trezorproto = {
.base = {&mp_type_module},
.globals = (mp_obj_dict_t *)&mp_module_trezorproto_globals,
};
MP_REGISTER_MODULE(MP_QSTR_trezorproto, mp_module_trezorproto);
#endif // MICROPY_PY_TREZORPROTO

View File

@ -1,17 +1,13 @@
#include "librust_qstr.h"
#include "py/obj.h"
mp_obj_t protobuf_type_for_name(mp_obj_t name);
mp_obj_t protobuf_type_for_wire(mp_obj_t wire_id);
mp_obj_t protobuf_decode(mp_obj_t buf, mp_obj_t def,
mp_obj_t enable_experimental);
mp_obj_t protobuf_len(mp_obj_t obj);
mp_obj_t protobuf_encode(mp_obj_t buf, mp_obj_t obj);
#include "librust_qstr.h"
#ifdef TREZOR_EMULATOR
mp_obj_t protobuf_debug_msg_type();
mp_obj_t protobuf_debug_msg_def_type();
#endif
extern mp_obj_module_t mp_module_trezorproto;
extern mp_obj_module_t mp_module_trezorui2;
#ifdef TREZOR_EMULATOR

View File

@ -55,10 +55,13 @@ static void _librust_qstrs(void) {
MP_QSTR_confirm_with_info;
MP_QSTR_count;
MP_QSTR_data;
MP_QSTR_decode;
MP_QSTR_description;
MP_QSTR_disable_animation;
MP_QSTR_draw_welcome_screen;
MP_QSTR_dry_run;
MP_QSTR_encode;
MP_QSTR_encoded_length;
MP_QSTR_extra;
MP_QSTR_fee_amount;
MP_QSTR_fee_label;
@ -130,8 +133,11 @@ static void _librust_qstrs(void) {
MP_QSTR_total_label;
MP_QSTR_touch_event;
MP_QSTR_trace;
MP_QSTR_trezorproto;
MP_QSTR_trezorui2;
MP_QSTR_tutorial;
MP_QSTR_type_for_name;
MP_QSTR_type_for_wire;
MP_QSTR_usb_event;
MP_QSTR_user_fee_change;
MP_QSTR_value;

View File

@ -15,29 +15,6 @@ use super::{
zigzag,
};
#[no_mangle]
pub extern "C" fn protobuf_type_for_name(name: Obj) -> Obj {
let block = || {
let name = Qstr::try_from(name)?;
let def = MsgDef::for_name(name.to_u16()).ok_or_else(|| Error::KeyError(name.into()))?;
let obj = MsgDefObj::alloc(def)?.into();
Ok(obj)
};
unsafe { util::try_or_raise(block) }
}
#[no_mangle]
pub extern "C" fn protobuf_type_for_wire(wire_id: Obj) -> Obj {
let block = || {
let wire_id = u16::try_from(wire_id)?;
let def = MsgDef::for_wire_id(wire_id).ok_or_else(|| Error::KeyError(wire_id.into()))?;
let obj = MsgDefObj::alloc(def)?.into();
Ok(obj)
};
unsafe { util::try_or_raise(block) }
}
#[no_mangle]
pub extern "C" fn protobuf_decode(buf: Obj, msg_def: Obj, enable_experimental: Obj) -> Obj {
let block = || {
let def = Gc::<MsgDefObj>::try_from(msg_def)?;

View File

@ -12,7 +12,6 @@ use super::{
zigzag,
};
#[no_mangle]
pub extern "C" fn protobuf_len(obj: Obj) -> Obj {
let block = || {
let obj = Gc::<MsgObj>::try_from(obj)?;
@ -23,7 +22,6 @@ pub extern "C" fn protobuf_len(obj: Obj) -> Obj {
unsafe { util::try_or_raise(block) }
}
#[no_mangle]
pub extern "C" fn protobuf_encode(buf: Obj, obj: Obj) -> Obj {
let block = || {
let obj = Gc::<MsgObj>::try_from(obj)?;

View File

@ -7,6 +7,7 @@ use crate::{
ffi,
gc::Gc,
map::Map,
module::Module,
obj::{Obj, ObjBase},
qstr::Qstr,
typ::Type,
@ -15,8 +16,9 @@ use crate::{
};
use super::{
decode::Decoder,
decode::{protobuf_decode, Decoder},
defs::{find_name_by_msg_offset, get_msg, MsgDef},
encode::{protobuf_encode, protobuf_len},
};
#[repr(C)]
@ -289,3 +291,72 @@ pub extern "C" fn protobuf_debug_msg_type() -> &'static Type {
pub extern "C" fn protobuf_debug_msg_def_type() -> &'static Type {
MsgDefObj::obj_type()
}
pub extern "C" fn protobuf_type_for_name(name: Obj) -> Obj {
let block = || {
let name = Qstr::try_from(name)?;
let def = MsgDef::for_name(name.to_u16()).ok_or_else(|| Error::KeyError(name.into()))?;
let obj = MsgDefObj::alloc(def)?.into();
Ok(obj)
};
unsafe { util::try_or_raise(block) }
}
pub extern "C" fn protobuf_type_for_wire(wire_id: Obj) -> Obj {
let block = || {
let wire_id = u16::try_from(wire_id)?;
let def = MsgDef::for_wire_id(wire_id).ok_or_else(|| Error::KeyError(wire_id.into()))?;
let obj = MsgDefObj::alloc(def)?.into();
Ok(obj)
};
unsafe { util::try_or_raise(block) }
}
#[no_mangle]
pub static mp_module_trezorproto: Module = obj_module! {
/// from typing_extensions import Self
///
/// # XXX
/// # Note that MessageType "subclasses" are not true subclasses, but instead instances
/// # of the built-in metaclass MsgDef. MessageType instances are in fact instances of
/// # the built-in type Msg. That is why isinstance checks do not work, and instead the
/// # MessageTypeSubclass.is_type_of() method must be used.
///
/// class MessageType:
/// MESSAGE_NAME: ClassVar[str] = "MessageType"
/// MESSAGE_WIRE_TYPE: ClassVar[int | None] = None
///
/// @classmethod
/// def is_type_of(cls: type[Self], msg: "MessageType") -> TypeGuard[Self]:
/// """Identify if the provided message belongs to this type."""
///
/// mock:global
/// T = TypeVar("T", bound=MessageType)
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorproto.to_obj(),
/// def type_for_name(name: str) -> type[MessageType]:
/// """Find the message definition for the given protobuf name."""
Qstr::MP_QSTR_type_for_name => obj_fn_1!(protobuf_type_for_name).as_obj(),
/// def type_for_wire(wire_id: int) -> type[MessageType]:
/// """Find the message definition for the given wire type (numeric identifier)."""
Qstr::MP_QSTR_type_for_wire => obj_fn_1!(protobuf_type_for_wire).as_obj(),
/// def decode(
/// buffer: bytes,
/// msg_type: type[T],
/// enable_experimental: bool,
/// ) -> T:
/// """Decode data in the buffer into the specified message type."""
Qstr::MP_QSTR_decode => obj_fn_3!(protobuf_decode).as_obj(),
/// def encoded_length(msg: MessageType) -> int:
/// """Calculate length of encoding of the specified message."""
Qstr::MP_QSTR_encoded_length => obj_fn_1!(protobuf_len).as_obj(),
/// def encode(buffer: bytearray, msg: MessageType) -> int:
/// """Encode the message into the specified buffer. Return length of
/// encoding."""
Qstr::MP_QSTR_encode => obj_fn_2!(protobuf_encode).as_obj()
};

View File

@ -1,34 +1,47 @@
from typing import *
from trezor.protobuf import MessageType
from typing_extensions import Self
# XXX
# Note that MessageType "subclasses" are not true subclasses, but instead instances
# of the built-in metaclass MsgDef. MessageType instances are in fact instances of
# the built-in type Msg. That is why isinstance checks do not work, and instead the
# MessageTypeSubclass.is_type_of() method must be used.
# rust/src/protobuf/obj.rs
class MessageType:
MESSAGE_NAME: ClassVar[str] = "MessageType"
MESSAGE_WIRE_TYPE: ClassVar[int | None] = None
@classmethod
def is_type_of(cls: type[Self], msg: "MessageType") -> TypeGuard[Self]:
"""Identify if the provided message belongs to this type."""
T = TypeVar("T", bound=MessageType)
# extmod/rustmods/modtrezorproto.c
def type_for_name(name: str) -> type[T]:
# rust/src/protobuf/obj.rs
def type_for_name(name: str) -> type[MessageType]:
"""Find the message definition for the given protobuf name."""
# extmod/rustmods/modtrezorproto.c
def type_for_wire(wire_type: int) -> type[T]:
"""Find the message definition for the given wire type (numeric
identifier)."""
# rust/src/protobuf/obj.rs
def type_for_wire(wire_id: int) -> type[MessageType]:
"""Find the message definition for the given wire type (numeric identifier)."""
# extmod/rustmods/modtrezorproto.c
# rust/src/protobuf/obj.rs
def decode(
buffer: bytes,
msg_type: Type[T],
msg_type: type[T],
enable_experimental: bool,
) -> T:
"""Decode data in the buffer into the specified message type."""
# extmod/rustmods/modtrezorproto.c
# rust/src/protobuf/obj.rs
def encoded_length(msg: MessageType) -> int:
"""Calculate length of encoding of the specified message."""
# extmod/rustmods/modtrezorproto.c
# rust/src/protobuf/obj.rs
def encode(buffer: bytearray, msg: MessageType) -> int:
"""Encode the message into the specified buffer. Return length of
encoding."""

View File

@ -9,23 +9,7 @@ type_for_name = trezorproto.type_for_name
type_for_wire = trezorproto.type_for_wire
if TYPE_CHECKING:
# XXX
# Note that MessageType "subclasses" are not true subclasses, but instead instances
# of the built-in metaclass MsgDef. MessageType instances are in fact instances of
# the built-in type Msg. That is why isinstance checks do not work, and instead the
# MessageTypeSubclass.is_type_of() method must be used.
from typing import TypeGuard, TypeVar
T = TypeVar("T", bound="MessageType")
class MessageType:
MESSAGE_NAME: str = "MessageType"
MESSAGE_WIRE_TYPE: int | None = None
@classmethod
def is_type_of(cls: type[T], msg: "MessageType") -> TypeGuard[T]:
"""Identify if the provided message belongs to this type."""
raise NotImplementedError
MessageType = trezorproto.MessageType
def load_message_buffer(