Coverage Report

Created: 2025-07-01 09:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/__w/smoldot/smoldot/repo/lib/src/transactions/validate/tests.rs
Line
Count
Source
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
    // Regression test for <https://github.com/smol-dot/smoldot/issues/873>.
30
31
1
    let test: Test = serde_json::from_str(include_str!("./test-fixture.json")).unwrap();
32
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
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
46
1
    let scale_encoded_header = hex::decode(test.block_header).unwrap();
47
48
1
    let main_trie_root = header::decode(&scale_encoded_header, 4).unwrap().state_root;
49
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::once14
(
val14
),
ver14
)));
76
            }
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
#[derive(serde::Deserialize)]
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
}