- code is broken because depending modules are added in the next commitvacuum_feat_solana
parent
66578e487d
commit
ff1317e174
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,232 @@
|
||||
# generated from __init__.py.mako
|
||||
# do not edit manually!
|
||||
<%def name="getProgramId(program)">${"_".join(program["name"].upper().split(" ") + ["ID"])}</%def>\
|
||||
<%def name="getInstructionIdText(program, instruction)">${"_".join([getProgramId(program)] + ["INS"] + instruction["name"].upper().split(" "))}</%def>\
|
||||
<%def name="getClassName(program, instruction)">${program["name"].replace(" ", "")}${instruction["name"].replace(" ", "")}Instruction</%def>\
|
||||
<%def name="getReferenceName(reference)">${"_".join(reference["name"].lower().split(" "))}</%def>\
|
||||
<%def name="getReferenceOptionalType(reference)">\
|
||||
% if reference["optional"]:
|
||||
| None\
|
||||
% endif
|
||||
</%def>\
|
||||
<%def name="getReferenceTypeTemplate(reference)">\
|
||||
% if reference["signer"]:
|
||||
% if reference["access"] == "w":
|
||||
ADDRESS_SIG\
|
||||
% else:
|
||||
ADDRESS_SIG_READ_ONLY\
|
||||
% endif
|
||||
% else:
|
||||
% if reference["access"] == "w":
|
||||
ADDRESS_RW\
|
||||
% else:
|
||||
ADDRESS_READ_ONLY\
|
||||
% endif
|
||||
% endif
|
||||
</%def>\
|
||||
<%def name="getReferenceOptionalTemplate(reference)">\
|
||||
% if reference["optional"]:
|
||||
, True\
|
||||
% else:
|
||||
, False\
|
||||
% endif
|
||||
</%def>\
|
||||
<%def name="getPythonType(type)">\
|
||||
% if type in ("u32", "u64", "i32", "i64", "timestamp", "lamports"):
|
||||
int\
|
||||
% elif type in ("pubKey", "authority"):
|
||||
Account\
|
||||
% elif type in ("string", "memo"):
|
||||
str\
|
||||
% else:
|
||||
int\
|
||||
% endif
|
||||
</%def>\
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from trezor.wire import ProcessError
|
||||
|
||||
from ..types import AccountTemplate, InstructionIdFormat, PropertyTemplate, UIProperty
|
||||
from .instruction import Instruction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type, TypeGuard
|
||||
from ..types import Account
|
||||
|
||||
% for program in programs["programs"]:
|
||||
${getProgramId(program)} = "${program["id"]}"
|
||||
% endfor
|
||||
|
||||
% for program in programs["programs"]:
|
||||
% for instruction in program["instructions"]:
|
||||
${getInstructionIdText(program, instruction)} = ${instruction["id"]}
|
||||
% endfor
|
||||
% endfor
|
||||
|
||||
def __getattr__(name: str) -> Type[Instruction]:
|
||||
ids = {
|
||||
%for program in programs["programs"]:
|
||||
%for instruction in program["instructions"]:
|
||||
"${getClassName(program, instruction)}": ("${program["id"]}", ${instruction["id"]}),
|
||||
%endfor
|
||||
%endfor
|
||||
}
|
||||
id = ids[name]
|
||||
|
||||
class FakeClass(Instruction):
|
||||
@classmethod
|
||||
def is_type_of(cls, ins: Any):
|
||||
return ins.program_id == id[0] and ins.instruction_id == id[1]
|
||||
|
||||
return FakeClass
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
||||
% for program in programs["programs"]:
|
||||
## generates classes for instructions
|
||||
% for instruction in program["instructions"]:
|
||||
class ${getClassName(program, instruction)}(Instruction):
|
||||
PROGRAM_ID = ${getProgramId(program)}
|
||||
INSTRUCTION_ID = ${getInstructionIdText(program, instruction)}
|
||||
|
||||
## generates properties for instruction parameters
|
||||
% for parameter in instruction["parameters"]:
|
||||
${parameter["name"]}: ${getPythonType(parameter["type"])}
|
||||
% endfor
|
||||
|
||||
## generates properties for reference accounts
|
||||
% for reference in instruction["references"]:
|
||||
${getReferenceName(reference)}: Account${getReferenceOptionalType(reference)}
|
||||
% endfor
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, ins: Any) -> TypeGuard["${getClassName(program, instruction)}"]:
|
||||
return (
|
||||
ins.program_id == cls.PROGRAM_ID
|
||||
and ins.instruction_id == cls.INSTRUCTION_ID
|
||||
)
|
||||
|
||||
% endfor
|
||||
% endfor
|
||||
|
||||
def get_instruction_id_length(program_id: str) -> InstructionIdFormat:
|
||||
% for program in programs["programs"]:
|
||||
if program_id == ${getProgramId(program)}:
|
||||
return InstructionIdFormat(${program["instruction_id_format"]["length"]}, ${program["instruction_id_format"]["is_included_if_zero"]})
|
||||
% endfor
|
||||
|
||||
return InstructionIdFormat(0, False)
|
||||
|
||||
|
||||
<%def name="getOptionalString(obj, string)">\
|
||||
% if string in obj:
|
||||
"${obj[string]}"\
|
||||
%else:
|
||||
None\
|
||||
% endif
|
||||
</%def>\
|
||||
|
||||
def get_instruction(
|
||||
program_id: str, instruction_id: int, instruction_accounts: list[Account], instruction_data: bytes
|
||||
) -> Instruction:
|
||||
% for program in programs["programs"]:
|
||||
% if len(program["instructions"]) > 0:
|
||||
if program_id == ${getProgramId(program)}:
|
||||
% for instruction in program["instructions"]:
|
||||
if instruction_id == ${getInstructionIdText(program, instruction)}:
|
||||
return Instruction(
|
||||
instruction_data,
|
||||
program_id,
|
||||
instruction_accounts,
|
||||
${getInstructionIdText(program, instruction)},
|
||||
[
|
||||
% for parameter in instruction["parameters"]:
|
||||
PropertyTemplate(
|
||||
"${parameter["name"]}",
|
||||
"${parameter["type"]}",
|
||||
${parameter["optional"]},
|
||||
),
|
||||
% endfor
|
||||
],
|
||||
[
|
||||
% for reference in instruction["references"]:
|
||||
AccountTemplate(
|
||||
"${reference["name"]}",
|
||||
${reference["is_authority"]},
|
||||
${reference["optional"]},
|
||||
),
|
||||
% endfor
|
||||
],
|
||||
[
|
||||
% for ui_property in instruction["ui_properties"]:
|
||||
UIProperty(
|
||||
${getOptionalString(ui_property, "parameter")},
|
||||
${getOptionalString(ui_property, "account")},
|
||||
"${ui_property["display_name"]}",
|
||||
${ui_property["is_authority"] if "is_authority" in ui_property else False},
|
||||
),
|
||||
% endfor
|
||||
],
|
||||
"${program["name"]}: ${instruction["name"]}",
|
||||
True,
|
||||
True,
|
||||
${instruction["is_multisig"]},
|
||||
${getOptionalString(instruction, "is_deprecated_warning")},
|
||||
)
|
||||
% endfor
|
||||
return Instruction(
|
||||
instruction_data,
|
||||
program_id,
|
||||
instruction_accounts,
|
||||
instruction_id,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
"${program["name"]}",
|
||||
True,
|
||||
False,
|
||||
False
|
||||
)
|
||||
% endif
|
||||
% endfor
|
||||
return Instruction(
|
||||
instruction_data,
|
||||
program_id,
|
||||
instruction_accounts,
|
||||
0,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
"Unsupported program",
|
||||
False,
|
||||
False,
|
||||
False
|
||||
)
|
||||
|
||||
% for param in programs["parameters"]:
|
||||
% if param["family"] == "enum":
|
||||
class ${param["name"]}:
|
||||
@classmethod
|
||||
def type(cls) -> str:
|
||||
return "${param["type"]}"
|
||||
|
||||
@classmethod
|
||||
def from_int(cls, value: int) -> str:
|
||||
% for variant in param["fields"]:
|
||||
if value == ${variant["value"]}:
|
||||
return "${variant["name"]}"
|
||||
% endfor
|
||||
raise ProcessError(f"Unknown value: {value}")
|
||||
% endif
|
||||
% endfor
|
||||
|
||||
|
||||
def enum_type_to_class(enum_type: str):
|
||||
% for param in programs["parameters"]:
|
||||
% if param["family"] == "enum":
|
||||
if enum_type == "${param["name"]}":
|
||||
return ${param["name"]}
|
||||
% endif
|
||||
% endfor
|
||||
raise ProcessError(f"Unknown enum type: {enum_type}")
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
CWD=`dirname "$0"`
|
||||
RENDER="python3 $CWD/build_solana_templates.py"
|
||||
|
||||
PROGRAMS_PATH="$CWD/../src/apps/solana/transaction"
|
||||
|
||||
FW_PATH=$PROGRAMS_PATH
|
||||
FW_OUTPUT_PATH="$FW_PATH/instructions.py"
|
||||
|
||||
TESTS_PATH="$CWD/../../tests/device_tests/solana/construct"
|
||||
TESTS_OUTPUT_PATH="$TESTS_PATH/instructions.py"
|
||||
|
||||
format() {
|
||||
isort $1 -q
|
||||
black $1 -q
|
||||
flake8 $1 -q
|
||||
}
|
||||
|
||||
check_results() {
|
||||
OUTPUT_PATH=$1
|
||||
|
||||
CHECK_FAIL=0
|
||||
TMP=`mktemp`
|
||||
TARGET=$OUTPUT_PATH
|
||||
$RENDER "$PROGRAMS_PATH" -o $TMP
|
||||
format $TMP
|
||||
|
||||
if ! diff -u "$TARGET" "$TMP"; then
|
||||
CHECK_FAIL=1
|
||||
fi
|
||||
exit $CHECK_FAIL
|
||||
}
|
||||
|
||||
if [ "$1" = "--check" ]; then
|
||||
check_results $FW_OUTPUT_PATH
|
||||
check_results $TESTS_OUTPUT_PATH
|
||||
else
|
||||
$RENDER $FW_PATH -p $PROGRAMS_PATH -o $FW_OUTPUT_PATH
|
||||
format $FW_OUTPUT_PATH
|
||||
|
||||
$RENDER $TESTS_PATH -p "$PROGRAMS_PATH" -o $TESTS_OUTPUT_PATH
|
||||
format $TESTS_OUTPUT_PATH
|
||||
fi
|
@ -0,0 +1,25 @@
|
||||
# !/usr/bin/env python3
|
||||
from json import load
|
||||
|
||||
import click
|
||||
from mako.template import Template
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("template_path", type=str)
|
||||
@click.option("-p", "--programs-path", type=str, default=None)
|
||||
@click.option("-o", "--out-file", type=click.File(mode="w"), default="-")
|
||||
def render(template_path, programs_path, out_file):
|
||||
if programs_path is None:
|
||||
programs_path = template_path
|
||||
|
||||
with open(f"{programs_path}/programs.json", "r") as file:
|
||||
programs = load(file)
|
||||
|
||||
template = Template(filename=f"{template_path}/instructions.py.mako")
|
||||
|
||||
out_file.write(template.render(programs=programs))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
render()
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,113 @@
|
||||
# generated from __init__.py.mako
|
||||
# do not edit manually!
|
||||
|
||||
<%def name="getProgramId(program)">${"_".join(program["name"].upper().split(" ") + ["ID"])}</%def>\
|
||||
<%def name="getInstructionIdText(instruction)">${"_".join(["INS"] + instruction["name"].upper().split(" "))}</%def>\
|
||||
<%def name="getProgramInstructionsEnumName(program)">${program["name"].replace(" ", "")}Instruction</%def>\
|
||||
<%def name="getProgramInstructionsConstructName(program)">${program["name"].replace(" ","")}_Instruction</%def>\
|
||||
<%def name="getInstructionConstructName(program, instruction)">${program["name"].replace(" ","")}_${instruction["name"].replace(" ", "")}_Instruction</%def>\
|
||||
<%def name="getConstructType(type)">\
|
||||
% if type in ("u64", "i64"):
|
||||
Int64ul\
|
||||
% elif type in ("u32", "i32"):
|
||||
Int32ul\
|
||||
% elif type == "u8":
|
||||
Byte\
|
||||
% elif type in ("pubKey", "authority"):
|
||||
PublicKey\
|
||||
% elif type == "string":
|
||||
String\
|
||||
% elif type == "memo":
|
||||
Memo\
|
||||
% else:
|
||||
Int64ul\
|
||||
% endif
|
||||
</%def>\
|
||||
from enum import IntEnum
|
||||
from construct import (
|
||||
Byte,
|
||||
GreedyBytes,
|
||||
GreedyRange,
|
||||
Int32ul,
|
||||
Int64ul,
|
||||
Optional,
|
||||
Struct,
|
||||
Switch,
|
||||
)
|
||||
from .custom_constructs import (
|
||||
CompactArray,
|
||||
CompactStruct,
|
||||
HexStringAdapter,
|
||||
InstructionIdAdapter,
|
||||
Memo,
|
||||
PublicKey,
|
||||
String,
|
||||
)
|
||||
|
||||
class Program:
|
||||
% for program in programs["programs"]:
|
||||
${getProgramId(program)} = "${program["id"]}"
|
||||
% endfor
|
||||
|
||||
INSTRUCTION_ID_FORMATS = {
|
||||
% for program in programs["programs"]:
|
||||
Program.${getProgramId(program)}: ${program["instruction_id_format"]},
|
||||
% endfor
|
||||
}
|
||||
|
||||
% for program in programs["programs"]:
|
||||
|
||||
${"#"} ${program["name"]} begin
|
||||
|
||||
class ${getProgramInstructionsEnumName(program)}(IntEnum):
|
||||
% for instruction in program["instructions"]:
|
||||
${getInstructionIdText(instruction)} = ${instruction["id"]}
|
||||
% endfor
|
||||
|
||||
% for instruction in program["instructions"]:
|
||||
${getInstructionConstructName(program, instruction)} = Struct(
|
||||
"program_index" / Byte,
|
||||
"accounts" / CompactStruct(
|
||||
% for reference in instruction["references"]:
|
||||
"${reference["name"]}" / Byte,
|
||||
% endfor
|
||||
% if instruction["is_multisig"]:
|
||||
"multisig_signers" / Optional(GreedyRange(Byte))
|
||||
% endif
|
||||
),
|
||||
"data" / CompactStruct(
|
||||
"instruction_id" / InstructionIdAdapter(GreedyBytes),
|
||||
% for parameter in instruction["parameters"]:
|
||||
"${parameter["name"]}" / ${getConstructType(parameter["type"])},
|
||||
% endfor
|
||||
),
|
||||
)
|
||||
|
||||
% endfor
|
||||
|
||||
${getProgramInstructionsConstructName(program)} = Switch(
|
||||
lambda this: this.instruction_id,
|
||||
{
|
||||
%for instruction in program["instructions"]:
|
||||
${getProgramInstructionsEnumName(program)}.${getInstructionIdText(instruction)}: ${getInstructionConstructName(program, instruction)},
|
||||
%endfor
|
||||
},
|
||||
)
|
||||
|
||||
${"#"} ${program["name"]} end
|
||||
% endfor
|
||||
|
||||
Instruction = Switch(
|
||||
lambda this: this.program_id,
|
||||
{
|
||||
% for program in programs["programs"]:
|
||||
Program.${getProgramId(program)}: ${getProgramInstructionsConstructName(program)},
|
||||
%endfor
|
||||
},
|
||||
# unknown instruction
|
||||
Struct(
|
||||
"program_index" / Byte,
|
||||
"accounts" / CompactArray(Byte),
|
||||
"data" / HexStringAdapter(GreedyBytes),
|
||||
)
|
||||
)
|
Loading…
Reference in new issue