1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use crate::sigma_protocol::prover::ContextExtension;
use bounded_vec::BoundedVec;
use ergo_chain_types::{Header, PreHeader};
use ergotree_ir::chain::ergo_box::ErgoBox;
/// BoundedVec type for Tx inputs, output_candidates and outputs
pub type TxIoVec<T> = BoundedVec<T, 1, { i16::MAX as usize }>;
/// Interpreter's context (blockchain state)
#[derive(Debug)]
pub struct Context<'ctx> {
/// Current height
pub height: u32,
/// Box that contains the script we're evaluating (from spending transaction inputs)
pub self_box: &'ctx ErgoBox,
/// Spending transaction outputs
pub outputs: &'ctx [ErgoBox],
/// Spending transaction data inputs
pub data_inputs: Option<TxIoVec<&'ctx ErgoBox>>,
/// Spending transaction inputs
pub inputs: TxIoVec<&'ctx ErgoBox>,
/// Pre header of current block
pub pre_header: PreHeader,
/// Fixed number of last block headers in descending order (first header is the newest one)
pub headers: [Header; 10],
/// prover-defined key-value pairs, that may be used inside a script
pub extension: ContextExtension,
}
impl<'ctx> Context<'ctx> {
/// Return a new Context with given context extension
pub fn with_extension(self, ext: ContextExtension) -> Self {
Context {
extension: ext,
..self
}
}
}
#[cfg(feature = "arbitrary")]
#[allow(clippy::unwrap_used)]
mod arbitrary {
use super::*;
use proptest::{collection::vec, option::of, prelude::*};
impl Arbitrary for Context<'static> {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(
0..i32::MAX as u32,
any::<ErgoBox>(),
vec(any::<ErgoBox>(), 1..3),
vec(any::<ErgoBox>(), 1..3),
of(vec(any::<ErgoBox>(), 1..3)),
any::<PreHeader>(),
any::<ContextExtension>(),
any::<[Header; 10]>(),
)
.prop_map(
|(
height,
self_box,
outputs,
inputs,
data_inputs,
pre_header,
extension,
headers,
)| {
// Leak variables. Since this is only used for testing this is acceptable and avoids introducing a new type (ContextOwned)
Self {
height,
self_box: Box::leak(Box::new(self_box)),
outputs: Vec::leak(outputs),
data_inputs: data_inputs.map(|v| {
v.into_iter()
.map(|i| &*Box::leak(Box::new(i)))
.collect::<Vec<_>>()
.try_into()
.unwrap()
}),
inputs: inputs
.into_iter()
.map(|i| &*Box::leak(Box::new(i)))
.collect::<Vec<_>>()
.try_into()
.unwrap(),
pre_header,
extension,
headers,
}
},
)
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}
}
#[cfg(test)]
mod tests {}