Skip to content

Commit 88a15ee

Browse files
authored
Add functions for op_return (#22)
* added functions for op_return; added run_with_op_return to helpers * fixed todo * added documentation for op_return functions
1 parent 685aa01 commit 88a15ee

4 files changed

Lines changed: 216 additions & 13 deletions

File tree

simf/lib/op_return.simf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// Returns true if the specified output is an OP_RETURN (null data) output
2+
pub fn is_output_op_return(output_index: u32) -> bool {
3+
match jet::output_null_datum(output_index, 0) {
4+
Some(entry: Option<Either<(u2, u256), Either<u1, u4>>>) => true,
5+
None => false,
6+
}
7+
}
8+
9+
/// Asserts that the specified output is an OP_RETURN (null data) output
10+
pub fn assert_output_is_op_return(output_index: u32) {
11+
assert!(is_output_op_return(output_index));
12+
}

simf/op_return_test.simf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::lib::op_return::{is_output_op_return, assert_output_is_op_return};
2+
use crate::helper::{if_test_this_function, assert_bool};
3+
4+
fn main() {
5+
let fn_idx: u8 = witness::FUNCTION_INDEX;
6+
7+
let index: u32 = witness::INDEX;
8+
let expected: bool = witness::EXPECTED;
9+
10+
match if_test_this_function(0, fn_idx) { true => { assert_bool(is_output_op_return(index), expected); }, false => (), };
11+
match if_test_this_function(1, fn_idx) { true => { assert_output_is_op_return(index); }, false => (), };
12+
}

tests/common/core.rs

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
use simplex::program::{Program, WitnessTrait};
66
use simplex::simplicityhl::elements::Script;
7-
use simplex::transaction::{FinalTransaction, PartialInput, ProgramInput, RequiredSignature};
7+
use simplex::transaction::{
8+
FinalTransaction, PartialInput, PartialOutput, ProgramInput, RequiredSignature,
9+
};
810

911
#[derive(Clone, Copy)]
1012
pub enum Expect {
@@ -41,13 +43,14 @@ pub fn fund(
4143
Ok(script)
4244
}
4345

44-
/// Spend the funded UTXO with `witness`. Returns the broadcast result.
45-
pub fn spend<W>(
46+
/// Construct the funded UTXO with `witness`.
47+
pub fn construct_final_tx<W>(
4648
context: &simplex::TestContext,
4749
program: &impl AsRef<Program>,
4850
script: &Script,
4951
witness: W,
50-
) -> anyhow::Result<String>
52+
data: Option<&[u8]>,
53+
) -> anyhow::Result<FinalTransaction>
5154
where
5255
W: WitnessTrait + 'static,
5356
{
@@ -62,22 +65,34 @@ where
6265
RequiredSignature::None,
6366
);
6467

65-
Ok(context.get_default_signer().broadcast(&ft)?.to_string())
68+
if let Some(data) = data {
69+
ft.add_output(PartialOutput::new_metadata(data))
70+
};
71+
72+
Ok(ft)
6673
}
6774

68-
/// Fund + spend + assert the outcome.
69-
pub fn run<W>(
75+
/// Spend the funded UTXO with `witness`. Return the broadcast result.
76+
pub fn spend<W>(
7077
context: &simplex::TestContext,
71-
program: impl AsRef<Program>,
78+
program: &impl AsRef<Program>,
79+
script: &Script,
7280
witness: W,
73-
expect: Expect,
74-
) -> anyhow::Result<()>
81+
data: Option<&[u8]>,
82+
) -> anyhow::Result<String>
7583
where
7684
W: WitnessTrait + 'static,
7785
{
78-
let script = fund(context, &program)?;
79-
let result = spend(context, &program, &script, witness);
86+
let ft = construct_final_tx(context, program, script, witness, data)?;
87+
88+
Ok(context.get_default_signer().broadcast(&ft)?.to_string())
89+
}
8090

91+
/// Assert that the test result is as expected.
92+
pub fn assert_error_msg(
93+
result: Result<String, anyhow::Error>,
94+
expect: Expect,
95+
) -> anyhow::Result<()> {
8196
match expect.error_message() {
8297
None => {
8398
result?;
@@ -88,7 +103,41 @@ where
88103
.to_string();
89104
assert!(err.contains(expected));
90105
}
91-
}
106+
};
92107

93108
Ok(())
94109
}
110+
111+
/// Fund + spend + assert the outcome.
112+
pub fn run<W>(
113+
context: &simplex::TestContext,
114+
program: impl AsRef<Program>,
115+
witness: W,
116+
expect: Expect,
117+
) -> anyhow::Result<()>
118+
where
119+
W: WitnessTrait + 'static,
120+
{
121+
let script = fund(context, &program)?;
122+
let result = spend(context, &program, &script, witness, None);
123+
124+
assert_error_msg(result, expect)
125+
}
126+
127+
/// Fund + spend + assert the outcome.
128+
/// Tx has OP_RETURN data metadata output
129+
pub fn run_with_op_return<W>(
130+
context: &simplex::TestContext,
131+
program: impl AsRef<Program>,
132+
witness: W,
133+
expect: Expect,
134+
data: &[u8],
135+
) -> anyhow::Result<()>
136+
where
137+
W: WitnessTrait + 'static,
138+
{
139+
let script = fund(context, &program)?;
140+
let result = spend(context, &program, &script, witness, Some(data));
141+
142+
assert_error_msg(result, expect)
143+
}

tests/op_return_test.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
mod common;
2+
3+
use rand::Rng;
4+
5+
use crate::common::core::{run, run_with_op_return};
6+
use common::core::Expect;
7+
8+
use simplicityhl_std::artifacts::op_return_test::OpReturnTestProgram;
9+
use simplicityhl_std::artifacts::op_return_test::derived_op_return_test::{
10+
OpReturnTestArguments, OpReturnTestWitness,
11+
};
12+
13+
enum FunctionToTest {
14+
IsOpReturn,
15+
AssertOutputIsOpReturn,
16+
}
17+
18+
#[inline]
19+
fn op(o: FunctionToTest) -> u8 {
20+
o as u8
21+
}
22+
23+
const DEFAULT_BOOL: bool = false;
24+
const DEFAULT_DATA: &[u8; 1] = &[1];
25+
26+
fn program() -> OpReturnTestProgram {
27+
OpReturnTestProgram::new(OpReturnTestArguments {})
28+
}
29+
30+
fn build_witness(function: u8, index: u32, expected: bool) -> OpReturnTestWitness {
31+
OpReturnTestWitness {
32+
function_index: function,
33+
index,
34+
expected,
35+
}
36+
}
37+
38+
mod op_return_tests {
39+
use super::*;
40+
41+
#[simplex::test]
42+
fn is_output_op_return_true(context: simplex::TestContext) -> anyhow::Result<()> {
43+
let index = 0;
44+
45+
run_with_op_return(
46+
&context,
47+
program(),
48+
build_witness(op(FunctionToTest::IsOpReturn), index, true),
49+
Expect::Ok,
50+
DEFAULT_DATA,
51+
)
52+
}
53+
54+
#[simplex::test]
55+
fn is_output_op_return_empty_index_false(context: simplex::TestContext) -> anyhow::Result<()> {
56+
let index = rand::thread_rng().gen_range(1..=u32::MAX);
57+
58+
run_with_op_return(
59+
&context,
60+
program(),
61+
build_witness(op(FunctionToTest::IsOpReturn), index, false),
62+
Expect::Ok,
63+
DEFAULT_DATA,
64+
)
65+
}
66+
67+
#[simplex::test]
68+
fn is_output_op_return_false(context: simplex::TestContext) -> anyhow::Result<()> {
69+
let index = 0;
70+
71+
run(
72+
&context,
73+
program(),
74+
build_witness(op(FunctionToTest::IsOpReturn), index, false),
75+
Expect::Ok,
76+
)
77+
}
78+
79+
#[simplex::test]
80+
fn assert_output_is_op_return_pass(context: simplex::TestContext) -> anyhow::Result<()> {
81+
let index = 0;
82+
83+
run_with_op_return(
84+
&context,
85+
program(),
86+
build_witness(
87+
op(FunctionToTest::AssertOutputIsOpReturn),
88+
index,
89+
DEFAULT_BOOL,
90+
),
91+
Expect::Ok,
92+
DEFAULT_DATA,
93+
)
94+
}
95+
96+
#[simplex::test]
97+
fn assert_output_is_op_return_empty_index_fail(
98+
context: simplex::TestContext,
99+
) -> anyhow::Result<()> {
100+
let index = rand::thread_rng().gen_range(1..=u32::MAX);
101+
102+
run_with_op_return(
103+
&context,
104+
program(),
105+
build_witness(
106+
op(FunctionToTest::AssertOutputIsOpReturn),
107+
index,
108+
DEFAULT_BOOL,
109+
),
110+
Expect::AssertFailed,
111+
DEFAULT_DATA,
112+
)
113+
}
114+
115+
#[simplex::test]
116+
fn assert_output_is_op_return_fail(context: simplex::TestContext) -> anyhow::Result<()> {
117+
let index = 0;
118+
119+
run(
120+
&context,
121+
program(),
122+
build_witness(
123+
op(FunctionToTest::AssertOutputIsOpReturn),
124+
index,
125+
DEFAULT_BOOL,
126+
),
127+
Expect::AssertFailed,
128+
)
129+
}
130+
}

0 commit comments

Comments
 (0)