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

script: Add some exhaustive testing #124

Open
wants to merge 1 commit into
base: staging
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions libs/chainscript/Cargo.toml
Original file line number Diff line number Diff line change
@@ -27,6 +27,8 @@ frame-support = { default-features = false, version = '4.0.0-dev', git = 'https:

[dev-dependencies]
# serde = '1.0.119'
flate2 = "1.0.22"
hex = '0.4.3'
hex-literal = "0.3.1"
proptest = "1.0.0"

2 changes: 2 additions & 0 deletions libs/chainscript/src/lib.rs
Original file line number Diff line number Diff line change
@@ -57,6 +57,8 @@ mod interpreter;
pub mod opcodes;
pub mod script;
pub mod sighash;
#[cfg(test)]
mod test;

#[cfg(feature = "testcontext")]
pub use context::testcontext::TestContext;
56 changes: 56 additions & 0 deletions libs/chainscript/src/test/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use crate::*;

// Test the interpreter on all 4-byte combinations of non-trivial opcodes.
#[test]
//#[ignore = "This test is too expensive to run by default"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to comment the ignore?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. It runs pretty quickly in release mode, but under debug, I will have to measure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running this test with debug build takes 147 seconds on my laptop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we aim for in these tests? Are tests that run a long-ish time under debug acceptable or do we want to disable them by default (make opt-in)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

147s is okay for me but is probably approaching the limit of "I'm getting bored waiting for this"-ness so maybe making them opt-in is a good idea. If someone touches the script stuff then they know to run them anyway so we're probably safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In release mode, it is about 5s on my laptop btw

fn test_4opc_sequences() {
use hex::FromHex;
use std::io::{BufRead, BufReader};

// The test vectors are encoded in a gzipped CSV file.
// Each line in the file is has the following comma-separated filelds:
// 1) The hex-encoded bitcoin script
// 2) The expected outcome, which is either 0 (script should fail) or 1 (script should succceed)
// 3) If the expected outcome is 1 (success), then a sequence of comma-separated hex-encoded
// stack items after the execution of the script follows.
//
// The test vectors were obtained obtained by running the script interpreter in Tapscript mode
// on all 4-opcode sequences of a subset of opcodes. Notable omissions include:
// * `OP_NOP_N`, `OP_SUCCESS_N`: These are trivial and including them would make the file much
// larger (and test run time much longer) with little benefit.
// * Opcodes dealing with checking signatures: These behave differently in Bitcoin.
// * `OP_PUSHDATA_N`: Some these should be included in the future here or in a separate test.
let test_vectors_raw = include_bytes!("test_vectors_4opc.csv.gz").as_ref();
let test_vectors = BufReader::new(flate2::bufread::GzDecoder::new(test_vectors_raw));

let mut fails = 0u32;
for line in test_vectors.lines().map(|l| l.expect("can't get a line")) {
let mut parts = line.split(',');
// Load the script.
let script: Script = Vec::from_hex(parts.next().expect("no script"))
.expect("script not in hex format")
.into();

// Load the expected outcome. It should be either 0, or 1 followed by stack items.
let expected: Option<Stack> = match parts.next().expect("no desired outcome") {
"0" => None,
"1" => {
// For successful outcome, read the expected sequence of items on the stack
let stack: Vec<_> =
parts.map(|s| Vec::from_hex(s).expect("hex item").into()).collect();
Some(stack.into())
}
_ => unreachable!("bad format"),
};

// Run the script and record mismatches between expected and actual outputs.
let result = run_script(&TestContext::default(), &script, vec![].into()).ok();
if expected != result {
eprintln!("FAIL {:?}: {:?} vs. {:?}", script, result, expected);
fails += 1;
}
}

// Let the test fail if we have at least one mismatch.
assert!(fails == 0, "{} tests failed", fails);
}
Binary file not shown.
2 changes: 1 addition & 1 deletion pallets/utxo/src/script.rs
Original file line number Diff line number Diff line change
@@ -166,8 +166,8 @@ pub(crate) mod test {
use super::*;
use chainscript::Context;
use core::time::Duration;
use sp_core::sr25519;
use proptest::prelude::*;
use sp_core::sr25519;

// Generate block time in seconds
pub fn gen_block_time_real() -> impl Strategy<Value = RawBlockTime> {
1 change: 0 additions & 1 deletion pallets/utxo/src/tests.rs
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@ use frame_support::{
sp_io::crypto,
sp_runtime::traits::{BlakeTwo256, Hash},
};

use crate::script::test::gen_block_time_real;
use crate::tokens::OutputData;
use proptest::prelude::*;