Skip to content

Commit

Permalink
Merge pull request #224 from trilitech/palmer@functori@handle-oxford-…
Browse files Browse the repository at this point in the history
…changes

Parser: handle Oxford changes
  • Loading branch information
ajinkyaraj-23 authored Feb 20, 2024
2 parents 895709c + 7a633aa commit cb5cdd2
Show file tree
Hide file tree
Showing 180 changed files with 186 additions and 86 deletions.
4 changes: 3 additions & 1 deletion app/src/parser/formatting.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ const char *const tz_michelson_op_names_ordered[TZ_LAST_MICHELSON_OPCODE + 1]
"EMIT", // 151
"Lambda_rec", // 152
"LAMBDA_REC", // 153
"TICKET" // 154
"TICKET", // 154
"BYTES", // 155
"NAT", // 156
};

const char *
Expand Down
2 changes: 1 addition & 1 deletion app/src/parser/formatting.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*
* Should be kept in sync with the last protocol update.
*/
#define TZ_LAST_MICHELSON_OPCODE 154
#define TZ_LAST_MICHELSON_OPCODE 157

/**
* @brief Get the human readable name of a Michelson op_code if valid
Expand Down
61 changes: 58 additions & 3 deletions app/src/parser/operation_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ const char *const tz_operation_parser_step_name[] = {"OPTION",
"READ_SORU_MESSAGES",
"READ_SORU_KIND",
"READ_BALLOT",
"READ_PROTOS"};
"READ_PROTOS",
"READ_PKH_LIST"};

/**
* @brief Get the string format of an operations step
Expand Down Expand Up @@ -229,8 +230,10 @@ TZ_OPERATION_FIELDS(soru_origin_fields,
TZ_OPERATION_MANAGER_OPERATION_FIELDS,
TZ_OPERATION_FIELD("Kind", TZ_OPERATION_FIELD_SORU_KIND),
TZ_OPERATION_FIELD("Kernel", TZ_OPERATION_FIELD_BINARY, .complex=true),
TZ_OPERATION_FIELD("Proof", TZ_OPERATION_FIELD_BINARY, .complex=true),
TZ_OPERATION_FIELD("Parameters", TZ_OPERATION_FIELD_EXPR, .complex=true)
TZ_OPERATION_FIELD("Parameters", TZ_OPERATION_FIELD_EXPR, .complex=true),
TZ_OPERATION_OPTION_FIELD("Whitelist",
TZ_OPERATION_FIELD("Whitelist", TZ_OPERATION_FIELD_PKH_LIST),
.display_none=false)
);

/**
Expand Down Expand Up @@ -1135,6 +1138,16 @@ tz_step_field(tz_parser_state *state)
op->frame->step_read_string.skip = field->skip;
break;
}
case TZ_OPERATION_FIELD_PKH_LIST: {
op->frame->step = TZ_OPERATION_STEP_READ_PKH_LIST;
op->frame->step_read_list.name = name;
op->frame->step_read_list.index = 0;
op->frame->step_read_list.skip = field->skip;
tz_must(push_frame(state, TZ_OPERATION_STEP_SIZE));
op->frame->step_size.size = 0;
op->frame->step_size.size_len = 4;
break;
}
case TZ_OPERATION_FIELD_BALLOT: {
op->frame->step = TZ_OPERATION_STEP_READ_BALLOT;
op->frame->step_read_string.skip = field->skip;
Expand Down Expand Up @@ -1181,6 +1194,42 @@ tz_step_read_pk(tz_parser_state *state)
tz_continue;
}

/**
* @brief Read a list of public key hash
*
* @param state: parser state
* @return tz_parser_result: parser result
*/
static tz_parser_result
tz_step_read_pkh_list(tz_parser_state *state)
{
ASSERT_STEP(state, READ_PKH_LIST);
tz_operation_state *op = &state->operation;
tz_parser_regs *regs = &state->regs;
uint8_t skip = op->frame->step_read_list.skip;
const char *name = op->frame->step_read_list.name;
uint16_t index = op->frame->step_read_list.index;

// Remaining content from previous public key hash - display this first.
if (regs->oofs > 0) {
tz_stop(IM_FULL);
}

if (op->frame->stop == state->ofs) {
tz_must(pop_frame(state));
} else {
op->frame->step_read_list.index++;
tz_must(push_frame(state, TZ_OPERATION_STEP_READ_BYTES));
snprintf(state->field_info.field_name, TZ_FIELD_NAME_SIZE, "%s (%d)",
name, index);
op->frame->step_read_bytes.kind = TZ_OPERATION_FIELD_PKH;
op->frame->step_read_bytes.skip = skip;
op->frame->step_read_bytes.ofs = 0;
op->frame->step_read_bytes.len = 21;
}
tz_continue;
}

/**
* @brief Read soru messages
*
Expand Down Expand Up @@ -1237,6 +1286,9 @@ tz_step_read_soru_kind(tz_parser_state *state)
case 1:
strlcpy((char *)CAPTURE, "wasm_2_0_0", sizeof(CAPTURE));
break;
case 2: /// Present in encoding, not activated in Oxford
strlcpy((char *)CAPTURE, "riscv", sizeof(CAPTURE));
break;
default:
tz_raise(INVALID_TAG);
}
Expand Down Expand Up @@ -1425,6 +1477,9 @@ tz_operation_parser_step(tz_parser_state *state)
case TZ_OPERATION_STEP_READ_PROTOS:
tz_must(tz_step_read_protos(state));
break;
case TZ_OPERATION_STEP_READ_PKH_LIST:
tz_must(tz_step_read_pkh_list(state));
break;
case TZ_OPERATION_STEP_PRINT:
case TZ_OPERATION_STEP_PARTIAL_PRINT:
tz_must(tz_step_print(
Expand Down
4 changes: 3 additions & 1 deletion app/src/parser/operation_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ typedef enum {
TZ_OPERATION_STEP_READ_SORU_MESSAGES,
TZ_OPERATION_STEP_READ_SORU_KIND,
TZ_OPERATION_STEP_READ_BALLOT,
TZ_OPERATION_STEP_READ_PROTOS
TZ_OPERATION_STEP_READ_PROTOS,
TZ_OPERATION_STEP_READ_PKH_LIST
} tz_operation_parser_step_kind;

/**
Expand Down Expand Up @@ -97,6 +98,7 @@ typedef enum {
TZ_OPERATION_FIELD_BH,
TZ_OPERATION_FIELD_SORU_MESSAGES,
TZ_OPERATION_FIELD_SORU_KIND,
TZ_OPERATION_FIELD_PKH_LIST,
TZ_OPERATION_FIELD_BALLOT
} tz_operation_field_kind;

Expand Down
25 changes: 13 additions & 12 deletions docker/Dockerfile.ocaml
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
FROM ocaml/opam:alpine-3.17-ocaml-4.14
FROM ocaml/opam:alpine-3.18-ocaml-4.14

RUN sudo cp /usr/bin/opam-2.1 /usr/bin/opam; \
OCTEZ_VERSION=17.1; \
opam remote add opam https://opam.ocaml.org; \
RUSTUP_TOOLCHAIN=1.71.1; \
OCTEZ_VERSION=19.1; \
OCTEZ_REPO=https://gitlab.com/tezos/tezos.git; \
OCTEZ_COMMIT=`git ls-remote $OCTEZ_REPO v$OCTEZ_VERSION | cut -f 1`; \
OCTEZ_URL=$OCTEZ_REPO#$OCTEZ_COMMIT; \
wget https://sh.rustup.rs/rustup-init.sh; \
chmod +x rustup-init.sh; \
./rustup-init.sh --profile minimal --default-toolchain $RUSTUP_TOOLCHAIN -y; \
source "$HOME/.cargo/env"; \
opam install \
tezos-client-017-PtNairob.$OCTEZ_VERSION \
terminal_size \
octez-codec.$OCTEZ_VERSION \
tezos-test-helpers.$OCTEZ_VERSION; \
opam pin tezos-benchmark.$OCTEZ_VERSION $OCTEZ_URL; \
octez-protocol-018-Proxford-libs.$OCTEZ_VERSION \
terminal_size; \
opam pin tezos-micheline-rewriting.$OCTEZ_VERSION $OCTEZ_URL; \
opam pin tezos-benchmark-type-inference-017-PtNairob.$OCTEZ_VERSION $OCTEZ_URL; \
opam pin tezos-017-PtNairob-test-helpers.$OCTEZ_VERSION $OCTEZ_URL; \
opam pin tezos-benchmark-017-PtNairob.$OCTEZ_VERSION $OCTEZ_URL; \
opam pin tezos-shell-benchmarks.$OCTEZ_VERSION $OCTEZ_URL; \
opam pin tezos-benchmarks-proto-017-PtNairob.$OCTEZ_VERSION $OCTEZ_URL; \
opam pin tezos-benchmark-type-inference-018-Proxford.$OCTEZ_VERSION $OCTEZ_URL; \
opam pin tezos-benchmark-018-Proxford.$OCTEZ_VERSION $OCTEZ_URL; \
opam pin tezos-benchmarks-proto-018-Proxford.$OCTEZ_VERSION $OCTEZ_URL; \
rm -rf opam-repository .opam/download-cache .opam/repo \
.opam/4.14/.opam-switch/build .opam/4.14/.opam-switch/sources;
4 changes: 2 additions & 2 deletions tests/generate/dune
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(executable
(name generate)
(libraries "tezos-protocol-017-PtNairob"
"tezos-benchmarks-proto-017-PtNairob"))
(libraries "octez-protocol-018-Proxford-libs.client"
"tezos-benchmarks-proto-018-Proxford"))
32 changes: 18 additions & 14 deletions tests/generate/gen_integration.ml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ let sign ppf ~signer:Apdu.Signer.({ sk; pk; _ } as signer) ~watermark bin =
in
send_async_apdus ppf async_apdus

open Tezos_protocol_017_PtNairob
open Tezos_protocol_018_Proxford
open Tezos_micheline

let rec pp_node ~wrap ppf (node : Protocol.Script_repr.node) =
Expand Down Expand Up @@ -317,25 +317,29 @@ let operation_to_screens
{ rollup; cemented_commitment; output_proof } ->
aux ~kind:"SR: execute outbox message"
[
make_screen ~title:"Rollup" "%a" Sc_rollup_repr.Address.pp rollup;
make_screen ~title:"Rollup" "%a" Sc_rollup.Address.pp rollup;
make_screen ~title:"Commitment" "%a" Sc_rollup.Commitment.Hash.pp
cemented_commitment;
need_expert_mode_screen "Output proof";
make_screen ~title:"Output proof" "%a" pp_string_binary output_proof;
]
| Sc_rollup_originate
{ kind; boot_sector; origination_proof; parameters_ty } ->
| Sc_rollup_originate { kind; boot_sector; parameters_ty; whitelist } ->
let whitelist =
match whitelist with
| None | Some [] -> []
| Some whitelist ->
make_screens ~title:"Whitelist"
Tezos_crypto.Signature.Public_key_hash.pp whitelist
in
aux ~kind:"SR: originate"
[
make_screen ~title:"Kind" "%a" Sc_rollup.Kind.pp kind;
need_expert_mode_screen "Kernel";
make_screen ~title:"Kernel" "%a" pp_string_binary boot_sector;
need_expert_mode_screen "Proof";
make_screen ~title:"Proof" "%a" pp_serialized_proof
origination_proof;
need_expert_mode_screen "Parameters";
make_screen ~title:"Parameters" "%a" pp_lazy_expr parameters_ty;
]
([
make_screen ~title:"Kind" "%a" Sc_rollup.Kind.pp kind;
need_expert_mode_screen "Kernel";
make_screen ~title:"Kernel" "%a" pp_string_binary boot_sector;
need_expert_mode_screen "Parameters";
make_screen ~title:"Parameters" "%a" pp_lazy_expr parameters_ty;
]
@ whitelist)
| _ -> assert false
in
let screen_of_operation (type t) (operation : t contents) =
Expand Down
4 changes: 2 additions & 2 deletions tests/generate/gen_micheline.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License. *)

open Tezos_protocol_017_PtNairob
open Tezos_protocol_018_Proxford
open Tezos_micheline
open Tezos_benchmarks_proto_017_PtNairob
open Tezos_benchmarks_proto_018_Proxford

let config =
{
Expand Down
24 changes: 12 additions & 12 deletions tests/generate/gen_operations.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License. *)

open Tezos_protocol_017_PtNairob
open Tezos_protocol_018_Proxford

let gen_lazy_expr =
let open QCheck2.Gen in
Expand Down Expand Up @@ -144,7 +144,7 @@ let some_sc_rollup_hash =
let gen_sc_rollup_hash =
let open QCheck2.Gen in
let+ sc_h = oneofl some_sc_rollup_hash in
Protocol.Alpha_context.Sc_rollup_repr.Address.of_b58check_exn sc_h
Protocol.Alpha_context.Sc_rollup.Address.of_b58check_exn sc_h

let some_sc_rollup_commiment_hash =
[
Expand Down Expand Up @@ -175,6 +175,7 @@ let some_protocol_hash =
"PtLimaPtLMwfNinJi9rCfDPWea8dFgTZ1MeJ9f1m2SRic6ayiwW";
"PtMumbai2TmsJHNGRkD8v8YDbtao7BLUC3wjASn1inAKLFCjaH1";
"PtNairobiyssHuh87hEhfVBGCVrK3WnS8Z2FT4ymB5tAa4r1nQf";
"ProxfordYmVfjWnRcgjWH36fW6PArwqykTFzotUxRs6gmTcZDuH";
"ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK";
"ProtoALphaALphaALphaALphaALphaALphaALpha61322gcLUGH";
"ProtoALphaALphaALphaALphaALphaALphaALphabc2a7ebx6WB";
Expand Down Expand Up @@ -279,6 +280,10 @@ let gen_entrypoint =
set_delegate;
remove_delegate;
deposit;
stake;
unstake;
finalize_unstake;
set_delegate_parameters;
of_string_strict_exn "jean_bob";
]

Expand Down Expand Up @@ -367,18 +372,13 @@ let gen_sc_rollup_execute_outbox_message =
let gen_sc_rollup_originate =
let open Protocol.Alpha_context in
let open QCheck2.Gen in
let* kind = oneofl Sc_rollup.Kind.[ Example_arith; Wasm_2_0_0 ] in
let* kind = oneofl Sc_rollup.Kind.[ Example_arith; Wasm_2_0_0; Riscv ] in
let* boot_sector = string_size small_nat in
let* origination_proof = string_size small_nat in
let origination_proof =
Data_encoding.(
origination_proof
|> Binary.to_bytes_exn (string' Hex)
|> Binary.of_bytes_exn Sc_rollup.Proof.serialized_encoding)
in
let* parameters_ty = gen_lazy_expr in
return
(Sc_rollup_originate { kind; boot_sector; origination_proof; parameters_ty })
let* whitelist =
QCheck2.Gen.option @@ list_size small_nat gen_public_key_hash
in
return (Sc_rollup_originate { kind; boot_sector; parameters_ty; whitelist })

let gen_proposals =
let open Protocol.Alpha_context in
Expand Down
2 changes: 1 addition & 1 deletion tests/generate/gen_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License. *)

open Tezos_protocol_017_PtNairob
open Tezos_protocol_018_Proxford
open Tezos_micheline

let random_state =
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 30 additions & 11 deletions tests/integration/nano/test_sign_sc_rollup_originate.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,44 @@
# Storage limit: 4
# Kind: arith
# Kernel: 396630396632393532643334353238633733336639343631356366633339626335353536313966633535306464346136376261323230386365386538363761613364313361366566393964666265333263363937346161396132313530643231656361323963333334396535396331336239303831663163313162343430616334643334353564656462653465653064653135613861663632306434633836323437643964313332646531626236646132336435666639643864666664613232626139613834
# Proof: 030002104135165622d08b0c6eac951c9d4fd65109585907bc30ef0617f6c26853c6ba724af04dd3e4b5861efae3166ebc12ef5781df9715c20943e8d0b7bc06068a6f8106737461747573c87a31b1c8e3af61756b336bcfc3b0c292c89b40cc8a5080ba99c45463d110ce8b
# Parameters: Pair "1" 2
# Whitelist (0): tz1ixvCiPJYyMjsp2nKBVaq54f6AdbV8hCKa
# Whitelist (1): tz2WmivuMG8MMRKMEmzKRMMxMApxZQWYNS4W
# Whitelist (2): tz3XMQscBFM9vPmpbYMavMmwxRMUWvWGZMQQ

def test_sign_sc_rollup_originate(app):
test_name = Path(__file__).stem

app.setup_expert_mode()

message = Message.from_bytes("030000000000000000000000000000000000000000000000000000000000000000c800ffdd6102321bc251e4a5190ad5b12b251069d9b4904e02030400000000c63966303966323935326433343532386337333366393436313563666333396263353535363139666335353064643461363762613232303863653865383637616133643133613665663939646662653332633639373461613961323135306432316563613239633333343965353963313362393038316631633131623434306163346433343535646564626534656530646531356138616636323064346338363234376439643133326465316262366461323364356666396438646666646132326261396138340000006c030002104135165622d08b0c6eac951c9d4fd65109585907bc30ef0617f6c26853c6ba724af04dd3e4b5861efae3166ebc12ef5781df9715c20943e8d0b7bc06068a6f8106737461747573c87a31b1c8e3af61756b336bcfc3b0c292c89b40cc8a5080ba99c45463d110ce8b0000000a07070100000001310002")
sc_rollup_originate_with_missing_white_list = "030000000000000000000000000000000000000000000000000000000000000000c800ffdd6102321bc251e4a5190ad5b12b251069d9b4904e02030400000000c63966303966323935326433343532386337333366393436313563666333396263353535363139666335353064643461363762613232303863653865383637616133643133613665663939646662653332633639373461613961323135306432316563613239633333343965353963313362393038316631633131623434306163346433343535646564626534656530646531356138616636323064346338363234376439643133326465316262366461323364356666396438646666646132326261396138340000000a07070100000001310002"

data = app.sign(DEFAULT_ACCOUNT,
message,
with_hash=True,
path=test_name)
def check_sign(name: str, whitelist: bytes):

app.checker.check_signature(
account=DEFAULT_ACCOUNT,
message=message,
with_hash=True,
data=data)
message = Message.from_bytes(sc_rollup_originate_with_missing_white_list + whitelist)

data = app.sign(DEFAULT_ACCOUNT,
message,
with_hash=True,
path=Path(test_name) / name)

app.checker.check_signature(
account=DEFAULT_ACCOUNT,
message=message,
with_hash=True,
data=data)

# None
check_sign("no_whitelist", "00")

# Some []
check_sign("no_whitelist", "ff00000000")

# Some [
# tz1ixvCiPJYyMjsp2nKBVaq54f6AdbV8hCKa;
# tz2WmivuMG8MMRKMEmzKRMMxMApxZQWYNS4W;
# tz3XMQscBFM9vPmpbYMavMmwxRMUWvWGZMQQ
# ]
check_sign("with_whitelist", "ff0000003f00ffdd6102321bc251e4a5190ad5b12b251069d9b401f6552df4f5ff51c3d13347cab045cfdb8b9bd8030278eb8b6ab9a768579cd5146b480789650c83f28e")

app.quit()
12 changes: 6 additions & 6 deletions tests/unit/ctest/tests_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,18 +457,18 @@ CTEST2(operation_parser, check_sc_rollup_originate_complexity)
"396333333439653539633133623930383166316331316234343061633464333435"
"356465646265346565306465313561386166363230643463383632343764396431"
"333264653162623664613233643566663964386466666461323262613961383400"
"00006c030002104135165622d08b0c6eac951c9d4fd65109585907bc30ef0617f6"
"c26853c6ba724af04dd3e4b5861efae3166ebc12ef5781df9715c20943e8d0b7bc"
"06068a6f8106737461747573c87a31b1c8e3af61756b336bcfc3b0c292c89b40cc"
"8a5080ba99c45463d110ce8b0000000a07070100000001310002";
"00000a07070100000001310002ff0000003f00ffdd6102321bc251e4a5190ad5b1"
"2b251069d9b401f6552df4f5ff51c3d13347cab045cfdb8b9bd8030278eb8b6ab9"
"a768579cd5146b480789650c83f28e";
const tz_fields_check fields_check[] = {
{"Source", false, 1},
{"Fee", false, 2},
{"Storage limit", false, 3},
{"Kind", false, 4},
{"Kernel", true, 5},
{"Proof", true, 6},
{"Parameters", true, 7},
{"Parameters", true, 6},
// {"Option", _, 7},
{"Whitelist", false, 8},
};
check_field_complexity(data, str, fields_check, sizeof(fields_check));
}
Loading

0 comments on commit cb5cdd2

Please sign in to comment.