Skip to content
This repository was archived by the owner on Apr 8, 2022. It is now read-only.

Commit 53a235e

Browse files
committed
script: Add some exhaustive testing
1 parent 0bc1e88 commit 53a235e

File tree

7 files changed

+65
-4
lines changed

7 files changed

+65
-4
lines changed

Cargo.lock

+4-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

libs/chainscript/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ frame-support = { default-features = false, version = '4.0.0-dev', git = 'https:
2727

2828
[dev-dependencies]
2929
# serde = '1.0.119'
30+
flate2 = "1.0.22"
31+
hex = '0.4.3'
3032
hex-literal = "0.3.1"
3133
proptest = "1.0.0"
3234

libs/chainscript/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ mod interpreter;
5757
pub mod opcodes;
5858
pub mod script;
5959
pub mod sighash;
60+
#[cfg(test)]
61+
mod test;
6062

6163
#[cfg(feature = "testcontext")]
6264
pub use context::testcontext::TestContext;

libs/chainscript/src/test/mod.rs

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use crate::*;
2+
3+
// Test the interpreter on all 4-byte combinations of non-trivial opcodes.
4+
#[test]
5+
//#[ignore = "This test is too expensive to run by default"]
6+
fn test_4opc_sequences() {
7+
use hex::FromHex;
8+
use std::io::{BufRead, BufReader};
9+
10+
// The test vectors are encoded in a gzipped CSV file.
11+
// Each line in the file is has the following comma-separated filelds:
12+
// 1) The hex-encoded bitcoin script
13+
// 2) The expected outcome, which is either 0 (script should fail) or 1 (script should succceed)
14+
// 3) If the expected outcome is 1 (success), then a sequence of comma-separated hex-encoded
15+
// stack items after the execution of the script follows.
16+
//
17+
// The test vectors were obtained obtained by running the script interpreter in Tapscript mode
18+
// on all 4-opcode sequences of a subset of opcodes. Notable omissions include:
19+
// * `OP_NOP_N`, `OP_SUCCESS_N`: These are trivial and including them would make the file much
20+
// larger (and test run time much longer) with little benefit.
21+
// * Opcodes dealing with checking signatures: These behave differently in Bitcoin.
22+
// * `OP_PUSHDATA_N`: Some these should be included in the future here or in a separate test.
23+
let test_vectors_raw = include_bytes!("test_vectors_4opc.csv.gz").as_ref();
24+
let test_vectors = BufReader::new(flate2::bufread::GzDecoder::new(test_vectors_raw));
25+
26+
let mut fails = 0u32;
27+
for line in test_vectors.lines().map(|l| l.expect("can't get a line")) {
28+
let mut parts = line.split(',');
29+
// Load the script.
30+
let script: Script = Vec::from_hex(parts.next().expect("no script"))
31+
.expect("script not in hex format")
32+
.into();
33+
34+
// Load the expected outcome. It should be either 0, or 1 followed by stack items.
35+
let expected: Option<Stack> = match parts.next().expect("no desired outcome") {
36+
"0" => None,
37+
"1" => {
38+
// For successful outcome, read the expected sequence of items on the stack
39+
let stack: Vec<_> =
40+
parts.map(|s| Vec::from_hex(s).expect("hex item").into()).collect();
41+
Some(stack.into())
42+
}
43+
_ => unreachable!("bad format"),
44+
};
45+
46+
// Run the script and record mismatches between expected and actual outputs.
47+
let result = run_script(&TestContext::default(), &script, vec![].into()).ok();
48+
if expected != result {
49+
eprintln!("FAIL {:?}: {:?} vs. {:?}", script, result, expected);
50+
fails += 1;
51+
}
52+
}
53+
54+
// Let the test fail if we have at least one mismatch.
55+
assert!(fails == 0, "{} tests failed", fails);
56+
}
Binary file not shown.

pallets/utxo/src/script.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ pub(crate) mod test {
166166
use super::*;
167167
use chainscript::Context;
168168
use core::time::Duration;
169-
use sp_core::sr25519;
170169
use proptest::prelude::*;
170+
use sp_core::sr25519;
171171

172172
// Generate block time in seconds
173173
pub fn gen_block_time_real() -> impl Strategy<Value = RawBlockTime> {

pallets/utxo/src/tests.rs

-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use frame_support::{
2626
sp_io::crypto,
2727
sp_runtime::traits::{BlakeTwo256, Hash},
2828
};
29-
3029
use crate::script::test::gen_block_time_real;
3130
use crate::tokens::OutputData;
3231
use proptest::prelude::*;

0 commit comments

Comments
 (0)