/__w/smoldot/smoldot/repo/lib/src/transactions/validate/tests.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Smoldot |
2 | | // Copyright (C) 2023 Pierre Krieger |
3 | | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 |
4 | | |
5 | | // This program is free software: you can redistribute it and/or modify |
6 | | // it under the terms of the GNU General Public License as published by |
7 | | // the Free Software Foundation, either version 3 of the License, or |
8 | | // (at your option) any later version. |
9 | | |
10 | | // This program is distributed in the hope that it will be useful, |
11 | | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | // GNU General Public License for more details. |
14 | | |
15 | | // You should have received a copy of the GNU General Public License |
16 | | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | | |
18 | | #![cfg(test)] |
19 | | |
20 | | use crate::{ |
21 | | executor::{self, runtime_call}, |
22 | | header, |
23 | | trie::proof_decode, |
24 | | }; |
25 | | use core::iter; |
26 | | |
27 | | #[test] |
28 | 1 | fn validate_from_proof() { |
29 | 1 | // Regression test for <https://github.com/smol-dot/smoldot/issues/873>. |
30 | 1 | |
31 | 1 | let test: Test = serde_json::from_str(include_str!("./test-fixture.json")).unwrap(); |
32 | 1 | |
33 | 1 | let runtime = executor::host::HostVmPrototype::new(executor::host::Config { |
34 | 1 | module: hex::decode(&test.runtime_code).unwrap(), |
35 | 1 | heap_pages: executor::DEFAULT_HEAP_PAGES, |
36 | 1 | allow_unresolved_imports: true, |
37 | 1 | exec_hint: executor::vm::ExecHint::ExecuteOnceWithNonDeterministicValidation, |
38 | 1 | }) |
39 | 1 | .unwrap(); |
40 | 1 | |
41 | 1 | let call_proof = proof_decode::decode_and_verify_proof(proof_decode::Config { |
42 | 1 | proof: hex::decode(&test.call_proof).unwrap(), |
43 | 1 | }) |
44 | 1 | .unwrap(); |
45 | 1 | |
46 | 1 | let scale_encoded_header = hex::decode(test.block_header).unwrap(); |
47 | 1 | |
48 | 1 | let main_trie_root = header::decode(&scale_encoded_header, 4).unwrap().state_root; |
49 | 1 | |
50 | 1 | let mut validation_in_progress = runtime_call::run(runtime_call::Config { |
51 | 1 | virtual_machine: runtime, |
52 | 1 | function_to_call: super::VALIDATION_FUNCTION_NAME, |
53 | 1 | parameter: super::validate_transaction_runtime_parameters_v3( |
54 | 1 | iter::once(&hex::decode(test.transaction_bytes).unwrap()), |
55 | 1 | super::TransactionSource::External, |
56 | 1 | &header::hash_from_scale_encoded_header(&scale_encoded_header), |
57 | 1 | ), |
58 | 1 | storage_proof_size_behavior: |
59 | 1 | runtime_call::StorageProofSizeBehavior::proof_recording_disabled(), |
60 | 1 | storage_main_trie_changes: Default::default(), |
61 | 1 | max_log_level: 0, |
62 | 1 | calculate_trie_changes: false, |
63 | 1 | }) |
64 | 1 | .unwrap(); |
65 | | |
66 | | loop { |
67 | 1 | match validation_in_progress { |
68 | 1 | runtime_call::RuntimeCall::Finished(Ok(_)) => return, // Success, |
69 | 0 | runtime_call::RuntimeCall::Finished(Err(_)) => panic!(), |
70 | 15 | runtime_call::RuntimeCall::StorageGet(get) => { |
71 | 15 | let value = call_proof |
72 | 15 | .storage_value(main_trie_root, get.key().as_ref()) |
73 | 15 | .unwrap(); |
74 | 15 | validation_in_progress = |
75 | 15 | get.inject_value(value.map(|(val, ver)| (iter::once(val), ver)14 )); |
76 | 15 | } |
77 | 0 | runtime_call::RuntimeCall::NextKey(nk) => { |
78 | 0 | let next_key = call_proof |
79 | 0 | .next_key( |
80 | 0 | main_trie_root, |
81 | 0 | nk.key(), |
82 | 0 | nk.or_equal(), |
83 | 0 | nk.prefix(), |
84 | 0 | nk.branch_nodes(), |
85 | 0 | ) |
86 | 0 | .unwrap(); |
87 | 0 | validation_in_progress = nk.inject_key(next_key); |
88 | 0 | } |
89 | 0 | runtime_call::RuntimeCall::ClosestDescendantMerkleValue(mv) => { |
90 | 0 | let value = call_proof |
91 | 0 | .closest_descendant_merkle_value(main_trie_root, mv.key()) |
92 | 0 | .unwrap(); |
93 | 0 | validation_in_progress = mv.inject_merkle_value(value); |
94 | 0 | } |
95 | 1 | runtime_call::RuntimeCall::SignatureVerification(r) => { |
96 | 1 | validation_in_progress = r.verify_and_resume() |
97 | | } |
98 | 0 | runtime_call::RuntimeCall::LogEmit(r) => validation_in_progress = r.resume(), |
99 | 0 | runtime_call::RuntimeCall::OffchainStorageSet(r) => validation_in_progress = r.resume(), |
100 | 0 | runtime_call::RuntimeCall::Offchain(_) => panic!(), |
101 | | } |
102 | | } |
103 | 1 | } |
104 | | |
105 | | // Serde structs used to decode the test fixtures. |
106 | | |
107 | 9 | #[derive(s5 erde::Deserialize)] _RINvXs_NvXNvNtNtNtCsN16ciHI6Qf_7smoldot12transactions8validate5tests1__NtBa_4TestNtNtCsf0yC2YK6bpM_5serde2de11Deserialize11deserializeNtB5_7___FieldB1h_11deserializeINtNtCscu7pqq74Vb8_10serde_json2de6MapKeyNtNtB2I_4read7StrReadEEBg_ Line | Count | Source | 107 | 4 | #[derive(serde::Deserialize)] |
Unexecuted instantiation: _RINvXs0_NvXNvNtNtNtCsN16ciHI6Qf_7smoldot12transactions8validate5tests1__NtBb_4TestNtNtCsf0yC2YK6bpM_5serde2de11Deserialize11deserializeNtB6_9___VisitorNtB1k_7Visitor9visit_seqINtNtCscu7pqq74Vb8_10serde_json2de9SeqAccessNtNtB2S_4read7StrReadEEBh_ _RINvXs0_NvXNvNtNtNtCsN16ciHI6Qf_7smoldot12transactions8validate5tests1__NtBb_4TestNtNtCsf0yC2YK6bpM_5serde2de11Deserialize11deserializeNtB6_9___VisitorNtB1k_7Visitor9visit_mapINtNtCscu7pqq74Vb8_10serde_json2de9MapAccessNtNtB2S_4read7StrReadEEBh_ Line | Count | Source | 107 | 5 | #[derive(s1 erde::Deserialize)] |
_RINvXNvXNvNtNtNtCsN16ciHI6Qf_7smoldot12transactions8validate5tests1__NtB8_4TestNtNtCsf0yC2YK6bpM_5serde2de11Deserialize11deserializeNtB3_14___FieldVisitorNtB1h_7Visitor9visit_strNtNtCscu7pqq74Vb8_10serde_json5error5ErrorEBe_ Line | Count | Source | 107 | 4 | #[derive(serde::Deserialize)] |
Unexecuted instantiation: _RNvXs0_NvXNvNtNtNtCsN16ciHI6Qf_7smoldot12transactions8validate5tests1__NtBa_4TestNtNtCsf0yC2YK6bpM_5serde2de11Deserialize11deserializeNtB5_9___VisitorNtB1j_7Visitor9expecting Unexecuted instantiation: _RNvXNvXNvNtNtNtCsN16ciHI6Qf_7smoldot12transactions8validate5tests1__NtB7_4TestNtNtCsf0yC2YK6bpM_5serde2de11Deserialize11deserializeNtB2_14___FieldVisitorNtB1g_7Visitor9expecting Unexecuted instantiation: _RINvXNvXNvNtNtNtCsN16ciHI6Qf_7smoldot12transactions8validate5tests1__NtB8_4TestNtNtCsf0yC2YK6bpM_5serde2de11Deserialize11deserializeNtB3_14___FieldVisitorNtB1h_7Visitor9visit_u64pEBe_ Unexecuted instantiation: _RINvXNvXNvNtNtNtCsN16ciHI6Qf_7smoldot12transactions8validate5tests1__NtB8_4TestNtNtCsf0yC2YK6bpM_5serde2de11Deserialize11deserializeNtB3_14___FieldVisitorNtB1h_7Visitor11visit_bytespEBe_ |
108 | | struct Test { |
109 | | #[serde(rename = "transactionBytes")] |
110 | | transaction_bytes: String, |
111 | | #[serde(rename = "runtimeCode")] |
112 | | runtime_code: String, |
113 | | #[serde(rename = "callProof")] |
114 | | call_proof: String, |
115 | | #[serde(rename = "blockHeader")] |
116 | | block_header: String, |
117 | | } |