From 423855f7bb093c651d5cd9bc8fa09e91fd8a3865 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Mon, 4 Mar 2024 13:18:47 +0100 Subject: [PATCH 01/28] testing: introduce the crate to help with faking complex types --- clarity/Cargo.toml | 1 + clarity/src/vm/fakes.rs | 1353 ++++++++++++++++++++++++++++ clarity/src/vm/mod.rs | 3 + clarity/src/vm/types/mod.rs | 4 + clarity/src/vm/types/signatures.rs | 12 +- 5 files changed, 1368 insertions(+), 5 deletions(-) create mode 100644 clarity/src/vm/fakes.rs diff --git a/clarity/Cargo.toml b/clarity/Cargo.toml index 4d51cf3e4e..b0452fab93 100644 --- a/clarity/Cargo.toml +++ b/clarity/Cargo.toml @@ -31,6 +31,7 @@ stacks_common = { package = "stacks-common", path = "../stacks-common" } rstest = "0.17.0" rstest_reuse = "0.5.0" hashbrown = { workspace = true } +fake = { version = "2.9.2", features = ["derive"] } [dependencies.serde_json] version = "1.0" diff --git a/clarity/src/vm/fakes.rs b/clarity/src/vm/fakes.rs new file mode 100644 index 0000000000..aa9389ce66 --- /dev/null +++ b/clarity/src/vm/fakes.rs @@ -0,0 +1,1353 @@ +#![allow(non_snake_case)] + +use fake::locales::EN; +use fake::Dummy; +use rand::Rng; +use stacks_common::types::chainstate::StacksAddress; +use stacks_common::types::Address; +use stacks_common::util::hash::Hash160; + +use self::raw::*; + +pub mod raw { + use std::collections::BTreeMap; + use std::sync::atomic::AtomicU32; + + use fake::locales::EN; + use fake::{Dummy, Fake, Faker}; + use hashbrown::HashMap; + use rand::Rng; + + use super::ENGLISH_WORDS; + use crate::vm::representations::Span; + use crate::vm::types::signatures::{CallableSubtype, FunctionArgSignature}; + use crate::vm::types::{ + ASCIIData, BuffData, BufferLength, CharType, FixedFunction, FunctionArg, FunctionSignature, + FunctionType, ListData, ListTypeData, OptionalData, ResponseData, SequenceData, + SequenceSubtype, StandardPrincipalData, StringSubtype, StringUTF8Length, TraitIdentifier, + TupleData, TupleTypeSignature, TypeSignature, UTF8Data, + }; + use crate::vm::{ClarityName, ContractName, SymbolicExpression, SymbolicExpressionType, Value}; + + const MAX_RECURSION_LEVEL: u32 = 1; + + impl Dummy for StandardPrincipalData { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + StandardPrincipalData(1, rng.gen()) + } + } + + pub struct EnglishWord(pub L); + impl Dummy> for &'static str { + fn dummy_with_rng(config: &EnglishWord, rng: &mut R) -> Self { + ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)] + } + } + + impl Dummy> for String { + fn dummy_with_rng(config: &EnglishWord, rng: &mut R) -> Self { + ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)].into() + } + } + + impl Dummy for ClarityName { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + ClarityName::from(ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)]) + } + } + + impl Dummy for ContractName { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + ContractName::from(ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)]) + } + } + + impl Dummy for UTF8Data { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let val = Value::string_utf8_from_string_utf8_literal( + ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)].to_string(), + ) + .expect("failed to fake utf8 string literal"); + + if let Value::Sequence(SequenceData::String(CharType::UTF8(utf8_data))) = val { + utf8_data + } else { + panic!("failed to fake utf8 string literal") + } + } + } + + impl Dummy for ASCIIData { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + ASCIIData { + data: ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)] + .as_bytes() + .to_vec(), + } + } + } + + impl Dummy for TypeSignature { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + random_type_signature(None, rng) + } + } + + fn random_type_signature(level: Option, rng: &mut R) -> TypeSignature { + let next_level = Some(level.unwrap_or_default() + 1); + + let mut signatures = vec![ + TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII( + BufferLength(rng.gen_range(5..50)), + ))), + TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8( + StringUTF8Length(rng.gen_range(5..50)), + ))), + TypeSignature::PrincipalType, + TypeSignature::BoolType, + TypeSignature::IntType, + TypeSignature::UIntType, + TypeSignature::SequenceType(SequenceSubtype::BufferType(BufferLength( + rng.gen_range(50..100), + ))), + TypeSignature::CallableType(CallableSubtype::Principal(Faker.fake())), + TypeSignature::TraitReferenceType(TraitIdentifier { + name: Faker.fake(), + contract_identifier: Faker.fake(), + }), + TypeSignature::ListUnionType( + (0..rng.gen_range(1..3)) + .into_iter() + .map(|_| Faker.fake()) + .collect(), + ), + ]; + + if let Some(level) = level { + if level < MAX_RECURSION_LEVEL { + let mut recursive_signatures = vec![ + TypeSignature::SequenceType(SequenceSubtype::ListType(ListTypeData { + max_len: rng.gen_range(1..5), + entry_type: Box::new(random_type_signature(next_level, rng)), + })), + TypeSignature::OptionalType(Box::new(random_type_signature(next_level, rng))), + TypeSignature::ResponseType(Box::new(( + random_type_signature(next_level, rng), + random_type_signature(next_level, rng), + ))), + TypeSignature::TupleType(TupleTypeSignature { + type_map: (0..rng.gen_range(1..3)) + .map(|_| (Faker.fake(), random_type_signature(next_level, rng))) + .collect(), + }), + ]; + + signatures.append(&mut recursive_signatures); + } + } + + signatures[rng.gen_range(0..signatures.len())].clone() + } + + impl Dummy for SymbolicExpressionType { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + random_symbolic_expression_type(None, rng) + } + } + + fn random_symbolic_expression_type( + level: Option, + rng: &mut R, + ) -> SymbolicExpressionType { + let next_level = Some(level.unwrap_or_default() + 1); + + let mut types = vec![ + SymbolicExpressionType::Atom(Faker.fake()), + SymbolicExpressionType::LiteralValue(random_value(next_level, rng)), + ]; + + if let Some(level) = level { + if level < MAX_RECURSION_LEVEL { + let mut recursive_types = vec![SymbolicExpressionType::List( + (1..rng.gen_range(1..3)) + .into_iter() + .map(|_| Faker.fake()) + .collect(), + )]; + + types.append(&mut recursive_types); + } + } + + types[rng.gen_range(0..types.len())].clone() + } + + impl Dummy for Value { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + random_value(None, rng) + } + } + + fn random_value(level: Option, rng: &mut R) -> Value { + let next_level = Some(level.unwrap_or_default() + 1); + + let mut values = vec![ + Value::Bool(Faker.fake()), + Value::Int(Faker.fake()), + Value::UInt(Faker.fake()), + Value::Principal(Faker.fake()), + Value::CallableContract(Faker.fake()), + ]; + + if let Some(lvl) = level { + if lvl < MAX_RECURSION_LEVEL { + let mut recursive_vals = vec![ + Value::Tuple(TupleData { + data_map: (0..rng.gen_range(1..3)) + .into_iter() + .map(|_| (Faker.fake(), random_value(next_level, rng))) + .collect(), + type_signature: TupleTypeSignature { + type_map: (0..rng.gen_range(1..3)) + .map(|_| (Faker.fake(), random_type_signature(next_level, rng))) + .collect(), + }, + }), + Value::Optional(OptionalData { + data: if level.is_none() { + Some(Box::new(random_value(next_level, rng))) + } else { + None + }, + }), + Value::Response(ResponseData { + committed: Faker.fake(), + data: Box::new(random_value(next_level, rng)), + }), + Value::string_utf8_from_string_utf8_literal( + ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)].to_string(), + ) + .expect("failed to fake utf8 string literal"), + Value::string_ascii_from_bytes( + ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)] + .as_bytes() + .to_vec(), + ) + .expect("failed to fake ascii string literal"), + Value::Sequence(SequenceData::List(ListData { + data: (0..rng.gen_range(1..3)) + .into_iter() + .map(|_| random_value(next_level, rng)) + .collect(), + type_signature: ListTypeData { + max_len: rng.gen_range(1..3), + entry_type: Box::new(random_type_signature(next_level, rng)), + }, + })), + Value::Sequence(SequenceData::Buffer(BuffData { + data: (10..rng.gen_range(20..40)) + .into_iter() + .map(|_| rng.gen()) + .collect(), + })), + ]; + + values.append(&mut recursive_vals); + } + } + + values[rng.gen_range(0..values.len())].clone() + } + + impl Dummy for FunctionSignature { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + FunctionSignature { + args: (0..rng.gen_range(1..3)) + .into_iter() + .map(|_| (random_type_signature(None, rng))) + .collect(), + returns: random_type_signature(None, rng), + } + } + } + + impl Dummy for FixedFunction { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + FixedFunction { + args: (0..rng.gen_range(1..3)) + .into_iter() + .map(|_| Faker.fake()) + .collect(), + returns: random_type_signature(None, rng), + } + } + } + + impl Dummy for FunctionArg { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + FunctionArg { + name: Faker.fake(), + signature: random_type_signature(None, rng), + } + } + } + + impl Dummy for FunctionArgSignature { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let sigs = vec![ + FunctionArgSignature::Union( + (0..rng.gen_range(1..2)) + .into_iter() + .map(|_| random_type_signature(None, rng)) + .collect(), + ), + FunctionArgSignature::Single(random_type_signature(None, rng)), + ]; + + sigs[rng.gen_range(0..sigs.len())].clone() + } + } + + impl Dummy for FunctionType { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let fn_types = vec![ + FunctionType::Fixed(Faker.fake()), + FunctionType::Variadic(Faker.fake(), Faker.fake()), + FunctionType::UnionArgs( + (0..rng.gen_range(1..2)) + .into_iter() + .map(|_| random_type_signature(None, rng)) + .collect(), + random_type_signature(None, rng), + ), + FunctionType::ArithmeticBinary, + FunctionType::ArithmeticUnary, + FunctionType::ArithmeticComparison, + FunctionType::ArithmeticVariadic, + FunctionType::Binary(Faker.fake(), Faker.fake(), Faker.fake()), + ]; + + fn_types[rng.gen_range(0..fn_types.len())].clone() + } + } + + impl Dummy for SymbolicExpression { + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + SymbolicExpression { + expr: random_symbolic_expression_type(None, rng), + id: rng.gen(), + #[cfg(feature = "developer-mode")] + end_line_comment: None, + #[cfg(feature = "developer-mode")] + span: Span::zero(), + #[cfg(feature = "developer-mode")] + post_comments: Default::default(), + #[cfg(feature = "developer-mode")] + pre_comments: Default::default(), + } + } + } +} + +const ENGLISH_WORDS: &'static [&'static str] = &[ + "glancing", + "gwaith", + "defines", + "panel", + "manitowoc", + "uspto", + "iseries", + "cations", + "create", + "harms", + "columbian", + "moonlight", + "fansite", + "pomegranate", + "lynnwood", + "finalist", + "survivor", + "veggie", + "haymarket", + "certainly", + "lubricant", + "guarded", + "challenges", + "pelican", + "heidegger", + "puccini", + "louisa", + "newsday", + "subjects", + "dances", + "mutex", + "apathy", + "rhodium", + "tumbled", + "takers", + "incline", + "screenshots", + "gangbangs", + "curled", + "orchestral", + "nerve", + "maude", + "cassettes", + "sonne", + "cried", + "shops", + "plantar", + "confirming", + "intestinal", + "nosed", + "waistband", + "prosecutor", + "newborns", + "cupcakes", + "crisis", + "travail", + "heaton", + "edgewood", + "diazepam", + "yahoogroups", + "implicit", + "endpoints", + "unequivocally", + "abilene", + "idiom", + "larynx", + "caloric", + "datagrams", + "alphabets", + "belcher", + "alright", + "assist", + "petitioned", + "mortimer", + "ruled", + "congruent", + "thankful", + "goulburn", + "reset", + "cornell", + "launchers", + "sovereignty", + "landers", + "mediums", + "limitation", + "appreciates", + "workstation", + "preparations", + "decimation", + "relocate", + "remembrance", + "discoverer", + "overriding", + "person", + "dudes", + "authenticate", + "researchers", + "native", + "northerly", + "tablatures", + "thanh", + "kiowa", + "kaplan", + "cooke", + "buckles", + "schoolgirls", + "capitalizing", + "brdrnone", + "artest", + "motorized", + "daniela", + "scrolling", + "squaretrade", + "fahrenheit", + "putters", + "runoff", + "taranaki", + "lexical", + "beginners", + "emeritus", + "artistry", + "fulfills", + "taxable", + "weakens", + "choline", + "workplace", + "sumitomo", + "glues", + "spake", + "camshaft", + "satellite", + "tougher", + "tahitian", + "withdraws", + "mistaken", + "glutamine", + "midst", + "adelaide", + "demeter", + "slightly", + "discusses", + "theatrical", + "routine", + "scare", + "awareness", + "counselors", + "vented", + "covered", + "shale", + "downstairs", + "commodores", + "dimensionname", + "brothel", + "declination", + "things", + "randy", + "suggesting", + "burdens", + "spartan", + "padre", + "adirondack", + "zacks", + "alvarez", + "neutrino", + "hessen", + "decimals", + "crafts", + "rocklin", + "suture", + "stakeholders", + "finalizing", + "fireworks", + "constructed", + "perfumed", + "sparked", + "anydvd", + "originality", + "interrupted", + "certs", + "multipliers", + "visualization", + "newlines", + "accueil", + "moment", + "leagues", + "capitalists", + "staffordshire", + "appellees", + "witches", + "alpaca", + "ahora", + "altitudes", + "stinger", + "avanti", + "catfish", + "shakur", + "trying", + "suburbia", + "maximilian", + "optometrists", + "overtime", + "domicile", + "spouses", + "hoyer", + "gracefully", + "searched", + "croupier", + "obscured", + "newsroom", + "streams", + "torrie", + "unproven", + "significantly", + "downloaden", + "heifer", + "bumble", + "wizard", + "deerfield", + "abysmal", + "shenyang", + "bunch", + "resale", + "delegation", + "indepth", + "powerseller", + "doped", + "davids", + "wilkins", + "blockbuster", + "postponed", + "pueblo", + "pence", + "blight", + "bastille", + "demanding", + "lifedrive", + "dilated", + "spheres", + "decreased", + "kagan", + "savor", + "sticky", + "homeschooling", + "teachings", + "sudanese", + "tapestry", + "statutory", + "parkersburg", + "declaration", + "concatenation", + "tacacs", + "incomparable", + "emigrants", + "ullman", + "playa", + "cardiopulmonary", + "slows", + "washes", + "rayburn", + "sagan", + "webbing", + "glass", + "kathy", + "screenings", + "stamina", + "dramas", + "jordans", + "fixings", + "alongside", + "apnea", + "choreography", + "counters", + "loire", + "silvio", + "lighters", + "disadvantage", + "kentucky", + "levine", + "hodge", + "eigen", + "buffets", + "bookseller", + "shiki", + "disqualify", + "distinctions", + "wheelers", + "dominique", + "etoile", + "inside", + "bookshelf", + "cranial", + "cessation", + "hydrographic", + "doctrinal", + "tankers", + "pickett", + "obliged", + "united", + "papua", + "darnell", + "dominica", + "apotheon", + "johnstown", + "forzieri", + "martens", + "armoured", + "mckean", + "centrifugal", + "avalanche", + "customs", + "gilmour", + "pharm", + "trajectory", + "lipoprotein", + "fomit", + "flush", + "dissatisfaction", + "facial", + "glitches", + "bookshot", + "patten", + "behaviors", + "adjacency", + "quadrangle", + "autoconf", + "countenance", + "sperm", + "jetblue", + "craven", + "genera", + "uclibc", + "optional", + "maritime", + "biloxi", + "gareth", + "camberley", + "aerodynamics", + "tomlin", + "compton", + "replicating", + "unlicensed", + "mongolia", + "shelter", + "trois", + "executable", + "danes", + "unlimited", + "nogroup", + "specificity", + "mercedes", + "oswald", + "larnaca", + "middleton", + "chatboard", + "uncovered", + "regal", + "costing", + "compasses", + "chart", + "separated", + "aligning", + "raster", + "concurrently", + "francesca", + "fittings", + "coopers", + "potters", + "technologist", + "washington", + "leiter", + "perfected", + "burying", + "strict", + "therefrom", + "freezer", + "souvenirs", + "interdependent", + "herrick", + "palais", + "brianna", + "juneau", + "edina", + "folate", + "remus", + "manilow", + "abdul", + "accepts", + "payday", + "pussycat", + "relativism", + "mandatory", + "cashing", + "kinder", + "pornos", + "stops", + "material", + "bigalow", + "plainly", + "perpetuate", + "flammability", + "astor", + "cairns", + "romance", + "mathias", + "distro", + "mackinac", + "meeks", + "multilayer", + "reproduction", + "broom", + "retailers", + "dunlop", + "blower", + "mooring", + "rhoda", + "phyto", + "bechtel", + "medalist", + "stipulate", + "restriction", + "leominster", + "regulating", + "assortment", + "complicity", + "holding", + "equinox", + "instructors", + "boland", + "ciprofloxacin", + "desoto", + "sucker", + "managment", + "guiana", + "starfleet", + "shout", + "disclosed", + "leningrad", + "useable", + "enotes", + "carpool", + "cherries", + "venous", + "hannah", + "suicides", + "toolkit", + "earnings", + "herder", + "halting", + "mehmet", + "shallow", + "astonishing", + "mollie", + "decoration", + "slowly", + "ioffer", + "messageboards", + "breaks", + "snipe", + "agencies", + "danger", + "boiler", + "jewelry", + "multiplexing", + "bianco", + "threatened", + "inhabitants", + "planar", + "brownfield", + "epinephrine", + "chopard", + "modifiers", + "pseudomonas", + "crafting", + "endpoint", + "rhododendron", + "phosphorylation", + "declared", + "artist", + "breathless", + "measures", + "limitations", + "grassley", + "cerritos", + "americana", + "premierguide", + "peruvian", + "marla", + "creatively", + "letzte", + "tabasco", + "reykjavik", + "centrist", + "liste", + "deuteronomy", + "babydoll", + "angie", + "commodity", + "morten", + "circulars", + "emperor", + "meridian", + "gecko", + "parti", + "revamp", + "convene", + "share", + "decree", + "littered", + "varieties", + "culvert", + "carta", + "contention", + "diffuser", + "philosophies", + "socialism", + "morrell", + "institutional", + "administrations", + "seize", + "macleod", + "irradiated", + "turnovr", + "federations", + "affaires", + "diameters", + "sensuous", + "madness", + "philanthropy", + "substr", + "cerruti", + "amstrad", + "gulfstream", + "transposition", + "parlour", + "fleet", + "sounded", + "beech", + "anglesey", + "regulators", + "intellectually", + "reiterated", + "stirling", + "knockout", + "allow", + "implantation", + "tingling", + "abstain", + "soundboard", + "mcalester", + "disassembly", + "catered", + "officejet", + "agreed", + "grievous", + "slated", + "octane", + "adventurers", + "thirteenth", + "molto", + "peacekeepers", + "provocative", + "tournament", + "caching", + "reasonableness", + "aneurysm", + "groundwork", + "salvatore", + "narayan", + "conventionally", + "itasca", + "techie", + "roscommon", + "jossey", + "interlude", + "kravitz", + "goings", + "parenting", + "founding", + "vegetation", + "showers", + "cities", + "chewable", + "condi", + "lookups", + "flashes", + "zydeco", + "pandas", + "ministers", + "beasty", + "inventors", + "londonderry", + "driver", + "freshest", + "jscript", + "lends", + "cowboys", + "stopping", + "doanh", + "militia", + "frankly", + "sensei", + "these", + "gandalf", + "meditation", + "spell", + "quasar", + "lugano", + "selectively", + "garnish", + "impartial", + "gilberto", + "collie", + "subcommittee", + "milestone", + "originators", + "swimwear", + "clint", + "dieser", + "profess", + "transsexual", + "myspace", + "gwendolyn", + "oppose", + "cypher", + "commit", + "flood", + "baroque", + "augustin", + "quicksearch", + "transylvania", + "roots", + "happen", + "informationhide", + "frazier", + "foreseen", + "recycle", + "electrics", + "unrelated", + "knicks", + "sedation", + "italians", + "thrive", + "rectory", + "dungeon", + "racquet", + "paraiso", + "alumnus", + "shorts", + "softening", + "uplink", + "theorists", + "cubes", + "ecampus", + "arrives", + "adipose", + "ultralight", + "barricades", + "transparencies", + "cites", + "landings", + "broderick", + "fifths", + "racking", + "graduate", + "gauteng", + "tained", + "crosby", + "coated", + "nance", + "furman", + "careerbuilder", + "magnetics", + "bleeds", + "quickest", + "peptidase", + "woody", + "amara", + "windscreen", + "greyhounds", + "mastering", + "clauses", + "atrios", + "neurology", + "proton", + "conseil", + "katja", + "offbeat", + "antagonists", + "unfpa", + "conduction", + "nieuw", + "slept", + "inositol", + "cheeses", + "akita", + "beverly", + "behaving", + "reserved", + "developmentally", + "curiosities", + "bayes", + "moorings", + "osgood", + "azres", + "veranda", + "mhonarc", + "festival", + "cartwright", + "filigree", + "helical", + "fluids", + "dorchester", + "carbine", + "shortly", + "thrusting", + "villeneuve", + "willem", + "guardia", + "cortisol", + "defibrillators", + "malta", + "marigold", + "twofold", + "assigned", + "feeble", + "gateshead", + "harcore", + "determinations", + "approximations", + "kites", + "rollins", + "mpltext", + "militaria", + "circulation", + "diabetics", + "coexistence", + "dominguez", + "ellyn", + "subcellular", + "villages", + "cautious", + "diagnosing", + "reassurance", + "diligence", + "tokyo", + "apacer", + "scratch", + "tooled", + "catagory", + "sumptuous", + "covalent", + "surgery", + "magazin", + "enjoying", + "criminal", + "preowned", + "cornwall", + "conversions", + "attire", + "masterbation", + "johnston", + "amarillo", + "lifehouse", + "applescript", + "coldwell", + "mating", + "plate", + "idyllic", + "cobalt", + "appear", + "knitting", + "alluvial", + "trainees", + "membrane", + "famous", + "overtly", + "rumble", + "multiplying", + "amour", + "mixtures", + "rubies", + "mascot", + "waits", + "calypso", + "dissociation", + "acknowledges", + "calabasas", + "selangor", + "staggering", + "horton", + "sevilla", + "zyxel", + "rebounding", + "dremel", + "ruling", + "restricts", + "salon", + "ruined", + "supermodels", + "evaluates", + "reforming", + "worden", + "undesirable", + "artista", + "englishman", + "transdermal", + "sally", + "doris", + "baits", + "reinforce", + "internets", + "readings", + "neutrons", + "donde", + "convened", + "brodie", + "mohan", + "nailing", + "normally", + "aristocrats", + "father", + "longwood", + "dreamweaver", + "bowels", + "quando", + "solves", + "expenses", + "appealing", + "knowit", + "jeeves", + "provided", + "spanking", + "caldera", + "kronos", + "hookers", + "rulemaking", + "tuscan", + "psychiatric", + "retails", + "horny", + "announcer", + "calvary", + "skaters", + "pimpin", + "cairn", + "wayne", + "shave", + "genealogy", + "titusville", + "equator", + "unicorn", + "pickabook", + "reservations", + "bottomed", + "meilleurs", + "intraday", + "hemoglobin", + "construed", + "intrusion", + "internat", + "mcmullen", + "epcot", + "iraqi", + "patrolling", + "murad", + "geographic", + "ecnext", + "toughness", + "steiner", + "musicals", + "micronesia", + "grantham", + "physicists", + "gratuit", + "inhabit", + "carter", + "shimizu", + "forcefully", + "batters", + "mcelroy", + "prefered", + "crickets", + "hatfield", + "buisness", + "deputy", + "disclosure", + "emulators", + "undertook", + "myths", + "grisham", + "lovely", + "postcards", + "blackfoot", + "knoll", + "gritty", + "suppressing", + "willard", + "slipping", + "morrisville", + "cynical", + "constitution", + "avenida", + "sociale", + "liguria", + "horrendous", + "behav", + "storefront", + "brought", + "irritability", + "neuroblastoma", + "torrent", + "bedlam", + "titled", + "topic", + "automakers", + "behemoth", + "popping", + "cobbler", + "warhead", + "emissions", + "handwritten", + "dividers", + "pooled", + "virginian", + "stays", + "psycho", + "carlos", + "mailroom", + "confirmed", + "buckley", + "materialized", + "varadero", + "mnogosearch", + "granada", + "ambiente", + "mississauga", + "grundy", + "unverified", + "exercises", + "lasagna", + "truckee", + "puppies", + "truce", + "cluster", + "kirkwood", + "bigpond", + "entail", + "scribes", + "minerals", + "vidio", + "tostring", + "tariq", + "vivian", + "foolishness", + "osborne", + "steamy", + "stonehenge", + "breathe", + "loosening", + "euchre", + "krazy", + "cyclades", + "stains", + "proponent", + "sterility", + "carmine", + "wisely", + "locations", + "migratory", + "hemisphere", + "foraging", + "tomaso", + "cured", + "playmobil", + "mania", + "treks", + "distinct", + "carded", + "ativan", + "darden", + "stunt", + "mingle", + "datasheet", + "kleine", + "hynes", + "biofuels", + "confiscated", + "blasted", + "mater", + "jayhawks", + "wanadoo", + "portions", + "holmes", + "fatty", + "cello", + "trafic", + "warfare", + "slugger", + "exiting", + "ascend", +]; diff --git a/clarity/src/vm/mod.rs b/clarity/src/vm/mod.rs index 9d74fae5d7..8033ba0cac 100644 --- a/clarity/src/vm/mod.rs +++ b/clarity/src/vm/mod.rs @@ -47,6 +47,9 @@ pub mod tests; #[cfg(any(test, feature = "testing"))] pub mod test_util; +#[cfg(any(test, feature = "testing"))] +pub mod fakes; + pub mod clarity; use std::collections::BTreeMap; diff --git a/clarity/src/vm/types/mod.rs b/clarity/src/vm/types/mod.rs index 6a988fd59a..af315f8c9b 100644 --- a/clarity/src/vm/types/mod.rs +++ b/clarity/src/vm/types/mod.rs @@ -84,6 +84,7 @@ impl StandardPrincipalData { } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)] +#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] pub struct QualifiedContractIdentifier { pub issuer: StandardPrincipalData, pub name: ContractName, @@ -130,6 +131,7 @@ impl fmt::Display for QualifiedContractIdentifier { } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] +#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] pub enum PrincipalData { Standard(StandardPrincipalData), Contract(QualifiedContractIdentifier), @@ -152,12 +154,14 @@ pub struct ResponseData { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] pub struct CallableData { pub contract_identifier: QualifiedContractIdentifier, pub trait_identifier: Option, } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)] +#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] pub struct TraitIdentifier { pub name: ClarityName, pub contract_identifier: QualifiedContractIdentifier, diff --git a/clarity/src/vm/types/signatures.rs b/clarity/src/vm/types/signatures.rs index 29445d2499..edba94e410 100644 --- a/clarity/src/vm/types/signatures.rs +++ b/clarity/src/vm/types/signatures.rs @@ -76,14 +76,14 @@ impl AssetIdentifier { #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct TupleTypeSignature { - type_map: BTreeMap, + pub type_map: BTreeMap, } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct BufferLength(u32); +pub struct BufferLength(pub u32); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct StringUTF8Length(u32); +pub struct StringUTF8Length(pub u32); // INVARIANTS enforced by the Type Signatures. // 1. A TypeSignature constructor will always fail rather than construct a @@ -151,6 +151,7 @@ pub enum StringSubtype { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] +#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] pub enum CallableSubtype { Principal(QualifiedContractIdentifier), Trait(TraitIdentifier), @@ -221,8 +222,8 @@ pub const UTF8_40: TypeSignature = SequenceType(SequenceSubtype::StringType(Stri #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ListTypeData { - max_len: u32, - entry_type: Box, + pub max_len: u32, + pub entry_type: Box, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -244,6 +245,7 @@ pub enum FunctionArgSignature { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] pub enum FunctionReturnsSignature { TypeOfArgAtPosition(usize), Fixed(TypeSignature), From c89c917f99683ccbb4a0fe42a68e685776fe9760 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Mon, 4 Mar 2024 13:27:54 +0100 Subject: [PATCH 02/28] fix: update faking methods to always use the received instance. --- clarity/src/vm/fakes.rs | 93 ++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/clarity/src/vm/fakes.rs b/clarity/src/vm/fakes.rs index aa9389ce66..f94f66502d 100644 --- a/clarity/src/vm/fakes.rs +++ b/clarity/src/vm/fakes.rs @@ -1,4 +1,18 @@ -#![allow(non_snake_case)] +// Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation +// Copyright (C) 2020 Stacks Open Internet Foundation +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . use fake::locales::EN; use fake::Dummy; @@ -11,7 +25,6 @@ use self::raw::*; pub mod raw { use std::collections::BTreeMap; - use std::sync::atomic::AtomicU32; use fake::locales::EN; use fake::{Dummy, Fake, Faker}; @@ -32,38 +45,38 @@ pub mod raw { const MAX_RECURSION_LEVEL: u32 = 1; impl Dummy for StandardPrincipalData { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { StandardPrincipalData(1, rng.gen()) } } pub struct EnglishWord(pub L); impl Dummy> for &'static str { - fn dummy_with_rng(config: &EnglishWord, rng: &mut R) -> Self { + fn dummy_with_rng(_: &EnglishWord, rng: &mut R) -> Self { ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)] } } impl Dummy> for String { - fn dummy_with_rng(config: &EnglishWord, rng: &mut R) -> Self { + fn dummy_with_rng(_: &EnglishWord, rng: &mut R) -> Self { ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)].into() } } impl Dummy for ClarityName { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { ClarityName::from(ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)]) } } impl Dummy for ContractName { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { ContractName::from(ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)]) } } impl Dummy for UTF8Data { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { let val = Value::string_utf8_from_string_utf8_literal( ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)].to_string(), ) @@ -78,7 +91,7 @@ pub mod raw { } impl Dummy for ASCIIData { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { ASCIIData { data: ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)] .as_bytes() @@ -88,11 +101,12 @@ pub mod raw { } impl Dummy for TypeSignature { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { random_type_signature(None, rng) } } + /// Generate a random `TypeSignature` instance. fn random_type_signature(level: Option, rng: &mut R) -> TypeSignature { let next_level = Some(level.unwrap_or_default() + 1); @@ -110,15 +124,15 @@ pub mod raw { TypeSignature::SequenceType(SequenceSubtype::BufferType(BufferLength( rng.gen_range(50..100), ))), - TypeSignature::CallableType(CallableSubtype::Principal(Faker.fake())), + TypeSignature::CallableType(CallableSubtype::Principal(Faker.fake_with_rng(rng))), TypeSignature::TraitReferenceType(TraitIdentifier { - name: Faker.fake(), - contract_identifier: Faker.fake(), + name: Faker.fake_with_rng(rng), + contract_identifier: Faker.fake_with_rng(rng), }), TypeSignature::ListUnionType( (0..rng.gen_range(1..3)) .into_iter() - .map(|_| Faker.fake()) + .map(|_| Faker.fake_with_rng(rng)) .collect(), ), ]; @@ -137,7 +151,7 @@ pub mod raw { ))), TypeSignature::TupleType(TupleTypeSignature { type_map: (0..rng.gen_range(1..3)) - .map(|_| (Faker.fake(), random_type_signature(next_level, rng))) + .map(|_| (Faker.fake_with_rng(rng), random_type_signature(next_level, rng))) .collect(), }), ]; @@ -150,11 +164,12 @@ pub mod raw { } impl Dummy for SymbolicExpressionType { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { random_symbolic_expression_type(None, rng) } } + /// Generate a random `SymbolicExpressionType` instance. fn random_symbolic_expression_type( level: Option, rng: &mut R, @@ -162,7 +177,7 @@ pub mod raw { let next_level = Some(level.unwrap_or_default() + 1); let mut types = vec![ - SymbolicExpressionType::Atom(Faker.fake()), + SymbolicExpressionType::Atom(Faker.fake_with_rng(rng)), SymbolicExpressionType::LiteralValue(random_value(next_level, rng)), ]; @@ -171,7 +186,7 @@ pub mod raw { let mut recursive_types = vec![SymbolicExpressionType::List( (1..rng.gen_range(1..3)) .into_iter() - .map(|_| Faker.fake()) + .map(|_| Faker.fake_with_rng(rng)) .collect(), )]; @@ -183,20 +198,21 @@ pub mod raw { } impl Dummy for Value { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { random_value(None, rng) } } + /// Generate a random `Value` instance. fn random_value(level: Option, rng: &mut R) -> Value { let next_level = Some(level.unwrap_or_default() + 1); let mut values = vec![ - Value::Bool(Faker.fake()), - Value::Int(Faker.fake()), - Value::UInt(Faker.fake()), - Value::Principal(Faker.fake()), - Value::CallableContract(Faker.fake()), + Value::Bool(Faker.fake_with_rng(rng)), + Value::Int(Faker.fake_with_rng(rng)), + Value::UInt(Faker.fake_with_rng(rng)), + Value::Principal(Faker.fake_with_rng(rng)), + Value::CallableContract(Faker.fake_with_rng(rng)), ]; if let Some(lvl) = level { @@ -205,11 +221,11 @@ pub mod raw { Value::Tuple(TupleData { data_map: (0..rng.gen_range(1..3)) .into_iter() - .map(|_| (Faker.fake(), random_value(next_level, rng))) + .map(|_| (Faker.fake_with_rng(rng), random_value(next_level, rng))) .collect(), type_signature: TupleTypeSignature { type_map: (0..rng.gen_range(1..3)) - .map(|_| (Faker.fake(), random_type_signature(next_level, rng))) + .map(|_| (Faker.fake_with_rng(rng), random_type_signature(next_level, rng))) .collect(), }, }), @@ -221,7 +237,7 @@ pub mod raw { }, }), Value::Response(ResponseData { - committed: Faker.fake(), + committed: Faker.fake_with_rng(rng), data: Box::new(random_value(next_level, rng)), }), Value::string_utf8_from_string_utf8_literal( @@ -260,7 +276,7 @@ pub mod raw { } impl Dummy for FunctionSignature { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { FunctionSignature { args: (0..rng.gen_range(1..3)) .into_iter() @@ -272,11 +288,11 @@ pub mod raw { } impl Dummy for FixedFunction { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { FixedFunction { args: (0..rng.gen_range(1..3)) .into_iter() - .map(|_| Faker.fake()) + .map(|_| Faker.fake_with_rng(rng)) .collect(), returns: random_type_signature(None, rng), } @@ -284,16 +300,16 @@ pub mod raw { } impl Dummy for FunctionArg { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { FunctionArg { - name: Faker.fake(), + name: Faker.fake_with_rng(rng), signature: random_type_signature(None, rng), } } } impl Dummy for FunctionArgSignature { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { let sigs = vec![ FunctionArgSignature::Union( (0..rng.gen_range(1..2)) @@ -309,10 +325,10 @@ pub mod raw { } impl Dummy for FunctionType { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { let fn_types = vec![ - FunctionType::Fixed(Faker.fake()), - FunctionType::Variadic(Faker.fake(), Faker.fake()), + FunctionType::Fixed(Faker.fake_with_rng(rng)), + FunctionType::Variadic(Faker.fake_with_rng(rng), Faker.fake_with_rng(rng)), FunctionType::UnionArgs( (0..rng.gen_range(1..2)) .into_iter() @@ -324,7 +340,7 @@ pub mod raw { FunctionType::ArithmeticUnary, FunctionType::ArithmeticComparison, FunctionType::ArithmeticVariadic, - FunctionType::Binary(Faker.fake(), Faker.fake(), Faker.fake()), + FunctionType::Binary(Faker.fake_with_rng(rng), Faker.fake_with_rng(rng), Faker.fake_with_rng(rng)), ]; fn_types[rng.gen_range(0..fn_types.len())].clone() @@ -332,7 +348,7 @@ pub mod raw { } impl Dummy for SymbolicExpression { - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { SymbolicExpression { expr: random_symbolic_expression_type(None, rng), id: rng.gen(), @@ -349,6 +365,7 @@ pub mod raw { } } +/// A list of random English words which can be used when generating fake data. const ENGLISH_WORDS: &'static [&'static str] = &[ "glancing", "gwaith", From 2d15f35d18c9e681f77136c7f4f5129ec8f8f96b Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Mon, 4 Mar 2024 13:28:25 +0100 Subject: [PATCH 03/28] fix: update faking methods to always use the received 'Rng' instance. --- Cargo.lock | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 4aa6412fef..53d18c7c61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -691,7 +691,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.0", ] [[package]] @@ -717,6 +717,7 @@ name = "clarity" version = "0.0.1" dependencies = [ "assert-json-diff", + "fake", "hashbrown 0.14.3", "integer-sqrt", "lazy_static", @@ -989,6 +990,57 @@ dependencies = [ ] [[package]] +<<<<<<< HEAD +======= +name = "darling" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.48", +] + +[[package]] +name = "darling_macro" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if 1.0.0", + "hashbrown 0.14.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +>>>>>>> d5f6e2ce4 (fix: update faking methods to always use the received 'Rng' instance.) name = "data-encoding" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1013,6 +1065,12 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "deunicode" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94" + [[package]] name = "digest" version = "0.8.1" @@ -1068,6 +1126,18 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "dummy" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e57e12b69e57fad516e01e2b3960f122696fdb13420e1a88ed8e210316f2876" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -1185,6 +1255,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "fake" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c25829bde82205da46e1823b2259db6273379f626fc211f126f65654a2669be" +dependencies = [ + "deunicode", + "dummy", + "rand 0.8.5", +] + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -1720,6 +1801,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.5.0" @@ -3592,6 +3679,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.0" From 9b63f36251d04ee16a684791f4e47557d6a379d9 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Mon, 4 Mar 2024 15:41:11 +0100 Subject: [PATCH 04/28] added new 'StacksHashMap' and 'StacksHashSet' types to 'stacks-common' --- stacks-common/Cargo.toml | 3 +- stacks-common/src/types/hashmap.rs | 70 ++++++++++++++++++++++++++++++ stacks-common/src/types/hashset.rs | 70 ++++++++++++++++++++++++++++++ stacks-common/src/types/mod.rs | 5 +++ 4 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 stacks-common/src/types/hashmap.rs create mode 100644 stacks-common/src/types/hashset.rs diff --git a/stacks-common/Cargo.toml b/stacks-common/Cargo.toml index 50eadfb85d..7687405e97 100644 --- a/stacks-common/Cargo.toml +++ b/stacks-common/Cargo.toml @@ -33,6 +33,7 @@ chrono = "0.4.19" libc = "0.2.82" wsts = { workspace = true } hashbrown = { workspace = true } +fake = { version = "2.9.2", optional = true } [target.'cfg(unix)'.dependencies] nix = "0.23" @@ -76,7 +77,7 @@ rand_core = { workspace = true } default = ["developer-mode"] developer-mode = [] slog_json = ["slog-json"] -testing = [] +testing = ["dep:fake"] [target.'cfg(all(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"), not(target_env = "msvc")))'.dependencies] sha2 = { version = "0.10", features = ["asm"] } diff --git a/stacks-common/src/types/hashmap.rs b/stacks-common/src/types/hashmap.rs new file mode 100644 index 0000000000..c4a09d2e2a --- /dev/null +++ b/stacks-common/src/types/hashmap.rs @@ -0,0 +1,70 @@ +use std::hash::Hash; +use std::iter::{FromIterator, IntoIterator}; +use std::ops::{Deref, DerefMut}; + +#[cfg(any(test, feature = "testing"))] +use fake::{Dummy, Fake, Faker}; +use hashbrown::HashMap; +use rand::Rng; + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct StacksHashMap(pub HashMap) +where + K: Eq + Hash; + +impl StacksHashMap +where + K: Eq + Hash, +{ + pub fn new() -> Self { + StacksHashMap(HashMap::new()) + } +} + +impl<'a, K, V> Deref for StacksHashMap +where + K: Eq + Hash, +{ + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for StacksHashMap +where + K: Eq + Hash, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl FromIterator<(K, V)> for StacksHashMap +where + K: Eq + Hash, +{ + fn from_iter>(iter: I) -> Self { + let mut map = StacksHashMap::new(); + for (key, value) in iter { + map.insert(key, value); + } + map + } +} + +#[cfg(any(test, feature = "testing"))] +impl Dummy for StacksHashMap +where + K: Eq + Hash + Dummy, + V: Dummy, +{ + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { + let mut map = HashMap::::new(); + for _ in 0..rng.gen_range(1..5) { + map.insert(Faker.fake(), Faker.fake()); + } + StacksHashMap(map) + } +} diff --git a/stacks-common/src/types/hashset.rs b/stacks-common/src/types/hashset.rs new file mode 100644 index 0000000000..3c534ad799 --- /dev/null +++ b/stacks-common/src/types/hashset.rs @@ -0,0 +1,70 @@ +use std::hash::Hash; +use std::iter::{FromIterator, IntoIterator}; +use std::ops::{Deref, DerefMut}; + +#[cfg(any(test, feature = "testing"))] +use fake::{Dummy, Fake, Faker}; +use hashbrown::HashSet; +use rand::Rng; + +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct StacksHashSet(pub hashbrown::HashSet) +where + T: Eq + Hash; + +impl StacksHashSet +where + T: Eq + Hash, +{ + pub fn new() -> Self { + StacksHashSet(hashbrown::HashSet::new()) + } +} + +impl Deref for StacksHashSet +where + T: Eq + Hash, +{ + type Target = hashbrown::HashSet; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for StacksHashSet +where + T: Eq + Hash, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl FromIterator for StacksHashSet +where + T: Eq + Hash, +{ + fn from_iter>(iter: I) -> Self { + let mut set = StacksHashSet(HashSet::new()); + for item in iter { + set.insert(item); + } + set + } +} + +#[cfg(any(test, feature = "testing"))] +impl Dummy for StacksHashSet +where + T: Dummy + Eq + Hash, +{ + fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { + let len = rng.gen_range(1..5); + let mut set = StacksHashSet::new(); + for _ in 0..len { + set.insert(T::dummy_with_rng(&config, rng)); + } + set + } +} diff --git a/stacks-common/src/types/mod.rs b/stacks-common/src/types/mod.rs index cf5603dba9..dc5d5f638a 100644 --- a/stacks-common/src/types/mod.rs +++ b/stacks-common/src/types/mod.rs @@ -14,6 +14,11 @@ use crate::util::secp256k1::{MessageSignature, Secp256k1PublicKey}; pub mod chainstate; pub mod net; +pub mod hashmap; +pub mod hashset; + +pub use hashmap::StacksHashMap; +pub use hashset::StacksHashSet; /// A container for public keys (compressed secp256k1 public keys) pub struct StacksPublicKeyBuffer(pub [u8; 33]); From a7068342015070b5cba4cac1e62e7af935a95409 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Mon, 4 Mar 2024 15:41:50 +0100 Subject: [PATCH 05/28] wip: new clarity-db tests, fix remaining impls for 'fake' --- Cargo.lock | 1 + clarity/Cargo.toml | 5 +- clarity/src/vm/callables.rs | 14 +- clarity/src/vm/contexts.rs | 6 +- clarity/src/vm/contracts.rs | 3 +- clarity/src/vm/database/mod.rs | 2 + clarity/src/vm/database/structures.rs | 4 + .../src/vm/database/tests/clarity_db_tests.rs | 163 ++++++++++++++++++ clarity/src/vm/database/tests/mod.rs | 1 + clarity/src/vm/fakes.rs | 26 +++ clarity/src/vm/mod.rs | 2 +- clarity/src/vm/types/mod.rs | 8 +- clarity/src/vm/types/signatures.rs | 4 +- clarity/src/vm/version.rs | 1 + 14 files changed, 222 insertions(+), 18 deletions(-) create mode 100644 clarity/src/vm/database/tests/clarity_db_tests.rs create mode 100644 clarity/src/vm/database/tests/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 53d18c7c61..1e7f6c0050 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3462,6 +3462,7 @@ dependencies = [ "chrono", "curve25519-dalek 2.0.0", "ed25519-dalek", + "fake", "hashbrown 0.14.3", "lazy_static", "libc", diff --git a/clarity/Cargo.toml b/clarity/Cargo.toml index b0452fab93..956443d63f 100644 --- a/clarity/Cargo.toml +++ b/clarity/Cargo.toml @@ -31,7 +31,7 @@ stacks_common = { package = "stacks-common", path = "../stacks-common" } rstest = "0.17.0" rstest_reuse = "0.5.0" hashbrown = { workspace = true } -fake = { version = "2.9.2", features = ["derive"] } +fake = { version = "2.9.2", features = ["derive"], optional = true } [dependencies.serde_json] version = "1.0" @@ -47,6 +47,7 @@ features = ["std"] [dev-dependencies] assert-json-diff = "1.0.0" +stacks_common = { package = "stacks-common", path = "../stacks-common", features = ["testing"] } # a nightly rustc regression (35dbef235 2021-03-02) prevents criterion from compiling # but it isn't necessary for tests: only benchmarks. therefore, commenting out for now. # criterion = "0.3" @@ -55,5 +56,5 @@ assert-json-diff = "1.0.0" default = [] developer-mode = [] slog_json = ["stacks_common/slog_json"] -testing = [] +testing = ["dep:fake"] diff --git a/clarity/src/vm/callables.rs b/clarity/src/vm/callables.rs index 32e7d05514..a5e074d688 100644 --- a/clarity/src/vm/callables.rs +++ b/clarity/src/vm/callables.rs @@ -56,20 +56,21 @@ pub enum CallableType { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum DefineType { ReadOnly, Public, Private, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct DefinedFunction { - identifier: FunctionIdentifier, - name: ClarityName, - arg_types: Vec, + pub identifier: FunctionIdentifier, + pub name: ClarityName, + pub arg_types: Vec, pub define_type: DefineType, - arguments: Vec, - body: SymbolicExpression, + pub arguments: Vec, + pub body: SymbolicExpression, } /// This enum handles the actual invocation of the method @@ -120,6 +121,7 @@ pub fn cost_input_sized_vararg(args: &[Value]) -> Result { } #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct FunctionIdentifier { identifier: String, } diff --git a/clarity/src/vm/contexts.rs b/clarity/src/vm/contexts.rs index de7b07036e..805e3f33db 100644 --- a/clarity/src/vm/contexts.rs +++ b/clarity/src/vm/contexts.rs @@ -18,12 +18,13 @@ use std::collections::{BTreeMap, BTreeSet}; use std::fmt; use std::mem::replace; -use hashbrown::{HashMap, HashSet}; +//use hashbrown::{HashMap, HashSet}; use serde::Serialize; use serde_json::json; use stacks_common::consts::CHAIN_ID_TESTNET; use stacks_common::types::chainstate::StacksBlockId; use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use super::EvalHook; use crate::vm::ast::{ASTRules, ContractAST}; @@ -205,7 +206,8 @@ pub struct GlobalContext<'a, 'hooks> { pub eval_hooks: Option>, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct ContractContext { pub contract_identifier: QualifiedContractIdentifier, pub variables: HashMap, diff --git a/clarity/src/vm/contracts.rs b/clarity/src/vm/contracts.rs index 1982665aee..be86d7a5e7 100644 --- a/clarity/src/vm/contracts.rs +++ b/clarity/src/vm/contracts.rs @@ -25,7 +25,8 @@ use crate::vm::types::{PrincipalData, QualifiedContractIdentifier}; use crate::vm::version::ClarityVersion; use crate::vm::{apply, eval_all, Value}; -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct Contract { pub contract_context: ContractContext, } diff --git a/clarity/src/vm/database/mod.rs b/clarity/src/vm/database/mod.rs index 1092992982..99bd07acd1 100644 --- a/clarity/src/vm/database/mod.rs +++ b/clarity/src/vm/database/mod.rs @@ -33,3 +33,5 @@ pub mod clarity_store; mod key_value_wrapper; mod sqlite; mod structures; +#[cfg(feature = "testing")] +mod tests; \ No newline at end of file diff --git a/clarity/src/vm/database/structures.rs b/clarity/src/vm/database/structures.rs index 937eda2bdc..b8fb414950 100644 --- a/clarity/src/vm/database/structures.rs +++ b/clarity/src/vm/database/structures.rs @@ -74,6 +74,7 @@ macro_rules! clarity_serializable { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct FungibleTokenMetadata { pub total_supply: Option, } @@ -81,6 +82,7 @@ pub struct FungibleTokenMetadata { clarity_serializable!(FungibleTokenMetadata); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct NonFungibleTokenMetadata { pub key_type: TypeSignature, } @@ -88,6 +90,7 @@ pub struct NonFungibleTokenMetadata { clarity_serializable!(NonFungibleTokenMetadata); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct DataMapMetadata { pub key_type: TypeSignature, pub value_type: TypeSignature, @@ -96,6 +99,7 @@ pub struct DataMapMetadata { clarity_serializable!(DataMapMetadata); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct DataVariableMetadata { pub value_type: TypeSignature, } diff --git a/clarity/src/vm/database/tests/clarity_db_tests.rs b/clarity/src/vm/database/tests/clarity_db_tests.rs new file mode 100644 index 0000000000..dcb8519e97 --- /dev/null +++ b/clarity/src/vm/database/tests/clarity_db_tests.rs @@ -0,0 +1,163 @@ +use fake::{Faker, Fake}; +use rusqlite::NO_PARAMS; +use stacks_common::util::hash::Sha512Trunc256Sum; + +use crate::vm::{contracts::Contract, database::{clarity_store::ContractCommitment, ClarityBackingStore, ClarityDatabase, ClaritySerializable, MemoryBackingStore, NULL_BURN_STATE_DB, NULL_HEADER_DB}, fakes::raw::EnglishWord, Value}; + +#[test] +fn insert_contract() { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + db.begin(); + + let contract: Contract = Faker.fake(); + let contract_id = contract.contract_context.contract_identifier.clone(); + + db.insert_contract(&contract_id, contract) + .expect("failed to insert contract into backing store"); + + let exists = sql_exists( + &mut store, + &format!( + "SELECT * FROM metadata_table WHERE key LIKE '%{}%'", + contract_id.to_string() + ) + ); + assert!(!exists); +} + +#[test] +fn get_contract() { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + db.begin(); + + let contract: Contract = Faker.fake(); + let contract_id = contract.contract_context.contract_identifier.clone(); + + db.insert_contract(&contract_id, contract.clone()) + .expect("failed to insert contract into backing store"); + + let retrieved_contract = db.get_contract(&contract_id) + .expect("failed to retrieve contract from backing store"); + + assert_eq!(contract, retrieved_contract); +} + +#[test] +fn insert_contract_without_begin_should_fail() { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + let contract: Contract = Faker.fake(); + let contract_id = contract.contract_context.contract_identifier.clone(); + + db.insert_contract(&contract_id, contract) + .expect_err("inserting contract without a begin should fail"); +} + +#[test] +fn insert_contract_with_commit_should_exist_in_backing_store() { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + db.begin(); + + let contract: Contract = Faker.fake(); + let contract_id = contract.contract_context.contract_identifier.clone(); + + db.insert_contract(&contract_id, contract.clone()) + .expect("failed to insert contract into backing store"); + + db.commit().expect("failed to commit to backing store"); + + let count = sql_query_u32( + &mut store, + &format!("SELECT COUNT(*) FROM metadata_table WHERE key LIKE '{}'", + format!("clr-meta::{}::vm-metadata::9::contract", contract_id.to_string()) + ) + ); + + assert_eq!(1, count); +} + +#[test] +fn put_data_no_commit() { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + db.begin(); + + db.put("hello", &ContractCommitment { + block_height: 1, + hash: Sha512Trunc256Sum::from_data(&[1, 2, 3, 4]) + }).expect("failed to put data"); + + let count = sql_query_u32(&mut store, "SELECT COUNT(*) FROM data_table"); + assert_eq!(0, count); +} + +#[test] +fn put_data_with_commit_should_exist_in_backing_store() { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + db.begin(); + + let key = Faker.fake::(); + db.put(&key, &ContractCommitment { + block_height: Faker.fake(), + hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()) + }).expect("failed to put data"); + + db.commit().expect("failed to commit to backing store"); + + let count = sql_query_u32( + &mut store, + &format!("SELECT COUNT(*) FROM data_table where key = '{}'", key) + ); + assert_eq!(1, count); +} + +#[test] +fn put_data_without_begin_fails() { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + let key = Faker.fake::(); + db.put(&key, &ContractCommitment { + block_height: Faker.fake(), + hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()) + }).expect_err("expected not-nested error"); +} + +/// Executes the provided SQL query, which is expected to return a positive +/// integer, and returns it as a u32. Panics upon SQL failure. +fn sql_query_u32(store: &mut S, sql: &str) -> u32 { + let sqlite = store.get_side_store(); + sqlite.query_row( + sql, + NO_PARAMS, + |row| { + let i: u32 = row.get(0)?; + Ok(i) + } + ).expect("failed to verify results in sqlite") +} + +/// Executes the provided SQL query as a subquery within a `SELECT EXISTS(...)` +/// statement. Returns true if the statement returns any rows, false otherwise. +/// Panics upon SQL failure. +fn sql_exists(store: &mut S, sql: &str) -> bool { + let sqlite = store.get_side_store(); + sqlite.query_row( + &format!("SELECT EXISTS({});", sql), + NO_PARAMS, + |row| { + let exists: bool = row.get(0)?; + Ok(exists) + } + ).expect("failed to verify results in sqlite") +} \ No newline at end of file diff --git a/clarity/src/vm/database/tests/mod.rs b/clarity/src/vm/database/tests/mod.rs new file mode 100644 index 0000000000..b830f7c46b --- /dev/null +++ b/clarity/src/vm/database/tests/mod.rs @@ -0,0 +1 @@ +mod clarity_db_tests; \ No newline at end of file diff --git a/clarity/src/vm/fakes.rs b/clarity/src/vm/fakes.rs index f94f66502d..0491fffd8b 100644 --- a/clarity/src/vm/fakes.rs +++ b/clarity/src/vm/fakes.rs @@ -32,6 +32,7 @@ pub mod raw { use rand::Rng; use super::ENGLISH_WORDS; + use crate::vm::callables::DefinedFunction; use crate::vm::representations::Span; use crate::vm::types::signatures::{CallableSubtype, FunctionArgSignature}; use crate::vm::types::{ @@ -100,6 +101,31 @@ pub mod raw { } } + impl Dummy for DefinedFunction { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { + + let arg_types: Vec = (0..rng.gen_range(1..3)) + .into_iter() + .map(|_| random_type_signature(None, rng)) + .collect(); + + let arguments: Vec = (0..arg_types.len()) + .into_iter() + .map(|_| Faker.fake_with_rng(rng)) + .collect(); + + DefinedFunction { + define_type: Faker.fake_with_rng(rng), + name: Faker.fake_with_rng(rng), + arg_types, + arguments, + body: Faker.fake_with_rng(rng), + identifier: Faker.fake_with_rng(rng), + + } + } + } + impl Dummy for TypeSignature { fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { random_type_signature(None, rng) diff --git a/clarity/src/vm/mod.rs b/clarity/src/vm/mod.rs index 8033ba0cac..27127f63f0 100644 --- a/clarity/src/vm/mod.rs +++ b/clarity/src/vm/mod.rs @@ -47,7 +47,7 @@ pub mod tests; #[cfg(any(test, feature = "testing"))] pub mod test_util; -#[cfg(any(test, feature = "testing"))] +#[cfg(feature = "testing")] pub mod fakes; pub mod clarity; diff --git a/clarity/src/vm/types/mod.rs b/clarity/src/vm/types/mod.rs index af315f8c9b..c5428cdea7 100644 --- a/clarity/src/vm/types/mod.rs +++ b/clarity/src/vm/types/mod.rs @@ -84,7 +84,7 @@ impl StandardPrincipalData { } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct QualifiedContractIdentifier { pub issuer: StandardPrincipalData, pub name: ContractName, @@ -131,7 +131,7 @@ impl fmt::Display for QualifiedContractIdentifier { } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] -#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum PrincipalData { Standard(StandardPrincipalData), Contract(QualifiedContractIdentifier), @@ -154,14 +154,14 @@ pub struct ResponseData { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct CallableData { pub contract_identifier: QualifiedContractIdentifier, pub trait_identifier: Option, } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct TraitIdentifier { pub name: ClarityName, pub contract_identifier: QualifiedContractIdentifier, diff --git a/clarity/src/vm/types/signatures.rs b/clarity/src/vm/types/signatures.rs index edba94e410..84f6d90fb4 100644 --- a/clarity/src/vm/types/signatures.rs +++ b/clarity/src/vm/types/signatures.rs @@ -151,7 +151,7 @@ pub enum StringSubtype { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] -#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum CallableSubtype { Principal(QualifiedContractIdentifier), Trait(TraitIdentifier), @@ -245,7 +245,7 @@ pub enum FunctionArgSignature { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(any(test, feature = "testing"), derive(fake::Dummy))] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum FunctionReturnsSignature { TypeOfArgAtPosition(usize), Fixed(TypeSignature), diff --git a/clarity/src/vm/version.rs b/clarity/src/vm/version.rs index f64d4ee878..64d28ff961 100644 --- a/clarity/src/vm/version.rs +++ b/clarity/src/vm/version.rs @@ -6,6 +6,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::errors::{Error, RuntimeErrorType}; #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, PartialOrd)] +#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum ClarityVersion { Clarity1, Clarity2, From cd7d30ddd2b6b085c4786461fef64b3ed19e9d41 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Mon, 4 Mar 2024 15:57:52 +0100 Subject: [PATCH 06/28] wip: moved fake to workspace dep --- Cargo.lock | 1 + Cargo.toml | 1 + clarity/Cargo.toml | 2 +- stacks-common/Cargo.toml | 2 +- stackslib/Cargo.toml | 3 ++- stackslib/src/util_lib/db.rs | 2 +- 6 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e7f6c0050..e27543ff25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3570,6 +3570,7 @@ dependencies = [ "criterion", "curve25519-dalek 2.0.0", "ed25519-dalek", + "fake", "hashbrown 0.14.3", "integer-sqrt", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index 66791df99c..aa173d495a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ rand = "0.8" rand_chacha = "0.3.1" tikv-jemallocator = "0.5.4" wsts = { version = "8.1", default-features = false } +fake = { version = "2.9.2", features = ["derive"] } # Use a bit more than default optimization for # dev builds to speed up test execution diff --git a/clarity/Cargo.toml b/clarity/Cargo.toml index 956443d63f..018edb2603 100644 --- a/clarity/Cargo.toml +++ b/clarity/Cargo.toml @@ -31,7 +31,7 @@ stacks_common = { package = "stacks-common", path = "../stacks-common" } rstest = "0.17.0" rstest_reuse = "0.5.0" hashbrown = { workspace = true } -fake = { version = "2.9.2", features = ["derive"], optional = true } +fake = { workspace = true, optional = true } [dependencies.serde_json] version = "1.0" diff --git a/stacks-common/Cargo.toml b/stacks-common/Cargo.toml index 7687405e97..28a59dba11 100644 --- a/stacks-common/Cargo.toml +++ b/stacks-common/Cargo.toml @@ -33,7 +33,7 @@ chrono = "0.4.19" libc = "0.2.82" wsts = { workspace = true } hashbrown = { workspace = true } -fake = { version = "2.9.2", optional = true } +fake = { workspace = true, optional = true } [target.'cfg(unix)'.dependencies] nix = "0.23" diff --git a/stackslib/Cargo.toml b/stackslib/Cargo.toml index 8e2c483017..e3a20d11a2 100644 --- a/stackslib/Cargo.toml +++ b/stackslib/Cargo.toml @@ -58,6 +58,7 @@ libstackerdb = { path = "../libstackerdb" } siphasher = "0.3.7" wsts = { workspace = true } hashbrown = { workspace = true } +fake = { workspace = true, optional = true } [target.'cfg(not(target_env = "msvc"))'.dependencies] tikv-jemallocator = {workspace = true} @@ -112,7 +113,7 @@ disable-costs = [] developer-mode = ["clarity/developer-mode"] monitoring_prom = ["prometheus"] slog_json = ["slog-json", "stacks-common/slog_json", "clarity/slog_json", "pox-locking/slog_json"] -testing = [] +testing = ["dep:fake"] [target.'cfg(all(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"), not(target_env = "msvc")))'.dependencies] sha2 = { version = "0.10", features = ["asm"] } diff --git a/stackslib/src/util_lib/db.rs b/stackslib/src/util_lib/db.rs index a06c23408b..55122c6c44 100644 --- a/stackslib/src/util_lib/db.rs +++ b/stackslib/src/util_lib/db.rs @@ -689,7 +689,7 @@ pub fn tx_begin_immediate_sqlite<'a>(conn: &'a mut Connection) -> Result Date: Mon, 4 Mar 2024 16:15:50 +0100 Subject: [PATCH 07/28] wip: add fuzz-loop for tests using fake --- .../src/vm/database/tests/clarity_db_tests.rs | 184 ++++++++++-------- 1 file changed, 99 insertions(+), 85 deletions(-) diff --git a/clarity/src/vm/database/tests/clarity_db_tests.rs b/clarity/src/vm/database/tests/clarity_db_tests.rs index dcb8519e97..b03116fb83 100644 --- a/clarity/src/vm/database/tests/clarity_db_tests.rs +++ b/clarity/src/vm/database/tests/clarity_db_tests.rs @@ -6,131 +6,145 @@ use crate::vm::{contracts::Contract, database::{clarity_store::ContractCommitmen #[test] fn insert_contract() { - let mut store = MemoryBackingStore::new(); - let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - - db.begin(); - - let contract: Contract = Faker.fake(); - let contract_id = contract.contract_context.contract_identifier.clone(); - - db.insert_contract(&contract_id, contract) - .expect("failed to insert contract into backing store"); - - let exists = sql_exists( - &mut store, - &format!( - "SELECT * FROM metadata_table WHERE key LIKE '%{}%'", - contract_id.to_string() - ) - ); - assert!(!exists); + for _ in 0..1000 { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + db.begin(); + + let contract: Contract = Faker.fake(); + let contract_id = contract.contract_context.contract_identifier.clone(); + + db.insert_contract(&contract_id, contract) + .expect("failed to insert contract into backing store"); + + let exists = sql_exists( + &mut store, + &format!( + "SELECT * FROM metadata_table WHERE key LIKE '%{}%'", + contract_id.to_string() + ) + ); + assert!(!exists); + } } #[test] fn get_contract() { - let mut store = MemoryBackingStore::new(); - let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + for _ in 0..1000 { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - db.begin(); + db.begin(); - let contract: Contract = Faker.fake(); - let contract_id = contract.contract_context.contract_identifier.clone(); + let contract: Contract = Faker.fake(); + let contract_id = contract.contract_context.contract_identifier.clone(); - db.insert_contract(&contract_id, contract.clone()) - .expect("failed to insert contract into backing store"); + db.insert_contract(&contract_id, contract.clone()) + .expect("failed to insert contract into backing store"); - let retrieved_contract = db.get_contract(&contract_id) - .expect("failed to retrieve contract from backing store"); + let retrieved_contract = db.get_contract(&contract_id) + .expect("failed to retrieve contract from backing store"); - assert_eq!(contract, retrieved_contract); + assert_eq!(contract, retrieved_contract); + } } #[test] fn insert_contract_without_begin_should_fail() { - let mut store = MemoryBackingStore::new(); - let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + for _ in 0..1000 { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - let contract: Contract = Faker.fake(); - let contract_id = contract.contract_context.contract_identifier.clone(); + let contract: Contract = Faker.fake(); + let contract_id = contract.contract_context.contract_identifier.clone(); - db.insert_contract(&contract_id, contract) - .expect_err("inserting contract without a begin should fail"); + db.insert_contract(&contract_id, contract) + .expect_err("inserting contract without a begin should fail"); + } } #[test] fn insert_contract_with_commit_should_exist_in_backing_store() { - let mut store = MemoryBackingStore::new(); - let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + for _ in 0..1000 { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - db.begin(); + db.begin(); - let contract: Contract = Faker.fake(); - let contract_id = contract.contract_context.contract_identifier.clone(); + let contract: Contract = Faker.fake(); + let contract_id = contract.contract_context.contract_identifier.clone(); - db.insert_contract(&contract_id, contract.clone()) - .expect("failed to insert contract into backing store"); + db.insert_contract(&contract_id, contract.clone()) + .expect("failed to insert contract into backing store"); - db.commit().expect("failed to commit to backing store"); + db.commit().expect("failed to commit to backing store"); - let count = sql_query_u32( - &mut store, - &format!("SELECT COUNT(*) FROM metadata_table WHERE key LIKE '{}'", - format!("clr-meta::{}::vm-metadata::9::contract", contract_id.to_string()) - ) - ); + let count = sql_query_u32( + &mut store, + &format!("SELECT COUNT(*) FROM metadata_table WHERE key LIKE '{}'", + format!("clr-meta::{}::vm-metadata::9::contract", contract_id.to_string()) + ) + ); - assert_eq!(1, count); + assert_eq!(1, count); + } } #[test] fn put_data_no_commit() { - let mut store = MemoryBackingStore::new(); - let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + for _ in 0..1000 { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - db.begin(); + db.begin(); - db.put("hello", &ContractCommitment { - block_height: 1, - hash: Sha512Trunc256Sum::from_data(&[1, 2, 3, 4]) - }).expect("failed to put data"); + db.put("hello", &ContractCommitment { + block_height: 1, + hash: Sha512Trunc256Sum::from_data(&[1, 2, 3, 4]) + }).expect("failed to put data"); - let count = sql_query_u32(&mut store, "SELECT COUNT(*) FROM data_table"); - assert_eq!(0, count); + let count = sql_query_u32(&mut store, "SELECT COUNT(*) FROM data_table"); + assert_eq!(0, count); + } } #[test] fn put_data_with_commit_should_exist_in_backing_store() { - let mut store = MemoryBackingStore::new(); - let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - - db.begin(); - - let key = Faker.fake::(); - db.put(&key, &ContractCommitment { - block_height: Faker.fake(), - hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()) - }).expect("failed to put data"); - - db.commit().expect("failed to commit to backing store"); - - let count = sql_query_u32( - &mut store, - &format!("SELECT COUNT(*) FROM data_table where key = '{}'", key) - ); - assert_eq!(1, count); + for _ in 0..1000 { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + db.begin(); + + let key = Faker.fake::(); + db.put(&key, &ContractCommitment { + block_height: Faker.fake(), + hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()) + }).expect("failed to put data"); + + db.commit().expect("failed to commit to backing store"); + + let count = sql_query_u32( + &mut store, + &format!("SELECT COUNT(*) FROM data_table where key = '{}'", key) + ); + assert_eq!(1, count); + } } #[test] fn put_data_without_begin_fails() { - let mut store = MemoryBackingStore::new(); - let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - - let key = Faker.fake::(); - db.put(&key, &ContractCommitment { - block_height: Faker.fake(), - hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()) - }).expect_err("expected not-nested error"); + for _ in 0..1000 { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + let key = Faker.fake::(); + db.put(&key, &ContractCommitment { + block_height: Faker.fake(), + hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()) + }).expect_err("expected not-nested error"); + } } /// Executes the provided SQL query, which is expected to return a positive From 7a468e820ad3ecaecbf6469f47d296df2d54111a Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Mon, 4 Mar 2024 16:21:07 +0100 Subject: [PATCH 08/28] chore: cargo fmt-stacks --- clarity/src/vm/contexts.rs | 3 +- clarity/src/vm/database/mod.rs | 2 +- .../src/vm/database/tests/clarity_db_tests.rs | 96 +++++++++++-------- clarity/src/vm/database/tests/mod.rs | 2 +- clarity/src/vm/fakes.rs | 24 +++-- stacks-common/src/types/mod.rs | 2 +- 6 files changed, 80 insertions(+), 49 deletions(-) diff --git a/clarity/src/vm/contexts.rs b/clarity/src/vm/contexts.rs index 805e3f33db..2b025fd946 100644 --- a/clarity/src/vm/contexts.rs +++ b/clarity/src/vm/contexts.rs @@ -23,8 +23,7 @@ use serde::Serialize; use serde_json::json; use stacks_common::consts::CHAIN_ID_TESTNET; use stacks_common::types::chainstate::StacksBlockId; -use stacks_common::types::StacksEpochId; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use super::EvalHook; use crate::vm::ast::{ASTRules, ContractAST}; diff --git a/clarity/src/vm/database/mod.rs b/clarity/src/vm/database/mod.rs index 99bd07acd1..0753271d29 100644 --- a/clarity/src/vm/database/mod.rs +++ b/clarity/src/vm/database/mod.rs @@ -34,4 +34,4 @@ mod key_value_wrapper; mod sqlite; mod structures; #[cfg(feature = "testing")] -mod tests; \ No newline at end of file +mod tests; diff --git a/clarity/src/vm/database/tests/clarity_db_tests.rs b/clarity/src/vm/database/tests/clarity_db_tests.rs index b03116fb83..498f74b06b 100644 --- a/clarity/src/vm/database/tests/clarity_db_tests.rs +++ b/clarity/src/vm/database/tests/clarity_db_tests.rs @@ -1,8 +1,15 @@ -use fake::{Faker, Fake}; +use fake::{Fake, Faker}; use rusqlite::NO_PARAMS; use stacks_common::util::hash::Sha512Trunc256Sum; -use crate::vm::{contracts::Contract, database::{clarity_store::ContractCommitment, ClarityBackingStore, ClarityDatabase, ClaritySerializable, MemoryBackingStore, NULL_BURN_STATE_DB, NULL_HEADER_DB}, fakes::raw::EnglishWord, Value}; +use crate::vm::contracts::Contract; +use crate::vm::database::clarity_store::ContractCommitment; +use crate::vm::database::{ + ClarityBackingStore, ClarityDatabase, ClaritySerializable, MemoryBackingStore, + NULL_BURN_STATE_DB, NULL_HEADER_DB, +}; +use crate::vm::fakes::raw::EnglishWord; +use crate::vm::Value; #[test] fn insert_contract() { @@ -18,12 +25,12 @@ fn insert_contract() { db.insert_contract(&contract_id, contract) .expect("failed to insert contract into backing store"); - let exists = sql_exists( + let exists = sql_exists( &mut store, &format!( - "SELECT * FROM metadata_table WHERE key LIKE '%{}%'", + "SELECT * FROM metadata_table WHERE key LIKE '%{}%'", contract_id.to_string() - ) + ), ); assert!(!exists); } @@ -43,7 +50,8 @@ fn get_contract() { db.insert_contract(&contract_id, contract.clone()) .expect("failed to insert contract into backing store"); - let retrieved_contract = db.get_contract(&contract_id) + let retrieved_contract = db + .get_contract(&contract_id) .expect("failed to retrieve contract from backing store"); assert_eq!(contract, retrieved_contract); @@ -81,10 +89,14 @@ fn insert_contract_with_commit_should_exist_in_backing_store() { db.commit().expect("failed to commit to backing store"); let count = sql_query_u32( - &mut store, - &format!("SELECT COUNT(*) FROM metadata_table WHERE key LIKE '{}'", - format!("clr-meta::{}::vm-metadata::9::contract", contract_id.to_string()) - ) + &mut store, + &format!( + "SELECT COUNT(*) FROM metadata_table WHERE key LIKE '{}'", + format!( + "clr-meta::{}::vm-metadata::9::contract", + contract_id.to_string() + ) + ), ); assert_eq!(1, count); @@ -99,10 +111,14 @@ fn put_data_no_commit() { db.begin(); - db.put("hello", &ContractCommitment { - block_height: 1, - hash: Sha512Trunc256Sum::from_data(&[1, 2, 3, 4]) - }).expect("failed to put data"); + db.put( + "hello", + &ContractCommitment { + block_height: 1, + hash: Sha512Trunc256Sum::from_data(&[1, 2, 3, 4]), + }, + ) + .expect("failed to put data"); let count = sql_query_u32(&mut store, "SELECT COUNT(*) FROM data_table"); assert_eq!(0, count); @@ -118,16 +134,20 @@ fn put_data_with_commit_should_exist_in_backing_store() { db.begin(); let key = Faker.fake::(); - db.put(&key, &ContractCommitment { - block_height: Faker.fake(), - hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()) - }).expect("failed to put data"); + db.put( + &key, + &ContractCommitment { + block_height: Faker.fake(), + hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()), + }, + ) + .expect("failed to put data"); db.commit().expect("failed to commit to backing store"); let count = sql_query_u32( - &mut store, - &format!("SELECT COUNT(*) FROM data_table where key = '{}'", key) + &mut store, + &format!("SELECT COUNT(*) FROM data_table where key = '{}'", key), ); assert_eq!(1, count); } @@ -140,10 +160,14 @@ fn put_data_without_begin_fails() { let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); let key = Faker.fake::(); - db.put(&key, &ContractCommitment { - block_height: Faker.fake(), - hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()) - }).expect_err("expected not-nested error"); + db.put( + &key, + &ContractCommitment { + block_height: Faker.fake(), + hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()), + }, + ) + .expect_err("expected not-nested error"); } } @@ -151,27 +175,23 @@ fn put_data_without_begin_fails() { /// integer, and returns it as a u32. Panics upon SQL failure. fn sql_query_u32(store: &mut S, sql: &str) -> u32 { let sqlite = store.get_side_store(); - sqlite.query_row( - sql, - NO_PARAMS, - |row| { + sqlite + .query_row(sql, NO_PARAMS, |row| { let i: u32 = row.get(0)?; Ok(i) - } - ).expect("failed to verify results in sqlite") + }) + .expect("failed to verify results in sqlite") } -/// Executes the provided SQL query as a subquery within a `SELECT EXISTS(...)` +/// Executes the provided SQL query as a subquery within a `SELECT EXISTS(...)` /// statement. Returns true if the statement returns any rows, false otherwise. /// Panics upon SQL failure. fn sql_exists(store: &mut S, sql: &str) -> bool { let sqlite = store.get_side_store(); - sqlite.query_row( - &format!("SELECT EXISTS({});", sql), - NO_PARAMS, - |row| { + sqlite + .query_row(&format!("SELECT EXISTS({});", sql), NO_PARAMS, |row| { let exists: bool = row.get(0)?; Ok(exists) - } - ).expect("failed to verify results in sqlite") -} \ No newline at end of file + }) + .expect("failed to verify results in sqlite") +} diff --git a/clarity/src/vm/database/tests/mod.rs b/clarity/src/vm/database/tests/mod.rs index b830f7c46b..7c49f7d37e 100644 --- a/clarity/src/vm/database/tests/mod.rs +++ b/clarity/src/vm/database/tests/mod.rs @@ -1 +1 @@ -mod clarity_db_tests; \ No newline at end of file +mod clarity_db_tests; diff --git a/clarity/src/vm/fakes.rs b/clarity/src/vm/fakes.rs index 0491fffd8b..707c67ad77 100644 --- a/clarity/src/vm/fakes.rs +++ b/clarity/src/vm/fakes.rs @@ -103,7 +103,6 @@ pub mod raw { impl Dummy for DefinedFunction { fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - let arg_types: Vec = (0..rng.gen_range(1..3)) .into_iter() .map(|_| random_type_signature(None, rng)) @@ -116,12 +115,11 @@ pub mod raw { DefinedFunction { define_type: Faker.fake_with_rng(rng), - name: Faker.fake_with_rng(rng), + name: Faker.fake_with_rng(rng), arg_types, arguments, body: Faker.fake_with_rng(rng), identifier: Faker.fake_with_rng(rng), - } } } @@ -177,7 +175,12 @@ pub mod raw { ))), TypeSignature::TupleType(TupleTypeSignature { type_map: (0..rng.gen_range(1..3)) - .map(|_| (Faker.fake_with_rng(rng), random_type_signature(next_level, rng))) + .map(|_| { + ( + Faker.fake_with_rng(rng), + random_type_signature(next_level, rng), + ) + }) .collect(), }), ]; @@ -251,7 +254,12 @@ pub mod raw { .collect(), type_signature: TupleTypeSignature { type_map: (0..rng.gen_range(1..3)) - .map(|_| (Faker.fake_with_rng(rng), random_type_signature(next_level, rng))) + .map(|_| { + ( + Faker.fake_with_rng(rng), + random_type_signature(next_level, rng), + ) + }) .collect(), }, }), @@ -366,7 +374,11 @@ pub mod raw { FunctionType::ArithmeticUnary, FunctionType::ArithmeticComparison, FunctionType::ArithmeticVariadic, - FunctionType::Binary(Faker.fake_with_rng(rng), Faker.fake_with_rng(rng), Faker.fake_with_rng(rng)), + FunctionType::Binary( + Faker.fake_with_rng(rng), + Faker.fake_with_rng(rng), + Faker.fake_with_rng(rng), + ), ]; fn_types[rng.gen_range(0..fn_types.len())].clone() diff --git a/stacks-common/src/types/mod.rs b/stacks-common/src/types/mod.rs index dc5d5f638a..9615f66171 100644 --- a/stacks-common/src/types/mod.rs +++ b/stacks-common/src/types/mod.rs @@ -13,9 +13,9 @@ use crate::util::hash::Hash160; use crate::util::secp256k1::{MessageSignature, Secp256k1PublicKey}; pub mod chainstate; -pub mod net; pub mod hashmap; pub mod hashset; +pub mod net; pub use hashmap::StacksHashMap; pub use hashset::StacksHashSet; From b12c2c866ee6f4163bbbd99b0d949004fd9e06d9 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Mon, 4 Mar 2024 18:08:30 +0100 Subject: [PATCH 09/28] chore: update lockfile --- Cargo.lock | 348 +++++++++++++++++++++++++---------------------------- 1 file changed, 165 insertions(+), 183 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e27543ff25..913396dc6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,7 +88,7 @@ dependencies = [ "aes 0.8.4", "cipher 0.4.4", "ctr 0.9.2", - "ghash 0.5.0", + "ghash 0.5.1", "subtle", ] @@ -120,9 +120,9 @@ checksum = "0453232ace82dee0dd0b4c87a59bd90f7b53b314f3e0f61fe2ee7c8a16482289" [[package]] name = "ahash" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -162,9 +162,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -210,9 +210,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arrayvec" @@ -265,7 +265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 5.0.0", + "event-listener 5.2.0", "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", @@ -359,7 +359,7 @@ dependencies = [ "futures-io", "futures-lite 2.2.0", "parking", - "polling 3.4.0", + "polling 3.5.0", "rustix 0.38.31", "slab", "tracing", @@ -573,9 +573,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" [[package]] name = "byte-slice-cast" @@ -603,12 +603,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" [[package]] name = "cfg-if" @@ -633,7 +630,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -674,9 +671,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", "clap_derive", @@ -684,9 +681,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", @@ -703,7 +700,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -986,12 +983,10 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] -<<<<<<< HEAD -======= name = "darling" version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1012,7 +1007,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -1023,24 +1018,10 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if 1.0.0", - "hashbrown 0.14.3", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] ->>>>>>> d5f6e2ce4 (fix: update faking methods to always use the received 'Rng' instance.) name = "data-encoding" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1135,7 +1116,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -1214,9 +1195,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.0.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" dependencies = [ "concurrent-queue", "parking", @@ -1239,7 +1220,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" dependencies = [ - "event-listener 5.0.0", + "event-listener 5.2.0", "pin-project-lite", ] @@ -1432,7 +1413,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -1449,9 +1430,9 @@ checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" @@ -1524,12 +1505,12 @@ dependencies = [ [[package]] name = "ghash" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ "opaque-debug", - "polyval 0.6.1", + "polyval 0.6.2", ] [[package]] @@ -1571,9 +1552,9 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" @@ -1590,7 +1571,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", "allocator-api2", "serde", ] @@ -1645,9 +1626,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -1686,9 +1667,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1757,7 +1738,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.5", + "socket2 0.5.6", "tokio", "tower-service", "tracing", @@ -1839,9 +1820,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1886,7 +1867,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.6", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -1906,6 +1887,17 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -1923,9 +1915,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -2065,9 +2057,9 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" dependencies = [ "value-bag", ] @@ -2142,9 +2134,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -2242,16 +2234,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.6", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ + "hermit-abi 0.3.9", "libc", ] @@ -2278,9 +2261,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "overload" @@ -2307,7 +2290,7 @@ dependencies = [ "rustfmt-wrapper", "serde", "sha2 0.10.8", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -2350,9 +2333,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.7" +version = "2.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" +checksum = "56f8023d0fb78c8e03784ea1c7f3fa36e68a723138990b8d5a47d916b651e7a8" dependencies = [ "memchr", "thiserror", @@ -2382,7 +2365,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -2476,9 +2459,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" dependencies = [ "cfg-if 1.0.0", "concurrent-queue", @@ -2511,9 +2494,9 @@ dependencies = [ [[package]] name = "polyval" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if 1.0.0", "cpufeatures", @@ -2718,9 +2701,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -2764,7 +2747,7 @@ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.5", + "regex-automata 0.4.6", "regex-syntax 0.8.2", ] @@ -2779,9 +2762,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -2865,16 +2848,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if 1.0.0", "getrandom 0.2.12", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3007,7 +2991,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.21", + "semver 1.0.22", ] [[package]] @@ -3057,7 +3041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -3077,7 +3061,7 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -3089,9 +3073,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -3114,7 +3098,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -3157,9 +3141,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "semver-parser" @@ -3178,9 +3162,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -3197,20 +3181,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -3382,11 +3366,11 @@ dependencies = [ [[package]] name = "slog-term" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d29185c55b7b258b4f120eab00f48557d4d9bc814f41713f449d35b0f8977c" +checksum = "b6e022d0b998abfe5c3782c1f03551a596269450ccd677ea51c56f8b214610e8" dependencies = [ - "atty", + "is-terminal", "slog", "term", "thread_local", @@ -3411,12 +3395,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3534,7 +3518,7 @@ name = "stacks-signer" version = "0.0.1" dependencies = [ "backoff", - "clap 4.5.0", + "clap 4.5.1", "clarity", "hashbrown 0.14.3", "libsigner", @@ -3720,9 +3704,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -3764,9 +3748,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if 1.0.0", "fastrand 2.0.1", @@ -3811,14 +3795,14 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -3867,9 +3851,7 @@ checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "itoa", - "libc", "num-conv", - "num_threads", "powerfmt", "serde", "time-core", @@ -3961,10 +3943,10 @@ dependencies = [ "backtrace", "bytes", "libc", - "mio 0.8.10", + "mio 0.8.11", "num_cpus", "pin-project-lite", - "socket2 0.5.5", + "socket2 0.5.6", "windows-sys 0.48.0", ] @@ -4033,7 +4015,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.5", + "toml_edit 0.22.6", ] [[package]] @@ -4058,15 +4040,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.5" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e68c159e8f5ba8a28c4eb7b0c0c190d77bb479047ca713270048145a9ad28a" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.1", + "winnow 0.6.5", ] [[package]] @@ -4078,7 +4060,7 @@ dependencies = [ "home", "once_cell", "regex", - "semver 1.0.21", + "semver 1.0.22", "walkdir", ] @@ -4108,7 +4090,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] @@ -4222,9 +4204,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -4323,9 +4305,9 @@ checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -4385,9 +4367,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -4395,24 +4377,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -4422,9 +4404,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4432,28 +4414,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -4514,7 +4496,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -4532,7 +4514,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -4552,17 +4534,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -4573,9 +4555,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -4585,9 +4567,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -4597,9 +4579,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -4609,9 +4591,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -4621,9 +4603,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -4633,9 +4615,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -4645,9 +4627,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winnow" @@ -4660,9 +4642,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.1" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d90f4e0f530c4c69f62b80d839e9ef3855edc9cba471a160c4d692deed62b401" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" dependencies = [ "memchr", ] @@ -4735,7 +4717,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.52", ] [[package]] From ec807eda232ef61d6a65f5c189c8a75d95dba54a Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Mon, 4 Mar 2024 19:34:32 +0100 Subject: [PATCH 10/28] chore: remove unnecessary include --- clarity/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/clarity/Cargo.toml b/clarity/Cargo.toml index 018edb2603..dc2a5d76e0 100644 --- a/clarity/Cargo.toml +++ b/clarity/Cargo.toml @@ -47,7 +47,6 @@ features = ["std"] [dev-dependencies] assert-json-diff = "1.0.0" -stacks_common = { package = "stacks-common", path = "../stacks-common", features = ["testing"] } # a nightly rustc regression (35dbef235 2021-03-02) prevents criterion from compiling # but it isn't necessary for tests: only benchmarks. therefore, commenting out for now. # criterion = "0.3" From fc62d41045c489a987d9edccc0e1e9cd87f26028 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Tue, 5 Mar 2024 15:38:20 +0100 Subject: [PATCH 11/28] wip: playing with propmap instead of fake --- Cargo.lock | 93 ++++++ Cargo.toml | 5 +- clarity-proptest/Cargo.toml | 15 + clarity-proptest/src/lib.rs | 578 ++++++++++++++++++++++++++++++++++++ 4 files changed, 690 insertions(+), 1 deletion(-) create mode 100644 clarity-proptest/Cargo.toml create mode 100644 clarity-proptest/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 913396dc6e..f75436fa9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -498,6 +498,21 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -733,6 +748,15 @@ dependencies = [ "time 0.2.27", ] +[[package]] +name = "clarity-proptest" +version = "0.1.0" +dependencies = [ + "clarity", + "proptest", + "stacks-common", +] + [[package]] name = "colorchoice" version = "1.0.0" @@ -1982,6 +2006,12 @@ dependencies = [ "rle-decode-fast", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.0.1" @@ -2226,6 +2256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2598,6 +2629,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "proptest" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.4.2", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax 0.8.2", + "rusty-fork", + "tempfile", + "unarray", +] + [[package]] name = "protobuf" version = "2.28.0" @@ -2613,6 +2664,12 @@ dependencies = [ "cc", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.35" @@ -2699,6 +2756,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "rayon" version = "1.9.0" @@ -3071,6 +3137,18 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.17" @@ -4181,6 +4259,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicase" version = "2.7.0" @@ -4297,6 +4381,15 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "waker-fn" version = "1.1.1" diff --git a/Cargo.toml b/Cargo.toml index aa173d495a..a3643ac0d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,9 @@ members = [ "contrib/tools/relay-server", "libsigner", "stacks-signer", - "testnet/stacks-node"] + "testnet/stacks-node", + "clarity-proptest" +] # Dependencies we want to keep the same between workspace members [workspace.dependencies] @@ -22,6 +24,7 @@ rand_chacha = "0.3.1" tikv-jemallocator = "0.5.4" wsts = { version = "8.1", default-features = false } fake = { version = "2.9.2", features = ["derive"] } +proptest = { version = "1.4.0" } # Use a bit more than default optimization for # dev builds to speed up test execution diff --git a/clarity-proptest/Cargo.toml b/clarity-proptest/Cargo.toml new file mode 100644 index 0000000000..3d9f7815b0 --- /dev/null +++ b/clarity-proptest/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "clarity-proptest" +version = "0.1.0" +edition = "2021" + +[lib] +path = "src/lib.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clarity = { path = "../clarity" } +stacks_common = { path = "../stacks-common", package = "stacks-common" } +proptest = { version = "1.4" } + diff --git a/clarity-proptest/src/lib.rs b/clarity-proptest/src/lib.rs new file mode 100644 index 0000000000..69a0327142 --- /dev/null +++ b/clarity-proptest/src/lib.rs @@ -0,0 +1,578 @@ +use std::hash::Hash; +use clarity::types::StacksHashMap; +use clarity::vm::contracts::Contract; +use clarity::vm::types::{ + ASCIIData, BuffData, CharType, ListData, ListTypeData, OptionalData, PrincipalData, + QualifiedContractIdentifier, ResponseData, SequenceData, SequenceSubtype, + StandardPrincipalData, StringSubtype, StringUTF8Length, TupleData, TupleTypeSignature, + TypeSignature, UTF8Data, Value, MAX_VALUE_SIZE, +}; +use clarity::vm::{ContractContext, ContractName}; +use proptest::prelude::*; +use proptest::sample::SizeRange; + +// pub fn contract() -> impl Strategy { +// (contract_context()) +// .prop_map(|ctx| Contract { contract_context: ctx }) +//} + +// pub struct ContractContext { +// pub contract_identifier: QualifiedContractIdentifier, +// pub variables: HashMap, +// pub functions: HashMap, +// pub defined_traits: HashMap>, +// pub implemented_traits: HashSet, +// // tracks the names of NFTs, FTs, Maps, and Data Vars. +// // used for ensuring that they never are defined twice. +// pub persisted_names: HashSet, +// // track metadata for contract defined storage +// pub meta_data_map: HashMap, +// pub meta_data_var: HashMap, +// pub meta_nft: HashMap, +// pub meta_ft: HashMap, +// pub data_size: u64, +// /// track the clarity version of the contract +// clarity_version: ClarityVersion, +// } + +pub fn stacks_hashmap( + key_strategy: impl Strategy, + value_strategy: impl Strategy, + size: impl Into +) -> impl Strategy> { + prop::collection::hash_map( + key_strategy, + value_strategy, + size + ) + .prop_map(|map| StacksHashMap(map.into_iter().collect()) + ) +} + +// pub fn contract_context() -> impl Strategy { +// let x = stacks_hashmap( +// "[a-zA-Z]{1,40}".prop_map_into(), +// prop_signature().prop_flat_map(prop_value), +// 0..16 +// ); + +// ( +// qualified_principal(), +// stacks_hashmap( +// "[a-zA-Z]{1,40}".prop_map_into(), +// prop_signature().prop_flat_map(prop_value), +// 0..16 +// ), +// stacks_hashmap("[a-zA-Z]{1,40}", defined_function(), 0..16), +// stacks_hashmap("[a-zA-Z]{1,40}", stacks_hashmap( +// "[a-zA-Z]{1,40}", +// function_signature(), +// 0..16 +// ), 0..16), +// prop::collection::hash_set(trait_identifier(), 0..16), +// prop::collection::hash_set("[a-zA-Z]{1,40}", 0..16), +// stacks_hashmap("[a-zA-Z]{1,40}", data_map_metadata(), 0..16), +// stacks_hashmap("[a-zA-Z]{1,40}", data_variable_metadata(), 0..16), +// stacks_hashmap("[a-zA-Z]{1,40}", non_fungible_token_metadata(), 0..16), +// stacks_hashmap("[a-zA-Z]{1,40}", fungible_token_metadata(), 0..16), +// 0u64..u64::MAX, +// clarity_version(), +// ) +// .prop_map(|( +// contract_identifier, +// variables, +// functions, +// defined_traits, +// implemented_traits, +// persisted_names, +// meta_data_map, +// meta_data_var, +// meta_nft, +// meta_ft, +// data_size, +// clarity_version, +// )| { +// ContractContext { +// contract_identifier, +// variables, +// functions, +// defined_traits, +// implemented_traits, +// persisted_names, +// meta_data_map, +// meta_data_var, +// meta_nft, +// meta_ft, +// data_size, +// clarity_version, +// } +// }) +// } + +pub fn prop_signature() -> impl Strategy { + let leaf = prop_oneof![ + Just(TypeSignature::IntType), + Just(TypeSignature::UIntType), + Just(TypeSignature::BoolType), + (0u32..128).prop_map(|s| TypeSignature::SequenceType(SequenceSubtype::BufferType( + s.try_into().unwrap() + ))), + (0u32..128).prop_map(|s| TypeSignature::SequenceType(SequenceSubtype::StringType( + StringSubtype::ASCII(s.try_into().unwrap()) + ))), + Just(TypeSignature::PrincipalType), + (0u32..32).prop_map(|s| TypeSignature::SequenceType(SequenceSubtype::StringType( + StringSubtype::UTF8(s.try_into().unwrap()) + ))) + ]; + leaf.prop_recursive(5, 64, 10, |inner| { + prop_oneof![ + // optional type: 10% NoType + 90% any other type + prop_oneof![ + 1 => Just(TypeSignature::NoType), + 9 => inner.clone(), + ] + .prop_map(|t| TypeSignature::new_option(t).unwrap()), + // response type: 20% (NoType, any) + 20% (any, NoType) + 60% (any, any) + prop_oneof![ + 1 => inner.clone().prop_map(|ok_ty| TypeSignature::new_response(ok_ty, TypeSignature::NoType).unwrap()), + 1 => inner.clone().prop_map(|err_ty| TypeSignature::new_response(TypeSignature::NoType, err_ty).unwrap()), + 3 => (inner.clone(), inner.clone()).prop_map(|(ok_ty, err_ty)| TypeSignature::new_response(ok_ty, err_ty).unwrap()), + ], + // tuple type + prop::collection::btree_map( + r#"[a-zA-Z]{1,16}"#.prop_map(|name| name.try_into().unwrap()), + inner.clone(), + 1..8 + ) + .prop_map(|btree| TypeSignature::TupleType(btree.try_into().unwrap())), + // list type + (8u32..32, inner.clone()).prop_map(|(s, ty)| (ListTypeData::new_list(ty, s).unwrap()).into()), + ] + }) +} + +#[derive(Clone, PartialEq, Eq)] +pub struct PropValue(Value); + +impl From for PropValue { + fn from(value: Value) -> Self { + PropValue(value) + } +} + +impl From for Value { + fn from(value: PropValue) -> Self { + value.0 + } +} + +impl std::fmt::Debug for PropValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("PropValue") + .field("value", &self.to_string()) + .field("type", &self.type_string()) + .finish() + } +} + +impl std::fmt::Display for PropValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self.0 { + Value::Sequence(SequenceData::String(clarity::vm::types::CharType::ASCII( + ASCIIData { data }, + ))) => { + write!(f, "\"")?; + for b in data { + if [b'\\', b'"'].contains(b) { + write!(f, "\\")?; + } + write!(f, "{}", *b as char)?; + } + write!(f, "\"") + } + Value::Sequence(SequenceData::String(CharType::UTF8(UTF8Data { data }))) => { + write!(f, "u\"")?; + for bytes in data { + // SAFETY: a utf8 sequence always contains a valid sequence of utf8 chars as vec of bytes + let c = unsafe { std::str::from_utf8_unchecked(bytes).chars().next().unwrap() }; + match c { + '\\' | '\"' => write!(f, "\\{c}")?, + _ if c.is_ascii_graphic() => write!(f, "{c}")?, + _ => write!(f, r#"\u{{{:X}}}"#, c as u32)?, + } + } + write!(f, "\"") + } + Value::Principal(p) => write!(f, "'{p}"), + Value::Optional(OptionalData { data }) => match data { + Some(inner) => write!(f, "(some {})", PropValue(*inner.clone())), + None => write!(f, "none"), + }, + Value::Response(ResponseData { committed, data }) => { + if *committed { + write!(f, "(ok {})", PropValue(*data.clone())) + } else { + write!(f, "(err {})", PropValue(*data.clone())) + } + } + Value::Sequence(SequenceData::List(ListData { data, .. })) => { + write!(f, "(list")?; + for d in data { + write!(f, " ")?; + write!(f, "{}", PropValue(d.clone()))?; + } + write!(f, ")") + } + Value::Tuple(data) => { + write!(f, "(tuple")?; + for (key, value) in &data.data_map { + write!(f, " ")?; + write!(f, "({} {})", &**key, PropValue(value.clone()))?; + } + write!(f, ")") + } + otherwise => write!(f, "{otherwise}"), + } + } +} + +impl PropValue { + pub fn any() -> impl Strategy { + prop_signature().prop_flat_map(prop_value).prop_map_into() + } + + pub fn from_type(ty: TypeSignature) -> impl Strategy { + prop_value(ty).prop_map_into() + } + + pub fn many_from_type(ty: TypeSignature, count: usize) -> impl Strategy> { + prop::collection::vec(Self::from_type(ty.clone()), count) + } + + pub fn any_sequence(size: usize) -> impl Strategy { + let any_list = prop_signature() + .prop_ind_flat_map2(move |ty| prop::collection::vec(prop_value(ty), size)) + .prop_map(move |(ty, vec)| { + Value::Sequence(SequenceData::List(ListData { + data: vec, + type_signature: ListTypeData::new_list(ty, size as u32).unwrap(), + })) + }); + // TODO: add string-utf8 + prop_oneof![ + // 10% chance for a buffer + 1 => buffer(size as u32), + // 10% chance for a string-ascii + 1 => string_ascii(size as u32), + // 80% chance for a list + 8 => any_list + ] + .prop_map_into() + } +} + +impl TryFrom> for PropValue { + type Error = clarity::vm::errors::Error; + + fn try_from(values: Vec) -> Result { + let values = values.into_iter().map(Value::from).collect(); + Value::cons_list_unsanitized(values).map(PropValue::from) + } +} + +fn prop_value(ty: TypeSignature) -> impl Strategy { + match ty { + TypeSignature::NoType => unreachable!(), + TypeSignature::IntType => int().boxed(), + TypeSignature::UIntType => uint().boxed(), + TypeSignature::BoolType => bool().boxed(), + TypeSignature::OptionalType(ty) => optional(*ty).boxed(), + TypeSignature::ResponseType(ok_err) => response(ok_err.0, ok_err.1).boxed(), + TypeSignature::SequenceType(SequenceSubtype::BufferType(size)) => { + buffer(size.into()).boxed() + } + TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII(size))) => { + string_ascii(size.into()).boxed() + } + TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8(size))) => { + string_utf8(size.into()).boxed() + } + TypeSignature::SequenceType(SequenceSubtype::ListType(list_type_data)) => { + list(list_type_data).boxed() + } + TypeSignature::TupleType(tuple_ty) => tuple(tuple_ty).boxed(), + TypeSignature::PrincipalType => { + prop_oneof![standard_principal(), qualified_principal()].boxed() + } + // TODO + TypeSignature::ListUnionType(_) => todo!(), + TypeSignature::CallableType(_) => todo!(), + TypeSignature::TraitReferenceType(_) => todo!(), + } +} + +fn int() -> impl Strategy { + any::().prop_map(Value::Int) +} + +fn uint() -> impl Strategy { + any::().prop_map(Value::UInt) +} + +fn bool() -> impl Strategy { + any::().prop_map(Value::Bool) +} + +pub fn string_ascii(size: u32) -> impl Strategy { + let size = size as usize; + prop::collection::vec(0x20u8..0x7e, size..=size).prop_map(|bytes| { + Value::Sequence(SequenceData::String(clarity::vm::types::CharType::ASCII( + clarity::vm::types::ASCIIData { data: bytes }, + ))) + }) +} + +pub fn string_utf8(size: u32) -> impl Strategy { + prop::collection::vec(any::(), size as usize).prop_map(|chars| { + let mut data = Vec::with_capacity(chars.len()); + for c in chars { + let mut encoded_char = vec![0; c.len_utf8()]; + c.encode_utf8(encoded_char.as_mut()); + data.push(encoded_char); + } + Value::Sequence(SequenceData::String(CharType::UTF8(UTF8Data { data }))) + }) +} + +fn buffer(size: u32) -> impl Strategy { + let size = size as usize; + prop::collection::vec(any::(), size..=size) + .prop_map(|bytes| Value::Sequence(SequenceData::Buffer(BuffData { data: bytes }))) +} + +fn optional(inner_ty: TypeSignature) -> impl Strategy { + match inner_ty { + TypeSignature::NoType => Just(Value::none()).boxed(), + _ => prop::option::of(prop_value(inner_ty)) + .prop_map(|v| { + Value::Optional(OptionalData { + data: v.map(Box::new), + }) + }) + .boxed(), + } +} + +fn response(ok_ty: TypeSignature, err_ty: TypeSignature) -> impl Strategy { + match (ok_ty, err_ty) { + (TypeSignature::NoType, err_ty) => prop_value(err_ty) + .prop_map(|err| { + Value::Response(ResponseData { + committed: false, + data: Box::new(err), + }) + }) + .boxed(), + (ok_ty, TypeSignature::NoType) => prop_value(ok_ty) + .prop_map(|ok| { + Value::Response(ResponseData { + committed: true, + data: Box::new(ok), + }) + }) + .boxed(), + (ok_ty, err_ty) => prop::result::maybe_err(prop_value(ok_ty), prop_value(err_ty)) + .prop_map(|res| { + Value::Response(ResponseData { + committed: res.is_ok(), + data: res.map_or_else(Box::new, Box::new), + }) + }) + .boxed(), + } +} + +fn list(list_type_data: ListTypeData) -> impl Strategy { + prop::collection::vec( + prop_value(list_type_data.get_list_item_type().clone()), + 0..=list_type_data.get_max_len() as usize, + ) + .prop_map(move |v| { + Value::Sequence(SequenceData::List(ListData { + data: v, + type_signature: list_type_data.clone(), + })) + }) +} + +fn tuple(tuple_ty: TupleTypeSignature) -> impl Strategy { + let fields: Vec<_> = tuple_ty.get_type_map().keys().cloned().collect(); + let strategies: Vec<_> = tuple_ty + .get_type_map() + .values() + .cloned() + .map(prop_value) + .collect(); + strategies.prop_map(move |vec_values| { + TupleData { + type_signature: tuple_ty.clone(), + data_map: fields.clone().into_iter().zip(vec_values).collect(), + } + .into() + }) +} + +fn standard_principal() -> impl Strategy { + (0u8..32, prop::collection::vec(any::(), 20)) + .prop_map(|(v, hash)| { + Value::Principal(PrincipalData::Standard(StandardPrincipalData( + v, + hash.try_into().unwrap(), + ))) + }) + .no_shrink() +} + +fn qualified_principal() -> impl Strategy { + (standard_principal(), "[a-zA-Z]{1,40}").prop_map(|(issuer_value, name)| { + let Value::Principal(PrincipalData::Standard(issuer)) = issuer_value else { + unreachable!() + }; + let name = ContractName::from(&*name); + Value::Principal(PrincipalData::Contract(QualifiedContractIdentifier { + issuer, + name, + })) + }) +} + +trait TypePrinter { + fn type_string(&self) -> String; +} + +impl TypePrinter for PropValue { + fn type_string(&self) -> String { + self.0.type_string() + } +} + +impl TypePrinter for Value { + fn type_string(&self) -> String { + match &self { + Value::Int(_) => type_string(&TypeSignature::IntType), + Value::UInt(_) => type_string(&TypeSignature::UIntType), + Value::Bool(_) => type_string(&TypeSignature::BoolType), + Value::Sequence(SequenceData::Buffer(length)) => { + type_string(&TypeSignature::SequenceType(SequenceSubtype::BufferType( + length + .len() + .expect("Failed to get buffer length from sequence data"), + ))) + } + Value::Sequence(SequenceData::String(CharType::ASCII(data))) => type_string( + &TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII( + data.len() + .expect("Failed to get ASCII string length from sequence data"), + ))), + ), + Value::Sequence(SequenceData::String(CharType::UTF8(data))) => type_string( + &TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8( + StringUTF8Length::try_from(u32::from( + data.len() + .expect("Failed to get UTF8 string length from sequence data"), + )) + .unwrap_or(StringUTF8Length::try_from(MAX_VALUE_SIZE / 4).unwrap()), + ))), + ), + Value::Optional(inner) => inner.type_string(), + Value::Response(inner) => inner.type_string(), + Value::Sequence(SequenceData::List(list_data)) => list_data.type_string(), + Value::Tuple(data) => data.type_string(), + Value::Principal(_) => type_string(&TypeSignature::PrincipalType), + Value::CallableContract(_) => type_string(&TypeSignature::PrincipalType), + } + } +} + +impl TypePrinter for OptionalData { + fn type_string(&self) -> String { + let inner = match self.data { + Some(ref inner) => inner.type_string(), + None => "int".to_owned(), // We need to default to something here + }; + format!("(optional {inner})") + } +} + +impl TypePrinter for ResponseData { + fn type_string(&self) -> String { + let (ok_string, err_string) = if self.committed { + (self.data.type_string(), "int".to_owned()) + } else { + ("int".to_owned(), self.data.type_string()) + }; + format!("(response {} {})", ok_string, err_string) + } +} + +impl TypePrinter for ListData { + fn type_string(&self) -> String { + format!( + "(list {} {})", + self.data.len(), + type_string(self.type_signature.get_list_item_type()) + ) + } +} + +impl TypePrinter for TupleData { + fn type_string(&self) -> String { + type_string(&TypeSignature::TupleType(self.type_signature.clone())) + } +} + +pub fn type_string(ty: &TypeSignature) -> String { + match ty { + TypeSignature::IntType => "int".to_owned(), + TypeSignature::UIntType => "uint".to_owned(), + TypeSignature::BoolType => "bool".to_owned(), + TypeSignature::OptionalType(inner) => format!("(optional {})", type_string(inner)), + TypeSignature::ResponseType(inner) => format!( + "(response {} {})", + type_string(&inner.0), + type_string(&inner.1) + ), + TypeSignature::SequenceType(SequenceSubtype::BufferType(len)) => format!("(buff {len})"), + TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII(len))) => { + format!("(string-ascii {len})") + } + TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8(len))) => { + format!("(string-utf8 {len})") + } + TypeSignature::SequenceType(SequenceSubtype::ListType(list_type_data)) => { + format!( + "(list {} {})", + list_type_data.get_max_len(), + type_string(list_type_data.get_list_item_type()) + ) + } + TypeSignature::TupleType(tuple_ty) => { + let mut s = String::new(); + s.push('{'); + for (key, value) in tuple_ty.get_type_map() { + s.push_str(key); + s.push(':'); + s.push_str(&type_string(value)); + s.push(','); + } + s.push('}'); + s + } + TypeSignature::PrincipalType => "principal".to_owned(), + TypeSignature::CallableType(_) => "principal".to_owned(), + TypeSignature::TraitReferenceType(_) => "principal".to_owned(), + TypeSignature::NoType => "int".to_owned(), // Use "int" as a default type + TypeSignature::ListUnionType(_) => unreachable!(), + } +} \ No newline at end of file From 47b022f2e96775e4a69015789933603121468319 Mon Sep 17 00:00:00 2001 From: Anthony Caccia Date: Tue, 5 Mar 2024 16:20:08 +0100 Subject: [PATCH 12/28] feat(clarity-proptest): add a contract strategy stub --- clarity-proptest/src/lib.rs | 169 +++++++++++++++--------------------- 1 file changed, 68 insertions(+), 101 deletions(-) diff --git a/clarity-proptest/src/lib.rs b/clarity-proptest/src/lib.rs index 69a0327142..377d43de1f 100644 --- a/clarity-proptest/src/lib.rs +++ b/clarity-proptest/src/lib.rs @@ -1,5 +1,4 @@ -use std::hash::Hash; -use clarity::types::StacksHashMap; +use clarity::types::{StacksHashMap, StacksHashSet}; use clarity::vm::contracts::Contract; use clarity::vm::types::{ ASCIIData, BuffData, CharType, ListData, ListTypeData, OptionalData, PrincipalData, @@ -7,108 +6,76 @@ use clarity::vm::types::{ StandardPrincipalData, StringSubtype, StringUTF8Length, TupleData, TupleTypeSignature, TypeSignature, UTF8Data, Value, MAX_VALUE_SIZE, }; -use clarity::vm::{ContractContext, ContractName}; +use clarity::vm::{ClarityName, ContractContext, ContractName}; use proptest::prelude::*; -use proptest::sample::SizeRange; - -// pub fn contract() -> impl Strategy { -// (contract_context()) -// .prop_map(|ctx| Contract { contract_context: ctx }) -//} - -// pub struct ContractContext { -// pub contract_identifier: QualifiedContractIdentifier, -// pub variables: HashMap, -// pub functions: HashMap, -// pub defined_traits: HashMap>, -// pub implemented_traits: HashSet, -// // tracks the names of NFTs, FTs, Maps, and Data Vars. -// // used for ensuring that they never are defined twice. -// pub persisted_names: HashSet, -// // track metadata for contract defined storage -// pub meta_data_map: HashMap, -// pub meta_data_var: HashMap, -// pub meta_nft: HashMap, -// pub meta_ft: HashMap, -// pub data_size: u64, -// /// track the clarity version of the contract -// clarity_version: ClarityVersion, -// } - -pub fn stacks_hashmap( - key_strategy: impl Strategy, - value_strategy: impl Strategy, - size: impl Into -) -> impl Strategy> { - prop::collection::hash_map( - key_strategy, - value_strategy, - size - ) - .prop_map(|map| StacksHashMap(map.into_iter().collect()) + +pub fn contract() -> impl Strategy { + fn clarity_name() -> impl Strategy { + "[a-z]{40}".prop_map(|s| s.try_into().unwrap()) + } + ( + // contract_identifier + qualified_principal().prop_map(|p| match p { + Value::Principal(PrincipalData::Contract(qual)) => qual, + _ => unreachable!(), + }), + // variables + prop::collection::vec((clarity_name(), PropValue::any().prop_map_into()), 0..8) + .prop_map(|v| StacksHashMap(v.into_iter().collect())), + // functions + Just(StacksHashMap::new()), + // defined_traits + Just(StacksHashMap::new()), + // implemented_traits + Just(StacksHashSet::new()), + // persisted_names + Just(StacksHashSet::new()), + // meta_data_map + Just(StacksHashMap::new()), + // meta_data_var + Just(StacksHashMap::new()), + // meta_nft + Just(StacksHashMap::new()), + // meta_ft + Just(StacksHashMap::new()), + // data_size + 0u64..64, + // clarity_version + Just(clarity::vm::ClarityVersion::Clarity2), ) + .prop_map( + |( + contract_identifier, + variables, + functions, + defined_traits, + implemented_traits, + persisted_names, + meta_data_map, + meta_data_var, + meta_nft, + meta_ft, + data_size, + clarity_version, + )| { + let mut cc = ContractContext::new(contract_identifier, clarity_version); + cc.variables = variables; + cc.functions = functions; + cc.defined_traits = defined_traits; + cc.implemented_traits = implemented_traits; + cc.persisted_names = persisted_names; + cc.meta_data_map = meta_data_map; + cc.meta_data_var = meta_data_var; + cc.meta_nft = meta_nft; + cc.meta_ft = meta_ft; + cc.data_size = data_size; + Contract { + contract_context: cc, + } + }, + ) } -// pub fn contract_context() -> impl Strategy { -// let x = stacks_hashmap( -// "[a-zA-Z]{1,40}".prop_map_into(), -// prop_signature().prop_flat_map(prop_value), -// 0..16 -// ); - -// ( -// qualified_principal(), -// stacks_hashmap( -// "[a-zA-Z]{1,40}".prop_map_into(), -// prop_signature().prop_flat_map(prop_value), -// 0..16 -// ), -// stacks_hashmap("[a-zA-Z]{1,40}", defined_function(), 0..16), -// stacks_hashmap("[a-zA-Z]{1,40}", stacks_hashmap( -// "[a-zA-Z]{1,40}", -// function_signature(), -// 0..16 -// ), 0..16), -// prop::collection::hash_set(trait_identifier(), 0..16), -// prop::collection::hash_set("[a-zA-Z]{1,40}", 0..16), -// stacks_hashmap("[a-zA-Z]{1,40}", data_map_metadata(), 0..16), -// stacks_hashmap("[a-zA-Z]{1,40}", data_variable_metadata(), 0..16), -// stacks_hashmap("[a-zA-Z]{1,40}", non_fungible_token_metadata(), 0..16), -// stacks_hashmap("[a-zA-Z]{1,40}", fungible_token_metadata(), 0..16), -// 0u64..u64::MAX, -// clarity_version(), -// ) -// .prop_map(|( -// contract_identifier, -// variables, -// functions, -// defined_traits, -// implemented_traits, -// persisted_names, -// meta_data_map, -// meta_data_var, -// meta_nft, -// meta_ft, -// data_size, -// clarity_version, -// )| { -// ContractContext { -// contract_identifier, -// variables, -// functions, -// defined_traits, -// implemented_traits, -// persisted_names, -// meta_data_map, -// meta_data_var, -// meta_nft, -// meta_ft, -// data_size, -// clarity_version, -// } -// }) -// } - pub fn prop_signature() -> impl Strategy { let leaf = prop_oneof![ Just(TypeSignature::IntType), @@ -575,4 +542,4 @@ pub fn type_string(ty: &TypeSignature) -> String { TypeSignature::NoType => "int".to_owned(), // Use "int" as a default type TypeSignature::ListUnionType(_) => unreachable!(), } -} \ No newline at end of file +} From bde7e771babe58d52a18f44df0e5b59f1cb26ccc Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Mon, 4 Mar 2024 15:34:49 +0100 Subject: [PATCH 13/28] fix: resolve DNS/hostnames for signer node_host value #4466 --- stacks-signer/src/client/stackerdb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stacks-signer/src/client/stackerdb.rs b/stacks-signer/src/client/stackerdb.rs index 78275f56cf..aca184140a 100644 --- a/stacks-signer/src/client/stackerdb.rs +++ b/stacks-signer/src/client/stackerdb.rs @@ -76,7 +76,7 @@ impl StackerDB { signers_message_stackerdb_sessions.insert( msg_id, StackerDBSession::new( - host, + host.to_string(), QualifiedContractIdentifier::new( stackerdb_issuer.into(), ContractName::from( From 99a543a69b925a10a83332874a601df0be1ea4b2 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Tue, 5 Mar 2024 16:24:13 +0100 Subject: [PATCH 14/28] wip: wrap hashbrown in fasade types --- stacks-common/Cargo.toml | 1 + .../src/deps_common/bitcoin/network/encodable.rs | 2 +- stacks-common/src/types/hashmap.rs | 16 +++++++++++++--- stacks-common/src/types/hashset.rs | 6 +++--- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/stacks-common/Cargo.toml b/stacks-common/Cargo.toml index 28a59dba11..38b1d89728 100644 --- a/stacks-common/Cargo.toml +++ b/stacks-common/Cargo.toml @@ -72,6 +72,7 @@ rstest = "0.11.0" rstest_reuse = "0.1.3" assert-json-diff = "1.0.0" rand_core = { workspace = true } +stacks-common = { path = ".", features = ["testing"] } [features] default = ["developer-mode"] diff --git a/stacks-common/src/deps_common/bitcoin/network/encodable.rs b/stacks-common/src/deps_common/bitcoin/network/encodable.rs index f14ee1fb85..540f96abed 100644 --- a/stacks-common/src/deps_common/bitcoin/network/encodable.rs +++ b/stacks-common/src/deps_common/bitcoin/network/encodable.rs @@ -32,7 +32,7 @@ use std::hash::Hash; use std::{mem, u32}; -use hashbrown::HashMap; +use crate::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::deps_common::bitcoin::network::serialize::{self, SimpleDecoder, SimpleEncoder}; use crate::deps_common::bitcoin::util::hash::Sha256dHash; diff --git a/stacks-common/src/types/hashmap.rs b/stacks-common/src/types/hashmap.rs index c4a09d2e2a..2b7de1046e 100644 --- a/stacks-common/src/types/hashmap.rs +++ b/stacks-common/src/types/hashmap.rs @@ -2,7 +2,7 @@ use std::hash::Hash; use std::iter::{FromIterator, IntoIterator}; use std::ops::{Deref, DerefMut}; -#[cfg(any(test, feature = "testing"))] +#[cfg(feature = "testing")] use fake::{Dummy, Fake, Faker}; use hashbrown::HashMap; use rand::Rng; @@ -19,6 +19,16 @@ where pub fn new() -> Self { StacksHashMap(HashMap::new()) } + + pub fn with_capacity(capacity: usize) -> Self { + StacksHashMap(HashMap::with_capacity(capacity)) + } +} + +impl Default for StacksHashMap { + fn default() -> Self { + StacksHashMap(HashMap::new()) + } } impl<'a, K, V> Deref for StacksHashMap @@ -54,7 +64,7 @@ where } } -#[cfg(any(test, feature = "testing"))] +#[cfg(feature = "testing")] impl Dummy for StacksHashMap where K: Eq + Hash + Dummy, @@ -67,4 +77,4 @@ where } StacksHashMap(map) } -} +} \ No newline at end of file diff --git a/stacks-common/src/types/hashset.rs b/stacks-common/src/types/hashset.rs index 3c534ad799..45dd75461b 100644 --- a/stacks-common/src/types/hashset.rs +++ b/stacks-common/src/types/hashset.rs @@ -2,12 +2,12 @@ use std::hash::Hash; use std::iter::{FromIterator, IntoIterator}; use std::ops::{Deref, DerefMut}; -#[cfg(any(test, feature = "testing"))] +#[cfg(feature = "testing")] use fake::{Dummy, Fake, Faker}; use hashbrown::HashSet; use rand::Rng; -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct StacksHashSet(pub hashbrown::HashSet) where T: Eq + Hash; @@ -54,7 +54,7 @@ where } } -#[cfg(any(test, feature = "testing"))] +#[cfg(feature = "testing")] impl Dummy for StacksHashSet where T: Dummy + Eq + Hash, From 5a304c8f7e7c7d03ba999599061a022164d9e435 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Tue, 5 Mar 2024 16:24:27 +0100 Subject: [PATCH 15/28] wip: wrap hashbrown in fasade types --- Cargo.lock | 1 + clarity/src/vm/analysis/arithmetic_checker/mod.rs | 2 +- clarity/src/vm/analysis/read_only_checker/mod.rs | 3 +-- clarity/src/vm/analysis/trait_checker/mod.rs | 3 +-- clarity/src/vm/analysis/type_checker/contexts.rs | 3 +-- .../src/vm/analysis/type_checker/v2_05/contexts.rs | 2 +- clarity/src/vm/analysis/type_checker/v2_05/mod.rs | 3 +-- .../src/vm/analysis/type_checker/v2_1/contexts.rs | 2 +- clarity/src/vm/analysis/type_checker/v2_1/mod.rs | 5 ++--- clarity/src/vm/analysis/types.rs | 3 +-- clarity/src/vm/ast/definition_sorter/mod.rs | 2 +- clarity/src/vm/ast/mod.rs | 2 +- clarity/src/vm/ast/sugar_expander/mod.rs | 2 +- clarity/src/vm/ast/traits_resolver/mod.rs | 4 ++-- clarity/src/vm/ast/types.rs | 2 +- clarity/src/vm/contexts.rs | 1 - clarity/src/vm/costs/mod.rs | 2 +- clarity/src/vm/coverage.rs | 2 +- clarity/src/vm/database/key_value_wrapper.rs | 2 +- clarity/src/vm/database/mod.rs | 2 +- clarity/src/vm/docs/contracts.rs | 2 +- clarity/src/vm/fakes.rs | 2 +- clarity/src/vm/mod.rs | 2 +- clarity/src/vm/tests/principals.rs | 2 +- clarity/src/vm/types/serialization.rs | 2 +- clarity/src/vm/types/signatures.rs | 14 +++++++------- contrib/tools/relay-server/src/http.rs | 2 +- contrib/tools/relay-server/src/state.rs | 2 +- contrib/tools/relay-server/src/url.rs | 2 +- libsigner/src/http.rs | 2 +- libsigner/src/messages.rs | 4 ++-- libsigner/src/tests/http.rs | 2 +- stacks-signer/src/client/mod.rs | 2 +- stacks-signer/src/client/stackerdb.rs | 2 +- stacks-signer/src/config.rs | 2 +- stacks-signer/src/runloop.rs | 2 +- stacks-signer/src/signer.rs | 2 +- stackslib/src/chainstate/nakamoto/test_signers.rs | 2 +- stackslib/src/chainstate/nakamoto/tests/node.rs | 2 +- stackslib/src/chainstate/stacks/boot/docs.rs | 2 +- testnet/stacks-node/src/nakamoto_node/miner.rs | 2 +- 41 files changed, 49 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f75436fa9a..6676723a8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3546,6 +3546,7 @@ dependencies = [ "slog", "slog-json", "slog-term", + "stacks-common", "time 0.2.27", "winapi 0.3.9", "wsts", diff --git a/clarity/src/vm/analysis/arithmetic_checker/mod.rs b/clarity/src/vm/analysis/arithmetic_checker/mod.rs index 5595905a48..622a6500eb 100644 --- a/clarity/src/vm/analysis/arithmetic_checker/mod.rs +++ b/clarity/src/vm/analysis/arithmetic_checker/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use hashbrown::HashMap; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; pub use super::errors::{ check_argument_count, check_arguments_at_least, CheckError, CheckErrors, CheckResult, diff --git a/clarity/src/vm/analysis/read_only_checker/mod.rs b/clarity/src/vm/analysis/read_only_checker/mod.rs index b02923c1a1..9c3b602511 100644 --- a/clarity/src/vm/analysis/read_only_checker/mod.rs +++ b/clarity/src/vm/analysis/read_only_checker/mod.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use hashbrown::HashMap; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; pub use super::errors::{ check_argument_count, check_arguments_at_least, CheckError, CheckErrors, CheckResult, diff --git a/clarity/src/vm/analysis/trait_checker/mod.rs b/clarity/src/vm/analysis/trait_checker/mod.rs index 868c1d378e..4941dcb779 100644 --- a/clarity/src/vm/analysis/trait_checker/mod.rs +++ b/clarity/src/vm/analysis/trait_checker/mod.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use hashbrown::HashMap; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::analysis::errors::{CheckError, CheckErrors, CheckResult}; use crate::vm::analysis::types::{AnalysisPass, ContractAnalysis}; diff --git a/clarity/src/vm/analysis/type_checker/contexts.rs b/clarity/src/vm/analysis/type_checker/contexts.rs index b56214807a..5fcc31677d 100644 --- a/clarity/src/vm/analysis/type_checker/contexts.rs +++ b/clarity/src/vm/analysis/type_checker/contexts.rs @@ -14,8 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use hashbrown::HashMap; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap}; use crate::vm::analysis::errors::{CheckError, CheckErrors, CheckResult}; use crate::vm::types::signatures::CallableSubtype; diff --git a/clarity/src/vm/analysis/type_checker/v2_05/contexts.rs b/clarity/src/vm/analysis/type_checker/v2_05/contexts.rs index 2a11f6839f..c4198879d7 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/contexts.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/contexts.rs @@ -16,7 +16,7 @@ use std::collections::BTreeMap; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::analysis::errors::{CheckError, CheckErrors, CheckResult}; use crate::vm::analysis::types::ContractAnalysis; diff --git a/clarity/src/vm/analysis/type_checker/v2_05/mod.rs b/clarity/src/vm/analysis/type_checker/v2_05/mod.rs index 286e2e11fa..30699f46df 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/mod.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/mod.rs @@ -20,8 +20,7 @@ pub mod natives; use std::collections::BTreeMap; -use hashbrown::HashMap; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use self::contexts::ContractContext; pub use self::natives::{SimpleNativeFunction, TypedNativeFunction}; diff --git a/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs b/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs index 8cbed1a416..b61700c58d 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs @@ -16,7 +16,7 @@ use std::collections::BTreeMap; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::analysis::errors::{CheckError, CheckErrors, CheckResult}; use crate::vm::analysis::types::ContractAnalysis; diff --git a/clarity/src/vm/analysis/type_checker/v2_1/mod.rs b/clarity/src/vm/analysis/type_checker/v2_1/mod.rs index a0937e84c8..006ad08263 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/mod.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/mod.rs @@ -19,8 +19,7 @@ pub mod natives; use std::collections::BTreeMap; -use hashbrown::HashMap; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use self::contexts::ContractContext; pub use self::natives::{SimpleNativeFunction, TypedNativeFunction}; @@ -754,7 +753,7 @@ fn clarity2_inner_type_check_type( TypeSignature::CallableType(CallableSubtype::Trait(_)), ) => { // Verify that all types in the union implement this trait - for subtype in types { + for subtype in types.into_iter() { clarity2_inner_type_check_type( db, contract_context, diff --git a/clarity/src/vm/analysis/types.rs b/clarity/src/vm/analysis/types.rs index 60a93f9c79..75691699cd 100644 --- a/clarity/src/vm/analysis/types.rs +++ b/clarity/src/vm/analysis/types.rs @@ -16,8 +16,7 @@ use std::collections::{BTreeMap, BTreeSet}; -use hashbrown::HashMap; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::analysis::analysis_db::AnalysisDatabase; use crate::vm::analysis::contract_interface_builder::ContractInterface; diff --git a/clarity/src/vm/ast/definition_sorter/mod.rs b/clarity/src/vm/ast/definition_sorter/mod.rs index eee6625310..ba99999aac 100644 --- a/clarity/src/vm/ast/definition_sorter/mod.rs +++ b/clarity/src/vm/ast/definition_sorter/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::ast::errors::{ParseError, ParseErrors, ParseResult}; use crate::vm::ast::types::{BuildASTPass, ContractAST}; diff --git a/clarity/src/vm/ast/mod.rs b/clarity/src/vm/ast/mod.rs index 1cff959695..e018eb44d6 100644 --- a/clarity/src/vm/ast/mod.rs +++ b/clarity/src/vm/ast/mod.rs @@ -319,7 +319,7 @@ pub fn build_ast( #[cfg(test)] mod test { - use hashbrown::HashMap; + use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::types::StacksEpochId; use crate::vm::ast::errors::ParseErrors; diff --git a/clarity/src/vm/ast/sugar_expander/mod.rs b/clarity/src/vm/ast/sugar_expander/mod.rs index 7fc6064b85..7e19758ed4 100644 --- a/clarity/src/vm/ast/sugar_expander/mod.rs +++ b/clarity/src/vm/ast/sugar_expander/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::ast::errors::{ParseError, ParseErrors, ParseResult}; use crate::vm::ast::types::{BuildASTPass, ContractAST, PreExpressionsDrain}; diff --git a/clarity/src/vm/ast/traits_resolver/mod.rs b/clarity/src/vm/ast/traits_resolver/mod.rs index 4cdb2f54a9..16a54eddea 100644 --- a/clarity/src/vm/ast/traits_resolver/mod.rs +++ b/clarity/src/vm/ast/traits_resolver/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::analysis::AnalysisDatabase; use crate::vm::ast::errors::{ParseError, ParseErrors, ParseResult}; @@ -158,7 +158,7 @@ impl TraitsResolver { }; } - for (trait_reference, expr) in referenced_traits { + for (trait_reference, expr) in referenced_traits.into_iter() { if !contract_ast .referenced_traits .contains_key(&trait_reference) diff --git a/clarity/src/vm/ast/types.rs b/clarity/src/vm/ast/types.rs index aedd31eae3..2c3679fe33 100644 --- a/clarity/src/vm/ast/types.rs +++ b/clarity/src/vm/ast/types.rs @@ -16,7 +16,7 @@ use std::vec::Drain; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::ast::errors::ParseResult; use crate::vm::representations::{PreSymbolicExpression, SymbolicExpression, TraitDefinition}; diff --git a/clarity/src/vm/contexts.rs b/clarity/src/vm/contexts.rs index 2b025fd946..d263fa5ec8 100644 --- a/clarity/src/vm/contexts.rs +++ b/clarity/src/vm/contexts.rs @@ -18,7 +18,6 @@ use std::collections::{BTreeMap, BTreeSet}; use std::fmt; use std::mem::replace; -//use hashbrown::{HashMap, HashSet}; use serde::Serialize; use serde_json::json; use stacks_common::consts::CHAIN_ID_TESTNET; diff --git a/clarity/src/vm/costs/mod.rs b/clarity/src/vm/costs/mod.rs index f70fbe6990..e7710f54e1 100644 --- a/clarity/src/vm/costs/mod.rs +++ b/clarity/src/vm/costs/mod.rs @@ -17,7 +17,7 @@ use std::collections::BTreeMap; use std::{cmp, fmt}; -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use lazy_static::lazy_static; use rusqlite::types::{FromSql, FromSqlResult, ToSql, ToSqlOutput, ValueRef}; use serde::{Deserialize, Serialize}; diff --git a/clarity/src/vm/coverage.rs b/clarity/src/vm/coverage.rs index be8a647e9c..117d96ed84 100644 --- a/clarity/src/vm/coverage.rs +++ b/clarity/src/vm/coverage.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::fs::File; use std::io::Write; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use serde_json::Value as JsonValue; use super::functions::define::DefineFunctionsParsed; diff --git a/clarity/src/vm/database/key_value_wrapper.rs b/clarity/src/vm/database/key_value_wrapper.rs index 65de1adce4..db28a7858e 100644 --- a/clarity/src/vm/database/key_value_wrapper.rs +++ b/clarity/src/vm/database/key_value_wrapper.rs @@ -16,7 +16,7 @@ use std::hash::Hash; -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::types::chainstate::StacksBlockId; use stacks_common::types::StacksEpochId; use stacks_common::util::hash::Sha512Trunc256Sum; diff --git a/clarity/src/vm/database/mod.rs b/clarity/src/vm/database/mod.rs index 0753271d29..ec49f0261d 100644 --- a/clarity/src/vm/database/mod.rs +++ b/clarity/src/vm/database/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; pub use self::clarity_db::{ BurnStateDB, ClarityDatabase, HeadersDB, StoreType, NULL_BURN_STATE_DB, NULL_HEADER_DB, diff --git a/clarity/src/vm/docs/contracts.rs b/clarity/src/vm/docs/contracts.rs index 7426be7966..4f6fb9540e 100644 --- a/clarity/src/vm/docs/contracts.rs +++ b/clarity/src/vm/docs/contracts.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::consts::CHAIN_ID_TESTNET; use stacks_common::types::StacksEpochId; diff --git a/clarity/src/vm/fakes.rs b/clarity/src/vm/fakes.rs index 707c67ad77..7de7530c4c 100644 --- a/clarity/src/vm/fakes.rs +++ b/clarity/src/vm/fakes.rs @@ -28,7 +28,7 @@ pub mod raw { use fake::locales::EN; use fake::{Dummy, Fake, Faker}; - use hashbrown::HashMap; + use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use rand::Rng; use super::ENGLISH_WORDS; diff --git a/clarity/src/vm/mod.rs b/clarity/src/vm/mod.rs index 27127f63f0..a877ca15ff 100644 --- a/clarity/src/vm/mod.rs +++ b/clarity/src/vm/mod.rs @@ -589,7 +589,7 @@ pub fn execute_v2(program: &str) -> Result> { #[cfg(test)] mod test { - use hashbrown::HashMap; + use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::consts::CHAIN_ID_TESTNET; use stacks_common::types::StacksEpochId; diff --git a/clarity/src/vm/tests/principals.rs b/clarity/src/vm/tests/principals.rs index 78fcf17659..a77f9d3517 100644 --- a/clarity/src/vm/tests/principals.rs +++ b/clarity/src/vm/tests/principals.rs @@ -1,4 +1,4 @@ -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::types::StacksEpochId; use stacks_common::util::hash::hex_bytes; diff --git a/clarity/src/vm/types/serialization.rs b/clarity/src/vm/types/serialization.rs index c7a92203b4..6db47be655 100644 --- a/clarity/src/vm/types/serialization.rs +++ b/clarity/src/vm/types/serialization.rs @@ -17,7 +17,7 @@ use std::io::{Read, Write}; use std::{cmp, error, fmt, str}; -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use lazy_static::lazy_static; use serde_json::Value as JSONValue; use stacks_common::codec::{Error as codec_error, StacksMessageCodec}; diff --git a/clarity/src/vm/types/signatures.rs b/clarity/src/vm/types/signatures.rs index 84f6d90fb4..ee4089565e 100644 --- a/clarity/src/vm/types/signatures.rs +++ b/clarity/src/vm/types/signatures.rs @@ -20,7 +20,7 @@ use std::hash::{Hash, Hasher}; use std::{cmp, fmt}; // TypeSignatures -use hashbrown::HashSet; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use lazy_static::lazy_static; use stacks_common::address::c32; use stacks_common::types::StacksEpochId; @@ -810,7 +810,7 @@ impl TypeSignature { ListUnionType(types) => { let mut is_trait = None; let mut is_principal = true; - for partial in types { + for partial in types.into_iter() { match partial { CallableSubtype::Principal(_) => { if is_trait.is_some() { @@ -1332,7 +1332,7 @@ impl TypeSignature { if x == y { Ok(a.clone()) } else { - Ok(ListUnionType(HashSet::from([x.clone(), y.clone()]))) + Ok(ListUnionType(HashSet::from_iter([x.clone(), y.clone()]))) } } (ListUnionType(l), CallableType(c)) | (CallableType(c), ListUnionType(l)) => { @@ -1344,7 +1344,7 @@ impl TypeSignature { | (CallableType(CallableSubtype::Principal(_)), PrincipalType) => Ok(PrincipalType), (PrincipalType, ListUnionType(l)) | (ListUnionType(l), PrincipalType) => { let mut all_principals = true; - for ty in l { + for ty in l.into_iter() { match ty { CallableSubtype::Trait(_) => { all_principals = false; @@ -2133,7 +2133,7 @@ mod test { contract_identifier: QualifiedContractIdentifier::transient(), }), ]; - let list_union = ListUnionType(callables.clone().into()); + let list_union = ListUnionType(callables.to_vec().into_iter().collect()); let callables2 = [ CallableSubtype::Principal(QualifiedContractIdentifier::local("bar").unwrap()), CallableSubtype::Trait(TraitIdentifier { @@ -2141,7 +2141,7 @@ mod test { contract_identifier: QualifiedContractIdentifier::transient(), }), ]; - let list_union2 = ListUnionType(callables2.clone().into()); + let list_union2 = ListUnionType(callables2.to_vec().into_iter().collect()); let list_union_merged = ListUnionType(HashSet::from_iter( [callables, callables2].concat().iter().cloned(), )); @@ -2149,7 +2149,7 @@ mod test { CallableSubtype::Principal(QualifiedContractIdentifier::local("foo").unwrap()), CallableSubtype::Principal(QualifiedContractIdentifier::local("bar").unwrap()), ]; - let list_union_principals = ListUnionType(callable_principals.into()); + let list_union_principals = ListUnionType(callable_principals.to_vec().into_iter().collect()); let notype_pairs = [ // NoType with X should result in X diff --git a/contrib/tools/relay-server/src/http.rs b/contrib/tools/relay-server/src/http.rs index c84f833bee..c9d40ddbbf 100644 --- a/contrib/tools/relay-server/src/http.rs +++ b/contrib/tools/relay-server/src/http.rs @@ -1,6 +1,6 @@ use std::io::{Error, Read}; -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::to_io_result::ToIoResult; diff --git a/contrib/tools/relay-server/src/state.rs b/contrib/tools/relay-server/src/state.rs index 084779c8d4..ab526387d5 100644 --- a/contrib/tools/relay-server/src/state.rs +++ b/contrib/tools/relay-server/src/state.rs @@ -1,4 +1,4 @@ -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; #[derive(Default)] pub struct State { diff --git a/contrib/tools/relay-server/src/url.rs b/contrib/tools/relay-server/src/url.rs index aedc5711d8..0226881495 100644 --- a/contrib/tools/relay-server/src/url.rs +++ b/contrib/tools/relay-server/src/url.rs @@ -1,4 +1,4 @@ -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; pub trait QueryEx { fn url_query(&self) -> HashMap<&str, &str>; diff --git a/libsigner/src/http.rs b/libsigner/src/http.rs index 95f2e2b3cb..37770b814a 100644 --- a/libsigner/src/http.rs +++ b/libsigner/src/http.rs @@ -18,7 +18,7 @@ use std::io; use std::io::{Read, Write}; use std::net::SocketAddr; -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::codec::MAX_MESSAGE_LEN; use stacks_common::deps_common::httparse; use stacks_common::util::chunked_encoding::*; diff --git a/libsigner/src/messages.rs b/libsigner/src/messages.rs index 6135312a87..7f343af95d 100644 --- a/libsigner/src/messages.rs +++ b/libsigner/src/messages.rs @@ -29,7 +29,7 @@ use blockstack_lib::net::api::postblock_proposal::{ use blockstack_lib::util_lib::boot::boot_code_id; use clarity::vm::types::serialization::SerializationError; use clarity::vm::types::QualifiedContractIdentifier; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use serde::{Deserialize, Serialize}; use stacks_common::codec::{ read_next, read_next_at_most, read_next_exact, write_next, Error as CodecError, @@ -300,7 +300,7 @@ impl StacksMessageCodecExtensions for HashSet { fn inner_consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { write_next(fd, &(self.len() as u32))?; for i in self { - write_next(fd, i)?; + write_next(fd, &i)?; } Ok(()) } diff --git a/libsigner/src/tests/http.rs b/libsigner/src/tests/http.rs index d2b052fae9..ce4cbd902d 100644 --- a/libsigner/src/tests/http.rs +++ b/libsigner/src/tests/http.rs @@ -17,7 +17,7 @@ use std::io::{Read, Write}; use std::{io, str}; -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::chunked_encoding::*; use crate::error::{EventError, RPCError}; diff --git a/stacks-signer/src/client/mod.rs b/stacks-signer/src/client/mod.rs index 8f458811ff..7e3cfb1fcd 100644 --- a/stacks-signer/src/client/mod.rs +++ b/stacks-signer/src/client/mod.rs @@ -139,7 +139,7 @@ pub(crate) mod tests { use clarity::vm::costs::ExecutionCost; use clarity::vm::types::TupleData; use clarity::vm::Value as ClarityValue; - use hashbrown::{HashMap, HashSet}; + use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use rand::distributions::Standard; use rand::{thread_rng, Rng}; use rand_core::{OsRng, RngCore}; diff --git a/stacks-signer/src/client/stackerdb.rs b/stacks-signer/src/client/stackerdb.rs index aca184140a..d301ff6e03 100644 --- a/stacks-signer/src/client/stackerdb.rs +++ b/stacks-signer/src/client/stackerdb.rs @@ -19,7 +19,7 @@ use blockstack_lib::chainstate::stacks::StacksTransaction; use blockstack_lib::util_lib::boot::boot_code_addr; use clarity::vm::types::QualifiedContractIdentifier; use clarity::vm::ContractName; -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use libsigner::{SignerMessage, SignerSession, StackerDBSession, TRANSACTIONS_MSG_ID}; use libstackerdb::{StackerDBChunkAckData, StackerDBChunkData}; use slog::{slog_debug, slog_warn}; diff --git a/stacks-signer/src/config.rs b/stacks-signer/src/config.rs index 2897bfdf0b..f0b7642c87 100644 --- a/stacks-signer/src/config.rs +++ b/stacks-signer/src/config.rs @@ -20,7 +20,7 @@ use std::path::PathBuf; use std::time::Duration; use blockstack_lib::chainstate::stacks::TransactionVersion; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use serde::Deserialize; use stacks_common::address::{ AddressHashMode, C32_ADDRESS_VERSION_MAINNET_SINGLESIG, C32_ADDRESS_VERSION_TESTNET_SINGLESIG, diff --git a/stacks-signer/src/runloop.rs b/stacks-signer/src/runloop.rs index ef5ffacdc3..2cb3568648 100644 --- a/stacks-signer/src/runloop.rs +++ b/stacks-signer/src/runloop.rs @@ -20,7 +20,7 @@ use std::time::Duration; use blockstack_lib::chainstate::burn::ConsensusHashExtensions; use blockstack_lib::chainstate::stacks::boot::{NakamotoSignerEntry, SIGNERS_NAME}; use blockstack_lib::util_lib::boot::boot_code_id; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use libsigner::{SignerEvent, SignerRunLoop}; use slog::{slog_debug, slog_error, slog_info, slog_warn}; use stacks_common::types::chainstate::{ConsensusHash, StacksAddress, StacksPublicKey}; diff --git a/stacks-signer/src/signer.rs b/stacks-signer/src/signer.rs index 59962e5ae5..3abfadb19b 100644 --- a/stacks-signer/src/signer.rs +++ b/stacks-signer/src/signer.rs @@ -22,7 +22,7 @@ use blockstack_lib::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockVote}; use blockstack_lib::chainstate::stacks::boot::SIGNERS_VOTING_FUNCTION_NAME; use blockstack_lib::chainstate::stacks::StacksTransaction; use blockstack_lib::net::api::postblock_proposal::BlockValidateResponse; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use libsigner::{BlockRejection, BlockResponse, RejectCode, SignerEvent, SignerMessage}; use slog::{slog_debug, slog_error, slog_info, slog_warn}; use stacks_common::codec::{read_next, StacksMessageCodec}; diff --git a/stackslib/src/chainstate/nakamoto/test_signers.rs b/stackslib/src/chainstate/nakamoto/test_signers.rs index e797a66ba3..3791d89f37 100644 --- a/stackslib/src/chainstate/nakamoto/test_signers.rs +++ b/stackslib/src/chainstate/nakamoto/test_signers.rs @@ -22,7 +22,7 @@ use std::{fs, io}; use clarity::vm::clarity::ClarityConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; use clarity::vm::types::*; -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use rand::seq::SliceRandom; use rand::{CryptoRng, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; diff --git a/stackslib/src/chainstate/nakamoto/tests/node.rs b/stackslib/src/chainstate/nakamoto/tests/node.rs index a9da6c5379..d47794540c 100644 --- a/stackslib/src/chainstate/nakamoto/tests/node.rs +++ b/stackslib/src/chainstate/nakamoto/tests/node.rs @@ -22,7 +22,7 @@ use std::{fs, io}; use clarity::vm::clarity::ClarityConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; use clarity::vm::types::*; -use hashbrown::HashMap; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use rand::seq::SliceRandom; use rand::{CryptoRng, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; diff --git a/stackslib/src/chainstate/stacks/boot/docs.rs b/stackslib/src/chainstate/stacks/boot/docs.rs index 62580f384a..a0b2dd1b10 100644 --- a/stackslib/src/chainstate/stacks/boot/docs.rs +++ b/stackslib/src/chainstate/stacks/boot/docs.rs @@ -1,5 +1,5 @@ use clarity::vm::docs::contracts::{produce_docs_refs, ContractSupportDocs}; -use hashbrown::{HashMap, HashSet}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use super::STACKS_BOOT_CODE_MAINNET; diff --git a/testnet/stacks-node/src/nakamoto_node/miner.rs b/testnet/stacks-node/src/nakamoto_node/miner.rs index 3546e48b93..7fcc7ecb63 100644 --- a/testnet/stacks-node/src/nakamoto_node/miner.rs +++ b/testnet/stacks-node/src/nakamoto_node/miner.rs @@ -21,7 +21,7 @@ use std::time::{Duration, Instant}; use clarity::boot_util::boot_code_id; use clarity::vm::clarity::ClarityConnection; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; -use hashbrown::HashSet; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use libsigner::{ BlockResponse, RejectCode, SignerMessage, SignerSession, StackerDBSession, BLOCK_MSG_ID, TRANSACTIONS_MSG_ID, From 80defd46ce733e9cb1a9bff8c8768ff81054d969 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Tue, 5 Mar 2024 18:53:17 +0100 Subject: [PATCH 16/28] wip: fixes for StacksHashMap and StacksHashSet --- Cargo.lock | 1 + .../src/vm/analysis/type_checker/v2_1/mod.rs | 2 +- clarity/src/vm/ast/traits_resolver/mod.rs | 4 +- clarity/src/vm/costs/mod.rs | 8 +++- clarity/src/vm/types/signatures.rs | 4 +- contrib/tools/relay-server/Cargo.toml | 1 + libsigner/src/messages.rs | 17 +++++--- stacks-common/src/types/hashmap.rs | 36 +++++++++++++++- stacks-common/src/types/hashset.rs | 42 +++++++++++++++++++ stacks-signer/src/client/mod.rs | 4 +- stacks-signer/src/runloop.rs | 12 ++++-- stacks-signer/src/signer.rs | 23 ++++++---- .../src/chainstate/nakamoto/signer_set.rs | 3 +- .../src/chainstate/nakamoto/test_signers.rs | 6 +-- .../src/chainstate/nakamoto/tests/mod.rs | 19 +++++---- .../src/chainstate/nakamoto/tests/node.rs | 2 +- stackslib/src/clarity_vm/tests/costs.rs | 6 +-- .../stacks-node/src/nakamoto_node/miner.rs | 5 +-- 18 files changed, 148 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6676723a8f..81a8416c27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2854,6 +2854,7 @@ name = "relay-server" version = "0.0.1" dependencies = [ "hashbrown 0.14.3", + "stacks-common", ] [[package]] diff --git a/clarity/src/vm/analysis/type_checker/v2_1/mod.rs b/clarity/src/vm/analysis/type_checker/v2_1/mod.rs index 006ad08263..333a3d567e 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/mod.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/mod.rs @@ -753,7 +753,7 @@ fn clarity2_inner_type_check_type( TypeSignature::CallableType(CallableSubtype::Trait(_)), ) => { // Verify that all types in the union implement this trait - for subtype in types.into_iter() { + for subtype in types.iter() { clarity2_inner_type_check_type( db, contract_context, diff --git a/clarity/src/vm/ast/traits_resolver/mod.rs b/clarity/src/vm/ast/traits_resolver/mod.rs index 16a54eddea..4815694b7d 100644 --- a/clarity/src/vm/ast/traits_resolver/mod.rs +++ b/clarity/src/vm/ast/traits_resolver/mod.rs @@ -158,10 +158,10 @@ impl TraitsResolver { }; } - for (trait_reference, expr) in referenced_traits.into_iter() { + for (trait_reference, expr) in referenced_traits.iter() { if !contract_ast .referenced_traits - .contains_key(&trait_reference) + .contains_key(trait_reference) { let mut err = ParseError::new(ParseErrors::TraitReferenceUnknown( trait_reference.to_string(), diff --git a/clarity/src/vm/costs/mod.rs b/clarity/src/vm/costs/mod.rs index e7710f54e1..f11b0c40b0 100644 --- a/clarity/src/vm/costs/mod.rs +++ b/clarity/src/vm/costs/mod.rs @@ -207,8 +207,12 @@ impl From for SerializedCostStateSummary { cost_function_references, } = other; SerializedCostStateSummary { - contract_call_circuits: contract_call_circuits.into_iter().collect(), - cost_function_references: cost_function_references.into_iter().collect(), + contract_call_circuits: contract_call_circuits.iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(), + cost_function_references: cost_function_references.iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(), } } } diff --git a/clarity/src/vm/types/signatures.rs b/clarity/src/vm/types/signatures.rs index ee4089565e..c694c33b8c 100644 --- a/clarity/src/vm/types/signatures.rs +++ b/clarity/src/vm/types/signatures.rs @@ -810,7 +810,7 @@ impl TypeSignature { ListUnionType(types) => { let mut is_trait = None; let mut is_principal = true; - for partial in types.into_iter() { + for partial in types.iter() { match partial { CallableSubtype::Principal(_) => { if is_trait.is_some() { @@ -1344,7 +1344,7 @@ impl TypeSignature { | (CallableType(CallableSubtype::Principal(_)), PrincipalType) => Ok(PrincipalType), (PrincipalType, ListUnionType(l)) | (ListUnionType(l), PrincipalType) => { let mut all_principals = true; - for ty in l.into_iter() { + for ty in l.iter() { match ty { CallableSubtype::Trait(_) => { all_principals = false; diff --git a/contrib/tools/relay-server/Cargo.toml b/contrib/tools/relay-server/Cargo.toml index 3736469065..5c796dcf16 100644 --- a/contrib/tools/relay-server/Cargo.toml +++ b/contrib/tools/relay-server/Cargo.toml @@ -9,3 +9,4 @@ path = "src/main.rs" [dependencies] hashbrown = { workspace = true } +stacks_common = { path = "../../../stacks-common", package = "stacks-common" } diff --git a/libsigner/src/messages.rs b/libsigner/src/messages.rs index 7f343af95d..d828eff37e 100644 --- a/libsigner/src/messages.rs +++ b/libsigner/src/messages.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use std::hash::Hash; use std::io::{Read, Write}; use std::net::{SocketAddr, TcpListener, TcpStream}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -299,7 +300,7 @@ impl StacksMessageCodecExtensions for BadPrivateShare { impl StacksMessageCodecExtensions for HashSet { fn inner_consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { write_next(fd, &(self.len() as u32))?; - for i in self { + for i in self.clone() { write_next(fd, &i)?; } Ok(()) @@ -321,14 +322,17 @@ impl StacksMessageCodecExtensions for DkgFailure { DkgFailure::BadState => write_next(fd, &0u8), DkgFailure::MissingPublicShares(shares) => { write_next(fd, &1u8)?; + let shares: HashSet = shares.into(); shares.inner_consensus_serialize(fd) } DkgFailure::BadPublicShares(shares) => { write_next(fd, &2u8)?; + let shares: HashSet = shares.into(); shares.inner_consensus_serialize(fd) } DkgFailure::MissingPrivateShares(shares) => { write_next(fd, &3u8)?; + let shares: HashSet = shares.into(); shares.inner_consensus_serialize(fd) } DkgFailure::BadPrivateShares(shares) => { @@ -348,15 +352,15 @@ impl StacksMessageCodecExtensions for DkgFailure { 0 => DkgFailure::BadState, 1 => { let set = HashSet::::inner_consensus_deserialize(fd)?; - DkgFailure::MissingPublicShares(set) + DkgFailure::MissingPublicShares(set.into()) } 2 => { let set = HashSet::::inner_consensus_deserialize(fd)?; - DkgFailure::BadPublicShares(set) + DkgFailure::BadPublicShares(set.into()) } 3 => { let set = HashSet::::inner_consensus_deserialize(fd)?; - DkgFailure::MissingPrivateShares(set) + DkgFailure::MissingPrivateShares(set.into()) } 4 => { let mut map = HashMap::new(); @@ -366,7 +370,7 @@ impl StacksMessageCodecExtensions for DkgFailure { let bad_share = BadPrivateShare::inner_consensus_deserialize(fd)?; map.insert(i, bad_share); } - DkgFailure::BadPrivateShares(map) + DkgFailure::BadPrivateShares(map.into()) } _ => { return Err(CodecError::DeserializeError(format!( @@ -541,11 +545,13 @@ impl StacksMessageCodecExtensions for DkgPrivateShares { let id = read_next::(fd)?; let num_share_map = read_next::(fd)?; let mut share_map = HashMap::new(); + for _ in 0..num_share_map { let id = read_next::(fd)?; let share: Vec = read_next(fd)?; share_map.insert(id, share); } + let share_map: hashbrown::HashMap<_, _> = share_map.into(); shares.push((id, share_map)); } Ok(DkgPrivateShares { @@ -1338,6 +1344,7 @@ mod test { rng.fill(&mut bytes[..]); shares_map.insert(i, bytes.to_vec()); } + let shares_map: hashbrown::HashMap<_, _> = shares_map.into(); shares.push((i, shares_map)); } test_fixture_packet(Message::DkgPrivateShares(DkgPrivateShares { diff --git a/stacks-common/src/types/hashmap.rs b/stacks-common/src/types/hashmap.rs index 2b7de1046e..4cbbd1c55e 100644 --- a/stacks-common/src/types/hashmap.rs +++ b/stacks-common/src/types/hashmap.rs @@ -25,9 +25,41 @@ where } } -impl Default for StacksHashMap { +impl Default for StacksHashMap +where + K: Eq + Hash, +{ fn default() -> Self { - StacksHashMap(HashMap::new()) + StacksHashMap(HashMap::::new()) + } +} + +impl From> for StacksHashMap +where + K: Eq + Hash, +{ + fn from(map: HashMap) -> Self { + StacksHashMap(map) + } +} + +impl From<&HashMap> for StacksHashMap +where + K: Eq + Hash + Clone, + V: Clone, +{ + fn from(map: &HashMap) -> Self { + StacksHashMap(map.clone()) + } +} + +impl Into> for StacksHashMap +where + K: Eq + Hash + Clone, + V: Clone, +{ + fn into(self) -> HashMap { + self.0 } } diff --git a/stacks-common/src/types/hashset.rs b/stacks-common/src/types/hashset.rs index 45dd75461b..340c21afbf 100644 --- a/stacks-common/src/types/hashset.rs +++ b/stacks-common/src/types/hashset.rs @@ -19,6 +19,10 @@ where pub fn new() -> Self { StacksHashSet(hashbrown::HashSet::new()) } + + pub fn with_capacity(capacity: usize) -> Self { + StacksHashSet(hashbrown::HashSet::with_capacity(capacity)) + } } impl Deref for StacksHashSet @@ -41,6 +45,17 @@ where } } +impl Iterator for StacksHashSet +where + T: Eq + Hash + Clone, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.0.clone().into_iter().next() + } +} + impl FromIterator for StacksHashSet where T: Eq + Hash, @@ -54,6 +69,33 @@ where } } +impl From> for StacksHashSet +where + T: Eq + Hash, +{ + fn from(set: HashSet) -> Self { + StacksHashSet(set) + } +} + +impl From<&HashSet> for StacksHashSet +where + T: Eq + Hash + Clone, +{ + fn from(set: &HashSet) -> Self { + StacksHashSet(set.clone()) + } +} + +impl Into> for StacksHashSet +where + T: Eq + Hash, +{ + fn into(self) -> HashSet { + self.0 + } +} + #[cfg(feature = "testing")] impl Dummy for StacksHashSet where diff --git a/stacks-signer/src/client/mod.rs b/stacks-signer/src/client/mod.rs index 7e3cfb1fcd..8f0a1a6bb4 100644 --- a/stacks-signer/src/client/mod.rs +++ b/stacks-signer/src/client/mod.rs @@ -432,8 +432,8 @@ pub(crate) mod tests { "Cannot generate 0 keys for the provided signers...Specify at least 1 key." ); let mut public_keys = PublicKeys { - signers: HashMap::new(), - key_ids: HashMap::new(), + signers: hashbrown::HashMap::new(), + key_ids: hashbrown::HashMap::new(), }; let reward_cycle = thread_rng().next_u64(); let rng = &mut OsRng; diff --git a/stacks-signer/src/runloop.rs b/stacks-signer/src/runloop.rs index 2cb3568648..e6ddd5c9a5 100644 --- a/stacks-signer/src/runloop.rs +++ b/stacks-signer/src/runloop.rs @@ -92,8 +92,8 @@ impl RunLoop { let mut signer_key_ids = HashMap::with_capacity(signers.len()); let mut signer_ids = HashMap::with_capacity(signers.len()); let mut public_keys = PublicKeys { - signers: HashMap::with_capacity(signers.len()), - key_ids: HashMap::with_capacity(4000), + signers: HashMap::with_capacity(signers.len()).into(), + key_ids: HashMap::with_capacity(4000).into(), }; let mut signer_public_keys = HashMap::with_capacity(signers.len()); for (i, entry) in signers.iter().enumerate() { @@ -213,7 +213,9 @@ impl RunLoop { signer_slot_id: *signer_slot_id, key_ids, signer_entries, - signer_slot_ids: signer_slot_ids.into_values().collect(), + signer_slot_ids: signer_slot_ids + .iter() + .map(|(_, v)| v.clone()).collect(), ecdsa_private_key: self.config.ecdsa_private_key, stacks_private_key: self.config.stacks_private_key, node_host: self.config.node_host.to_string(), @@ -415,7 +417,9 @@ mod tests { let parsed_entries = RunLoop::parse_nakamoto_signer_entries(&signer_entries, false); assert_eq!(parsed_entries.signer_ids.len(), nmb_signers); - let mut signer_ids = parsed_entries.signer_ids.into_values().collect::>(); + let mut signer_ids = parsed_entries.signer_ids.iter() + .map(|(_, v)| v.clone()) + .collect::>(); signer_ids.sort(); assert_eq!( signer_ids, diff --git a/stacks-signer/src/signer.rs b/stacks-signer/src/signer.rs index 3abfadb19b..df30aca6d6 100644 --- a/stacks-signer/src/signer.rs +++ b/stacks-signer/src/signer.rs @@ -178,8 +178,14 @@ impl From for Signer { dkg_end_timeout: signer_config.dkg_end_timeout, nonce_timeout: signer_config.nonce_timeout, sign_timeout: signer_config.sign_timeout, - signer_key_ids: signer_config.signer_entries.coordinator_key_ids, - signer_public_keys: signer_config.signer_entries.signer_public_keys, + signer_key_ids: signer_config.signer_entries.coordinator_key_ids + .iter() + .map(|(k, v)| (k.clone(), v.clone().into_iter().collect::>())) + .collect::>(), + signer_public_keys: signer_config.signer_entries.signer_public_keys + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect::>() }; let coordinator = FireCoordinator::new(coordinator_config); @@ -213,7 +219,8 @@ impl From for Signer { signer_addresses: signer_config .signer_entries .signer_ids - .into_keys() + .iter() + .map(|(k, _)| k.clone()) .collect(), signer_slot_ids: signer_config.signer_slot_ids.clone(), next_signer_slot_ids: vec![], @@ -708,7 +715,7 @@ impl Signer { /// Get transactions from stackerdb for the given addresses and account nonces, filtering out any malformed transactions fn get_signer_transactions( &mut self, - nonces: &std::collections::HashMap, + nonces: &HashMap, ) -> Result, ClientError> { let transactions: Vec<_> = self .stackerdb @@ -741,7 +748,7 @@ impl Signer { let transactions: Vec<_> = self .stackerdb .get_next_transactions_with_retry(&self.next_signer_slot_ids)?; - let mut filtered_transactions = std::collections::HashMap::new(); + let mut filtered_transactions = HashMap::new(); NakamotoSigners::update_filtered_transactions( &mut filtered_transactions, &account_nonces, @@ -749,7 +756,7 @@ impl Signer { transactions, ); // We only allow enforcement of one special cased transaction per signer address per block - Ok(filtered_transactions.into_values().collect()) + Ok(filtered_transactions.iter().map(|(_, v)| v.clone()).collect()) } /// Determine the vote for a block and update the block info and nonce request accordingly @@ -925,8 +932,8 @@ impl Signer { &self, stacks_client: &StacksClient, signer_addresses: &[StacksAddress], - ) -> std::collections::HashMap { - let mut account_nonces = std::collections::HashMap::with_capacity(signer_addresses.len()); + ) -> HashMap { + let mut account_nonces = HashMap::with_capacity(signer_addresses.len()); for address in signer_addresses { let Ok(account_nonce) = retry_with_exponential_backoff(|| { stacks_client diff --git a/stackslib/src/chainstate/nakamoto/signer_set.rs b/stackslib/src/chainstate/nakamoto/signer_set.rs index 5049286908..2383ead739 100644 --- a/stackslib/src/chainstate/nakamoto/signer_set.rs +++ b/stackslib/src/chainstate/nakamoto/signer_set.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::BTreeMap; use std::ops::DerefMut; use clarity::vm::ast::ASTRules; @@ -36,6 +36,7 @@ use stacks_common::codec::{ use stacks_common::consts::{ self, FIRST_BURNCHAIN_CONSENSUS_HASH, FIRST_STACKS_BLOCK_HASH, MINER_REWARD_MATURITY, }; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, ConsensusHash, StacksAddress, StacksBlockId, StacksPrivateKey, StacksPublicKey, TrieHash, VRFSeed, diff --git a/stackslib/src/chainstate/nakamoto/test_signers.rs b/stackslib/src/chainstate/nakamoto/test_signers.rs index 3791d89f37..153d5631f2 100644 --- a/stackslib/src/chainstate/nakamoto/test_signers.rs +++ b/stackslib/src/chainstate/nakamoto/test_signers.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use std::cell::RefCell; -use std::collections::{HashSet, VecDeque}; +use std::collections::VecDeque; use std::path::{Path, PathBuf}; use std::{fs, io}; @@ -119,7 +119,7 @@ impl Default for TestSigners { Self { signer_parties, aggregate_public_key, - poly_commitments, + poly_commitments: poly_commitments.into(), num_keys, threshold, party_key_ids, @@ -179,7 +179,7 @@ impl TestSigners { .collect(); self.poly_commitments = match wsts::v2::test_helpers::dkg(&mut self.signer_parties, &mut rng) { - Ok(poly_commitments) => poly_commitments, + Ok(poly_commitments) => poly_commitments.into(), Err(secret_errors) => { panic!("Got secret errors from DKG: {:?}", secret_errors); } diff --git a/stackslib/src/chainstate/nakamoto/tests/mod.rs b/stackslib/src/chainstate/nakamoto/tests/mod.rs index 28d620b814..66afcf73f5 100644 --- a/stackslib/src/chainstate/nakamoto/tests/mod.rs +++ b/stackslib/src/chainstate/nakamoto/tests/mod.rs @@ -15,7 +15,6 @@ // along with this program. If not, see . use std::borrow::BorrowMut; -use std::collections::HashMap; use std::fs; use clarity::types::chainstate::{PoxId, SortitionId, StacksBlockId}; @@ -35,7 +34,7 @@ use stacks_common::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, ConsensusHash, StacksAddress, StacksPrivateKey, StacksPublicKey, StacksWorkScore, TrieHash, VRFSeed, }; -use stacks_common::types::{Address, PrivateKey, StacksEpoch, StacksEpochId}; +use stacks_common::types::{StacksHashMap as HashMap, Address, PrivateKey, StacksEpoch, StacksEpochId}; use stacks_common::util::get_epoch_time_secs; use stacks_common::util::hash::{hex_bytes, Hash160, MerkleTree, Sha512Trunc256Sum}; use stacks_common::util::secp256k1::{MessageSignature, Secp256k1PublicKey}; @@ -2356,7 +2355,7 @@ fn valid_vote_transaction() { }), }; valid_tx.set_origin_nonce(1); - let mut account_nonces = std::collections::HashMap::new(); + let mut account_nonces = HashMap::new(); account_nonces.insert(valid_tx.origin_address(), 1); assert!(NakamotoSigners::valid_vote_transaction( &account_nonces, @@ -2577,7 +2576,7 @@ fn valid_vote_transaction_malformed_transactions() { }; invalid_nonce.set_origin_nonce(0); // old nonce - let mut account_nonces = std::collections::HashMap::new(); + let mut account_nonces = HashMap::new(); account_nonces.insert(invalid_not_contract_call.origin_address(), 1); for tx in vec![ invalid_not_contract_call, @@ -2708,7 +2707,7 @@ fn filter_one_transaction_per_signer_multiple_addresses() { }; valid_tx_2_address_2.set_origin_nonce(2); let mut filtered_transactions = HashMap::new(); - let mut account_nonces = std::collections::HashMap::new(); + let mut account_nonces = HashMap::new(); account_nonces.insert(valid_tx_1_address_1.origin_address(), 1); account_nonces.insert(valid_tx_1_address_2.origin_address(), 1); NakamotoSigners::update_filtered_transactions( @@ -2723,7 +2722,9 @@ fn filter_one_transaction_per_signer_multiple_addresses() { valid_tx_2_address_1, ], ); - let txs: Vec<_> = filtered_transactions.into_values().collect(); + let txs: Vec<_> = filtered_transactions.iter() + .map(|(_, v)| v.clone()) + .collect(); assert_eq!(txs.len(), 2); assert!(txs.contains(&valid_tx_1_address_1)); assert!(txs.contains(&valid_tx_1_address_2)); @@ -2805,7 +2806,7 @@ fn filter_one_transaction_per_signer_duplicate_nonces() { }; valid_tx_3.set_origin_nonce(0); - let mut account_nonces = std::collections::HashMap::new(); + let mut account_nonces = HashMap::new(); account_nonces.insert(valid_tx_1.origin_address(), 0); let mut txs = vec![valid_tx_2, valid_tx_1, valid_tx_3]; let mut filtered_transactions = HashMap::new(); @@ -2815,7 +2816,9 @@ fn filter_one_transaction_per_signer_duplicate_nonces() { false, txs.clone(), ); - let filtered_txs: Vec<_> = filtered_transactions.into_values().collect(); + let filtered_txs: Vec<_> = filtered_transactions.iter() + .map(|(_, v)| v.clone()) + .collect(); txs.sort_by(|a, b| a.txid().cmp(&b.txid())); assert_eq!(filtered_txs.len(), 1); assert!(filtered_txs.contains(&txs.first().expect("failed to get first tx"))); diff --git a/stackslib/src/chainstate/nakamoto/tests/node.rs b/stackslib/src/chainstate/nakamoto/tests/node.rs index d47794540c..29bc530111 100644 --- a/stackslib/src/chainstate/nakamoto/tests/node.rs +++ b/stackslib/src/chainstate/nakamoto/tests/node.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use std::cell::RefCell; -use std::collections::{HashSet, VecDeque}; +use std::collections::VecDeque; use std::path::{Path, PathBuf}; use std::{fs, io}; diff --git a/stackslib/src/clarity_vm/tests/costs.rs b/stackslib/src/clarity_vm/tests/costs.rs index a4d9f9294a..8f9bcd9414 100644 --- a/stackslib/src/clarity_vm/tests/costs.rs +++ b/stackslib/src/clarity_vm/tests/costs.rs @@ -1537,7 +1537,7 @@ fn test_cost_voting_integration(use_mainnet: bool, clarity_version: ClarityVersi tracker.contract_call_circuits().is_empty(), "No contract call circuits should have been processed" ); - for (target, referenced_function) in tracker.cost_function_references().into_iter() { + for (target, referenced_function) in tracker.cost_function_references().iter() { assert_eq!( &referenced_function.contract_id, &boot_code_id("costs", use_mainnet), @@ -1652,8 +1652,8 @@ fn test_cost_voting_integration(use_mainnet: bool, clarity_version: ClarityVersi assert_eq!(circuit2.unwrap().contract_id, cost_definer); assert_eq!(circuit2.unwrap().function_name, "cost-definition-multi-arg"); - for (target, referenced_function) in tracker.cost_function_references().into_iter() { - if target == &ClarityCostFunction::Le { + for (target, referenced_function) in tracker.cost_function_references().iter() { + if **target == ClarityCostFunction::Le { assert_eq!(&referenced_function.contract_id, &cost_definer); assert_eq!(&referenced_function.function_name, "cost-definition-le"); } else { diff --git a/testnet/stacks-node/src/nakamoto_node/miner.rs b/testnet/stacks-node/src/nakamoto_node/miner.rs index 7fcc7ecb63..44cac6e6e3 100644 --- a/testnet/stacks-node/src/nakamoto_node/miner.rs +++ b/testnet/stacks-node/src/nakamoto_node/miner.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; // Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation // Copyright (C) 2020-2023 Stacks Open Internet Foundation // @@ -359,7 +358,7 @@ impl BlockMinerThread { _ => {} // Any other message is ignored } } - Ok(filtered_transactions.into_values().collect()) + Ok(filtered_transactions.iter().map(|(_, v)| v.clone()).collect()) } fn wait_for_signer_signature( @@ -450,7 +449,7 @@ impl BlockMinerThread { rejections_weight = rejections_weight.saturating_add( *signer_weights .get( - &slot_ids_addresses + slot_ids_addresses .get(&signer_id) .expect("FATAL: signer not found in slot ids"), ) From 23c26f0d44daf8631af54a3cc1b897708a92edbc Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Tue, 5 Mar 2024 19:11:19 +0100 Subject: [PATCH 17/28] wip: cargo fmt-stacks --- clarity-proptest/src/lib.rs | 1 + clarity/src/vm/ast/mod.rs | 3 +-- clarity/src/vm/ast/traits_resolver/mod.rs | 5 +--- clarity/src/vm/costs/mod.rs | 9 ++++--- clarity/src/vm/coverage.rs | 2 +- clarity/src/vm/database/key_value_wrapper.rs | 3 +-- clarity/src/vm/docs/contracts.rs | 3 +-- clarity/src/vm/fakes.rs | 2 +- clarity/src/vm/mod.rs | 3 +-- clarity/src/vm/tests/principals.rs | 3 +-- clarity/src/vm/types/serialization.rs | 3 +-- clarity/src/vm/types/signatures.rs | 7 +++--- libsigner/src/http.rs | 2 +- libsigner/src/messages.rs | 4 +-- .../deps_common/bitcoin/network/encodable.rs | 3 +-- stacks-common/src/types/hashmap.rs | 8 +++--- stacks-signer/src/client/mod.rs | 5 ++-- stacks-signer/src/client/stackerdb.rs | 2 +- stacks-signer/src/config.rs | 3 +-- stacks-signer/src/runloop.rs | 10 ++++---- stacks-signer/src/signer.rs | 25 +++++++++++++------ .../src/chainstate/nakamoto/signer_set.rs | 5 ++-- .../src/chainstate/nakamoto/test_signers.rs | 2 +- .../src/chainstate/nakamoto/tests/mod.rs | 10 +++++--- .../src/chainstate/nakamoto/tests/node.rs | 2 +- .../stacks-node/src/nakamoto_node/miner.rs | 10 +++++--- 26 files changed, 74 insertions(+), 61 deletions(-) diff --git a/clarity-proptest/src/lib.rs b/clarity-proptest/src/lib.rs index 377d43de1f..5d65f3c640 100644 --- a/clarity-proptest/src/lib.rs +++ b/clarity-proptest/src/lib.rs @@ -13,6 +13,7 @@ pub fn contract() -> impl Strategy { fn clarity_name() -> impl Strategy { "[a-z]{40}".prop_map(|s| s.try_into().unwrap()) } + ( // contract_identifier qualified_principal().prop_map(|p| match p { diff --git a/clarity/src/vm/ast/mod.rs b/clarity/src/vm/ast/mod.rs index e018eb44d6..a95d32047e 100644 --- a/clarity/src/vm/ast/mod.rs +++ b/clarity/src/vm/ast/mod.rs @@ -319,8 +319,7 @@ pub fn build_ast( #[cfg(test)] mod test { - use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; - use stacks_common::types::StacksEpochId; + use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::ast::errors::ParseErrors; use crate::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; diff --git a/clarity/src/vm/ast/traits_resolver/mod.rs b/clarity/src/vm/ast/traits_resolver/mod.rs index 4815694b7d..0b44d5e912 100644 --- a/clarity/src/vm/ast/traits_resolver/mod.rs +++ b/clarity/src/vm/ast/traits_resolver/mod.rs @@ -159,10 +159,7 @@ impl TraitsResolver { } for (trait_reference, expr) in referenced_traits.iter() { - if !contract_ast - .referenced_traits - .contains_key(trait_reference) - { + if !contract_ast.referenced_traits.contains_key(trait_reference) { let mut err = ParseError::new(ParseErrors::TraitReferenceUnknown( trait_reference.to_string(), )); diff --git a/clarity/src/vm/costs/mod.rs b/clarity/src/vm/costs/mod.rs index f11b0c40b0..c84b555e0e 100644 --- a/clarity/src/vm/costs/mod.rs +++ b/clarity/src/vm/costs/mod.rs @@ -17,11 +17,10 @@ use std::collections::BTreeMap; use std::{cmp, fmt}; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use lazy_static::lazy_static; use rusqlite::types::{FromSql, FromSqlResult, ToSql, ToSqlOutput, ValueRef}; use serde::{Deserialize, Serialize}; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::boot_util::boot_code_id; use crate::vm::ast::ContractAST; @@ -207,10 +206,12 @@ impl From for SerializedCostStateSummary { cost_function_references, } = other; SerializedCostStateSummary { - contract_call_circuits: contract_call_circuits.iter() + contract_call_circuits: contract_call_circuits + .iter() .map(|(k, v)| (k.clone(), v.clone())) .collect(), - cost_function_references: cost_function_references.iter() + cost_function_references: cost_function_references + .iter() .map(|(k, v)| (k.clone(), v.clone())) .collect(), } diff --git a/clarity/src/vm/coverage.rs b/clarity/src/vm/coverage.rs index 117d96ed84..9034cd183c 100644 --- a/clarity/src/vm/coverage.rs +++ b/clarity/src/vm/coverage.rs @@ -2,8 +2,8 @@ use std::collections::BTreeMap; use std::fs::File; use std::io::Write; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use serde_json::Value as JsonValue; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use super::functions::define::DefineFunctionsParsed; use super::EvalHook; diff --git a/clarity/src/vm/database/key_value_wrapper.rs b/clarity/src/vm/database/key_value_wrapper.rs index db28a7858e..b66d8e91ae 100644 --- a/clarity/src/vm/database/key_value_wrapper.rs +++ b/clarity/src/vm/database/key_value_wrapper.rs @@ -16,9 +16,8 @@ use std::hash::Hash; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::types::chainstate::StacksBlockId; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::hash::Sha512Trunc256Sum; use super::clarity_store::SpecialCaseHandler; diff --git a/clarity/src/vm/docs/contracts.rs b/clarity/src/vm/docs/contracts.rs index 4f6fb9540e..3753018958 100644 --- a/clarity/src/vm/docs/contracts.rs +++ b/clarity/src/vm/docs/contracts.rs @@ -1,8 +1,7 @@ use std::collections::BTreeMap; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::consts::CHAIN_ID_TESTNET; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use crate::vm::analysis::{mem_type_check, ContractAnalysis}; use crate::vm::ast::{build_ast_with_rules, ASTRules}; diff --git a/clarity/src/vm/fakes.rs b/clarity/src/vm/fakes.rs index 7de7530c4c..ab9dd2d5df 100644 --- a/clarity/src/vm/fakes.rs +++ b/clarity/src/vm/fakes.rs @@ -28,8 +28,8 @@ pub mod raw { use fake::locales::EN; use fake::{Dummy, Fake, Faker}; - use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use rand::Rng; + use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use super::ENGLISH_WORDS; use crate::vm::callables::DefinedFunction; diff --git a/clarity/src/vm/mod.rs b/clarity/src/vm/mod.rs index a877ca15ff..876553df16 100644 --- a/clarity/src/vm/mod.rs +++ b/clarity/src/vm/mod.rs @@ -589,9 +589,8 @@ pub fn execute_v2(program: &str) -> Result> { #[cfg(test)] mod test { - use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::consts::CHAIN_ID_TESTNET; - use stacks_common::types::StacksEpochId; + use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use super::ClarityVersion; use crate::vm::callables::{DefineType, DefinedFunction}; diff --git a/clarity/src/vm/tests/principals.rs b/clarity/src/vm/tests/principals.rs index a77f9d3517..625e1a162f 100644 --- a/clarity/src/vm/tests/principals.rs +++ b/clarity/src/vm/tests/principals.rs @@ -1,5 +1,4 @@ -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::hash::hex_bytes; use crate::vm::ast::ASTRules; diff --git a/clarity/src/vm/types/serialization.rs b/clarity/src/vm/types/serialization.rs index 6db47be655..a51ffdc01c 100644 --- a/clarity/src/vm/types/serialization.rs +++ b/clarity/src/vm/types/serialization.rs @@ -17,11 +17,10 @@ use std::io::{Read, Write}; use std::{cmp, error, fmt, str}; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use lazy_static::lazy_static; use serde_json::Value as JSONValue; use stacks_common::codec::{Error as codec_error, StacksMessageCodec}; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::hash::{hex_bytes, to_hex}; use stacks_common::util::retry::BoundReader; diff --git a/clarity/src/vm/types/signatures.rs b/clarity/src/vm/types/signatures.rs index c694c33b8c..c1ad2bd4d5 100644 --- a/clarity/src/vm/types/signatures.rs +++ b/clarity/src/vm/types/signatures.rs @@ -19,11 +19,11 @@ use std::collections::BTreeMap; use std::hash::{Hash, Hasher}; use std::{cmp, fmt}; -// TypeSignatures -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use lazy_static::lazy_static; use stacks_common::address::c32; use stacks_common::types::StacksEpochId; +// TypeSignatures +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::hash; use crate::vm::costs::{cost_functions, runtime_cost, CostOverflowingMath}; @@ -2149,7 +2149,8 @@ mod test { CallableSubtype::Principal(QualifiedContractIdentifier::local("foo").unwrap()), CallableSubtype::Principal(QualifiedContractIdentifier::local("bar").unwrap()), ]; - let list_union_principals = ListUnionType(callable_principals.to_vec().into_iter().collect()); + let list_union_principals = + ListUnionType(callable_principals.to_vec().into_iter().collect()); let notype_pairs = [ // NoType with X should result in X diff --git a/libsigner/src/http.rs b/libsigner/src/http.rs index 37770b814a..96f3ab4cff 100644 --- a/libsigner/src/http.rs +++ b/libsigner/src/http.rs @@ -18,9 +18,9 @@ use std::io; use std::io::{Read, Write}; use std::net::SocketAddr; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::codec::MAX_MESSAGE_LEN; use stacks_common::deps_common::httparse; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::chunked_encoding::*; use crate::error::{EventError, RPCError}; diff --git a/libsigner/src/messages.rs b/libsigner/src/messages.rs index d828eff37e..7c85758fa0 100644 --- a/libsigner/src/messages.rs +++ b/libsigner/src/messages.rs @@ -30,13 +30,13 @@ use blockstack_lib::net::api::postblock_proposal::{ use blockstack_lib::util_lib::boot::boot_code_id; use clarity::vm::types::serialization::SerializationError; use clarity::vm::types::QualifiedContractIdentifier; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use serde::{Deserialize, Serialize}; use stacks_common::codec::{ read_next, read_next_at_most, read_next_exact, write_next, Error as CodecError, StacksMessageCodec, }; use stacks_common::consts::SIGNER_SLOTS_PER_USER; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::hash::Sha512Trunc256Sum; use tiny_http::{ Method as HttpMethod, Request as HttpRequest, Response as HttpResponse, Server as HttpServer, @@ -545,7 +545,7 @@ impl StacksMessageCodecExtensions for DkgPrivateShares { let id = read_next::(fd)?; let num_share_map = read_next::(fd)?; let mut share_map = HashMap::new(); - + for _ in 0..num_share_map { let id = read_next::(fd)?; let share: Vec = read_next(fd)?; diff --git a/stacks-common/src/deps_common/bitcoin/network/encodable.rs b/stacks-common/src/deps_common/bitcoin/network/encodable.rs index 540f96abed..9e941db2c3 100644 --- a/stacks-common/src/deps_common/bitcoin/network/encodable.rs +++ b/stacks-common/src/deps_common/bitcoin/network/encodable.rs @@ -32,10 +32,9 @@ use std::hash::Hash; use std::{mem, u32}; -use crate::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; - use crate::deps_common::bitcoin::network::serialize::{self, SimpleDecoder, SimpleEncoder}; use crate::deps_common::bitcoin::util::hash::Sha256dHash; +use crate::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; /// Maximum size, in bytes, of a vector we are allowed to decode pub const MAX_VEC_SIZE: usize = 64 * 1024 * 1024; diff --git a/stacks-common/src/types/hashmap.rs b/stacks-common/src/types/hashmap.rs index 4cbbd1c55e..924f824fc8 100644 --- a/stacks-common/src/types/hashmap.rs +++ b/stacks-common/src/types/hashmap.rs @@ -25,7 +25,7 @@ where } } -impl Default for StacksHashMap +impl Default for StacksHashMap where K: Eq + Hash, { @@ -41,7 +41,7 @@ where fn from(map: HashMap) -> Self { StacksHashMap(map) } -} +} impl From<&HashMap> for StacksHashMap where @@ -53,7 +53,7 @@ where } } -impl Into> for StacksHashMap +impl Into> for StacksHashMap where K: Eq + Hash + Clone, V: Clone, @@ -109,4 +109,4 @@ where } StacksHashMap(map) } -} \ No newline at end of file +} diff --git a/stacks-signer/src/client/mod.rs b/stacks-signer/src/client/mod.rs index 8f0a1a6bb4..1a378eeedf 100644 --- a/stacks-signer/src/client/mod.rs +++ b/stacks-signer/src/client/mod.rs @@ -139,14 +139,15 @@ pub(crate) mod tests { use clarity::vm::costs::ExecutionCost; use clarity::vm::types::TupleData; use clarity::vm::Value as ClarityValue; - use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use rand::distributions::Standard; use rand::{thread_rng, Rng}; use rand_core::{OsRng, RngCore}; use stacks_common::types::chainstate::{ BlockHeaderHash, ConsensusHash, StacksAddress, StacksPrivateKey, StacksPublicKey, }; - use stacks_common::types::{StacksEpochId, StacksPublicKeyBuffer}; + use stacks_common::types::{ + StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet, StacksPublicKeyBuffer, + }; use stacks_common::util::hash::{Hash160, Sha256Sum}; use wsts::curve::ecdsa; use wsts::curve::point::{Compressed, Point}; diff --git a/stacks-signer/src/client/stackerdb.rs b/stacks-signer/src/client/stackerdb.rs index d301ff6e03..d43682c56d 100644 --- a/stacks-signer/src/client/stackerdb.rs +++ b/stacks-signer/src/client/stackerdb.rs @@ -19,13 +19,13 @@ use blockstack_lib::chainstate::stacks::StacksTransaction; use blockstack_lib::util_lib::boot::boot_code_addr; use clarity::vm::types::QualifiedContractIdentifier; use clarity::vm::ContractName; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use libsigner::{SignerMessage, SignerSession, StackerDBSession, TRANSACTIONS_MSG_ID}; use libstackerdb::{StackerDBChunkAckData, StackerDBChunkData}; use slog::{slog_debug, slog_warn}; use stacks_common::codec::{read_next, StacksMessageCodec}; use stacks_common::consts::SIGNER_SLOTS_PER_USER; use stacks_common::types::chainstate::StacksPrivateKey; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::{debug, warn}; use super::ClientError; diff --git a/stacks-signer/src/config.rs b/stacks-signer/src/config.rs index f0b7642c87..ed0ca10e77 100644 --- a/stacks-signer/src/config.rs +++ b/stacks-signer/src/config.rs @@ -20,14 +20,13 @@ use std::path::PathBuf; use std::time::Duration; use blockstack_lib::chainstate::stacks::TransactionVersion; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use serde::Deserialize; use stacks_common::address::{ AddressHashMode, C32_ADDRESS_VERSION_MAINNET_SINGLESIG, C32_ADDRESS_VERSION_TESTNET_SINGLESIG, }; use stacks_common::consts::{CHAIN_ID_MAINNET, CHAIN_ID_TESTNET}; use stacks_common::types::chainstate::{StacksAddress, StacksPrivateKey, StacksPublicKey}; -use stacks_common::types::PrivateKey; +use stacks_common::types::{PrivateKey, StacksHashMap as HashMap, StacksHashSet as HashSet}; use wsts::curve::point::Point; use wsts::curve::scalar::Scalar; use wsts::state_machine::PublicKeys; diff --git a/stacks-signer/src/runloop.rs b/stacks-signer/src/runloop.rs index e6ddd5c9a5..0eb2de5bef 100644 --- a/stacks-signer/src/runloop.rs +++ b/stacks-signer/src/runloop.rs @@ -20,10 +20,10 @@ use std::time::Duration; use blockstack_lib::chainstate::burn::ConsensusHashExtensions; use blockstack_lib::chainstate::stacks::boot::{NakamotoSignerEntry, SIGNERS_NAME}; use blockstack_lib::util_lib::boot::boot_code_id; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use libsigner::{SignerEvent, SignerRunLoop}; use slog::{slog_debug, slog_error, slog_info, slog_warn}; use stacks_common::types::chainstate::{ConsensusHash, StacksAddress, StacksPublicKey}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::{debug, error, info, warn}; use wsts::curve::ecdsa; use wsts::curve::point::{Compressed, Point}; @@ -213,9 +213,7 @@ impl RunLoop { signer_slot_id: *signer_slot_id, key_ids, signer_entries, - signer_slot_ids: signer_slot_ids - .iter() - .map(|(_, v)| v.clone()).collect(), + signer_slot_ids: signer_slot_ids.iter().map(|(_, v)| v.clone()).collect(), ecdsa_private_key: self.config.ecdsa_private_key, stacks_private_key: self.config.stacks_private_key, node_host: self.config.node_host.to_string(), @@ -417,7 +415,9 @@ mod tests { let parsed_entries = RunLoop::parse_nakamoto_signer_entries(&signer_entries, false); assert_eq!(parsed_entries.signer_ids.len(), nmb_signers); - let mut signer_ids = parsed_entries.signer_ids.iter() + let mut signer_ids = parsed_entries + .signer_ids + .iter() .map(|(_, v)| v.clone()) .collect::>(); signer_ids.sort(); diff --git a/stacks-signer/src/signer.rs b/stacks-signer/src/signer.rs index df30aca6d6..d465135d16 100644 --- a/stacks-signer/src/signer.rs +++ b/stacks-signer/src/signer.rs @@ -22,12 +22,11 @@ use blockstack_lib::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockVote}; use blockstack_lib::chainstate::stacks::boot::SIGNERS_VOTING_FUNCTION_NAME; use blockstack_lib::chainstate::stacks::StacksTransaction; use blockstack_lib::net::api::postblock_proposal::BlockValidateResponse; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use libsigner::{BlockRejection, BlockResponse, RejectCode, SignerEvent, SignerMessage}; use slog::{slog_debug, slog_error, slog_info, slog_warn}; use stacks_common::codec::{read_next, StacksMessageCodec}; use stacks_common::types::chainstate::StacksAddress; -use stacks_common::types::StacksEpochId; +use stacks_common::types::{StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::hash::Sha512Trunc256Sum; use stacks_common::{debug, error, info, warn}; use wsts::common::{MerkleRoot, Signature}; @@ -178,14 +177,23 @@ impl From for Signer { dkg_end_timeout: signer_config.dkg_end_timeout, nonce_timeout: signer_config.nonce_timeout, sign_timeout: signer_config.sign_timeout, - signer_key_ids: signer_config.signer_entries.coordinator_key_ids + signer_key_ids: signer_config + .signer_entries + .coordinator_key_ids .iter() - .map(|(k, v)| (k.clone(), v.clone().into_iter().collect::>())) + .map(|(k, v)| { + ( + k.clone(), + v.clone().into_iter().collect::>(), + ) + }) .collect::>(), - signer_public_keys: signer_config.signer_entries.signer_public_keys + signer_public_keys: signer_config + .signer_entries + .signer_public_keys .iter() .map(|(k, v)| (k.clone(), v.clone())) - .collect::>() + .collect::>(), }; let coordinator = FireCoordinator::new(coordinator_config); @@ -756,7 +764,10 @@ impl Signer { transactions, ); // We only allow enforcement of one special cased transaction per signer address per block - Ok(filtered_transactions.iter().map(|(_, v)| v.clone()).collect()) + Ok(filtered_transactions + .iter() + .map(|(_, v)| v.clone()) + .collect()) } /// Determine the vote for a block and update the block info and nonce request accordingly diff --git a/stackslib/src/chainstate/nakamoto/signer_set.rs b/stackslib/src/chainstate/nakamoto/signer_set.rs index 2383ead739..22e62d6781 100644 --- a/stackslib/src/chainstate/nakamoto/signer_set.rs +++ b/stackslib/src/chainstate/nakamoto/signer_set.rs @@ -36,12 +36,13 @@ use stacks_common::codec::{ use stacks_common::consts::{ self, FIRST_BURNCHAIN_CONSENSUS_HASH, FIRST_STACKS_BLOCK_HASH, MINER_REWARD_MATURITY, }; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, ConsensusHash, StacksAddress, StacksBlockId, StacksPrivateKey, StacksPublicKey, TrieHash, VRFSeed, }; -use stacks_common::types::{PrivateKey, StacksEpochId}; +use stacks_common::types::{ + PrivateKey, StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet, +}; use stacks_common::util::get_epoch_time_secs; use stacks_common::util::hash::{to_hex, Hash160, MerkleHashFunc, MerkleTree, Sha512Trunc256Sum}; use stacks_common::util::retry::BoundReader; diff --git a/stackslib/src/chainstate/nakamoto/test_signers.rs b/stackslib/src/chainstate/nakamoto/test_signers.rs index 153d5631f2..5d211f9530 100644 --- a/stackslib/src/chainstate/nakamoto/test_signers.rs +++ b/stackslib/src/chainstate/nakamoto/test_signers.rs @@ -22,13 +22,13 @@ use std::{fs, io}; use clarity::vm::clarity::ClarityConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; use clarity::vm::types::*; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use rand::seq::SliceRandom; use rand::{CryptoRng, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; use stacks_common::address::*; use stacks_common::consts::{FIRST_BURNCHAIN_CONSENSUS_HASH, FIRST_STACKS_BLOCK_HASH}; use stacks_common::types::chainstate::{BlockHeaderHash, SortitionId, StacksBlockId, VRFSeed}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::hash::Hash160; use stacks_common::util::sleep_ms; use stacks_common::util::vrf::{VRFProof, VRFPublicKey}; diff --git a/stackslib/src/chainstate/nakamoto/tests/mod.rs b/stackslib/src/chainstate/nakamoto/tests/mod.rs index 66afcf73f5..1f7f065ce0 100644 --- a/stackslib/src/chainstate/nakamoto/tests/mod.rs +++ b/stackslib/src/chainstate/nakamoto/tests/mod.rs @@ -34,7 +34,9 @@ use stacks_common::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, ConsensusHash, StacksAddress, StacksPrivateKey, StacksPublicKey, StacksWorkScore, TrieHash, VRFSeed, }; -use stacks_common::types::{StacksHashMap as HashMap, Address, PrivateKey, StacksEpoch, StacksEpochId}; +use stacks_common::types::{ + Address, PrivateKey, StacksEpoch, StacksEpochId, StacksHashMap as HashMap, +}; use stacks_common::util::get_epoch_time_secs; use stacks_common::util::hash::{hex_bytes, Hash160, MerkleTree, Sha512Trunc256Sum}; use stacks_common::util::secp256k1::{MessageSignature, Secp256k1PublicKey}; @@ -2722,7 +2724,8 @@ fn filter_one_transaction_per_signer_multiple_addresses() { valid_tx_2_address_1, ], ); - let txs: Vec<_> = filtered_transactions.iter() + let txs: Vec<_> = filtered_transactions + .iter() .map(|(_, v)| v.clone()) .collect(); assert_eq!(txs.len(), 2); @@ -2816,7 +2819,8 @@ fn filter_one_transaction_per_signer_duplicate_nonces() { false, txs.clone(), ); - let filtered_txs: Vec<_> = filtered_transactions.iter() + let filtered_txs: Vec<_> = filtered_transactions + .iter() .map(|(_, v)| v.clone()) .collect(); txs.sort_by(|a, b| a.txid().cmp(&b.txid())); diff --git a/stackslib/src/chainstate/nakamoto/tests/node.rs b/stackslib/src/chainstate/nakamoto/tests/node.rs index 29bc530111..3b1008c3b6 100644 --- a/stackslib/src/chainstate/nakamoto/tests/node.rs +++ b/stackslib/src/chainstate/nakamoto/tests/node.rs @@ -22,13 +22,13 @@ use std::{fs, io}; use clarity::vm::clarity::ClarityConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; use clarity::vm::types::*; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use rand::seq::SliceRandom; use rand::{CryptoRng, RngCore, SeedableRng}; use rand_chacha::ChaCha20Rng; use stacks_common::address::*; use stacks_common::consts::{FIRST_BURNCHAIN_CONSENSUS_HASH, FIRST_STACKS_BLOCK_HASH}; use stacks_common::types::chainstate::{BlockHeaderHash, SortitionId, StacksBlockId, VRFSeed}; +use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use stacks_common::util::hash::Hash160; use stacks_common::util::sleep_ms; use stacks_common::util::vrf::{VRFProof, VRFPublicKey}; diff --git a/testnet/stacks-node/src/nakamoto_node/miner.rs b/testnet/stacks-node/src/nakamoto_node/miner.rs index 44cac6e6e3..c8b08201f4 100644 --- a/testnet/stacks-node/src/nakamoto_node/miner.rs +++ b/testnet/stacks-node/src/nakamoto_node/miner.rs @@ -20,7 +20,6 @@ use std::time::{Duration, Instant}; use clarity::boot_util::boot_code_id; use clarity::vm::clarity::ClarityConnection; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; use libsigner::{ BlockResponse, RejectCode, SignerMessage, SignerSession, StackerDBSession, BLOCK_MSG_ID, TRANSACTIONS_MSG_ID, @@ -42,7 +41,9 @@ use stacks::core::FIRST_BURNCHAIN_CONSENSUS_HASH; use stacks::net::stackerdb::StackerDBs; use stacks_common::codec::{read_next, StacksMessageCodec}; use stacks_common::types::chainstate::{StacksAddress, StacksBlockId}; -use stacks_common::types::{PrivateKey, StacksEpochId}; +use stacks_common::types::{ + PrivateKey, StacksEpochId, StacksHashMap as HashMap, StacksHashSet as HashSet, +}; use stacks_common::util::hash::{Hash160, Sha512Trunc256Sum}; use stacks_common::util::vrf::VRFProof; use wsts::curve::point::Point; @@ -358,7 +359,10 @@ impl BlockMinerThread { _ => {} // Any other message is ignored } } - Ok(filtered_transactions.iter().map(|(_, v)| v.clone()).collect()) + Ok(filtered_transactions + .iter() + .map(|(_, v)| v.clone()) + .collect()) } fn wait_for_signer_signature( From aa37f329f683dbc2494769e21c34f51a6e56ceaf Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Tue, 5 Mar 2024 19:40:28 +0100 Subject: [PATCH 18/28] wip: proptest vs fake --- Cargo.lock | 3 + clarity-proptest/Cargo.toml | 1 + clarity-proptest/src/lib.rs | 2 + clarity-proptest/src/tests.rs | 57 +++++++++++++++++++ clarity/Cargo.toml | 2 + clarity/src/vm/database/mod.rs | 2 +- .../src/vm/database/tests/clarity_db_tests.rs | 11 +++- 7 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 clarity-proptest/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 81a8416c27..8d19ae60d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -729,10 +729,12 @@ name = "clarity" version = "0.0.1" dependencies = [ "assert-json-diff", + "clarity-proptest", "fake", "hashbrown 0.14.3", "integer-sqrt", "lazy_static", + "proptest", "rand 0.8.5", "rand_chacha 0.3.1", "regex", @@ -754,6 +756,7 @@ version = "0.1.0" dependencies = [ "clarity", "proptest", + "rusqlite", "stacks-common", ] diff --git a/clarity-proptest/Cargo.toml b/clarity-proptest/Cargo.toml index 3d9f7815b0..0339d16988 100644 --- a/clarity-proptest/Cargo.toml +++ b/clarity-proptest/Cargo.toml @@ -12,4 +12,5 @@ path = "src/lib.rs" clarity = { path = "../clarity" } stacks_common = { path = "../stacks-common", package = "stacks-common" } proptest = { version = "1.4" } +rusqlite = { version = "=0.24.2", features = ["blob", "serde_json", "i128_blob", "bundled", "trace"] } diff --git a/clarity-proptest/src/lib.rs b/clarity-proptest/src/lib.rs index 5d65f3c640..47dec8a60d 100644 --- a/clarity-proptest/src/lib.rs +++ b/clarity-proptest/src/lib.rs @@ -9,6 +9,8 @@ use clarity::vm::types::{ use clarity::vm::{ClarityName, ContractContext, ContractName}; use proptest::prelude::*; +mod tests; + pub fn contract() -> impl Strategy { fn clarity_name() -> impl Strategy { "[a-z]{40}".prop_map(|s| s.try_into().unwrap()) diff --git a/clarity-proptest/src/tests.rs b/clarity-proptest/src/tests.rs new file mode 100644 index 0000000000..6d9c0a1466 --- /dev/null +++ b/clarity-proptest/src/tests.rs @@ -0,0 +1,57 @@ +use proptest::prelude::*; +use clarity::vm::database::{ClarityBackingStore, ClarityDatabase, MemoryBackingStore, NULL_HEADER_DB, NULL_BURN_STATE_DB}; +use rusqlite::NO_PARAMS; + +use crate::contract; + +proptest! { + #[test] + fn insert_contract(contract in contract()) { + let mut store = MemoryBackingStore::new(); + let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); + + db.begin(); + + //let contract: Contract = Faker.fake(); + + let contract_id = contract.contract_context.contract_identifier.clone(); + + db.insert_contract(&contract_id, contract) + .expect("failed to insert contract into backing store"); + + let exists = sql_exists( + &mut store, + &format!( + "SELECT * FROM metadata_table WHERE key LIKE '%{}%'", + contract_id.to_string() + ), + ); + assert!(!exists); + } +} + + +/// Executes the provided SQL query, which is expected to return a positive +/// integer, and returns it as a u32. Panics upon SQL failure. +fn sql_query_u32(store: &mut S, sql: &str) -> u32 { + let sqlite = store.get_side_store(); + sqlite + .query_row(sql, NO_PARAMS, |row| { + let i: u32 = row.get(0)?; + Ok(i) + }) + .expect("failed to verify results in sqlite") +} + +/// Executes the provided SQL query as a subquery within a `SELECT EXISTS(...)` +/// statement. Returns true if the statement returns any rows, false otherwise. +/// Panics upon SQL failure. +fn sql_exists(store: &mut S, sql: &str) -> bool { + let sqlite = store.get_side_store(); + sqlite + .query_row(&format!("SELECT EXISTS({});", sql), NO_PARAMS, |row| { + let exists: bool = row.get(0)?; + Ok(exists) + }) + .expect("failed to verify results in sqlite") +} diff --git a/clarity/Cargo.toml b/clarity/Cargo.toml index dc2a5d76e0..d0446e5cba 100644 --- a/clarity/Cargo.toml +++ b/clarity/Cargo.toml @@ -47,6 +47,8 @@ features = ["std"] [dev-dependencies] assert-json-diff = "1.0.0" +proptest = { workspace = true } +clarity-proptest = { path = "../clarity-proptest" } # a nightly rustc regression (35dbef235 2021-03-02) prevents criterion from compiling # but it isn't necessary for tests: only benchmarks. therefore, commenting out for now. # criterion = "0.3" diff --git a/clarity/src/vm/database/mod.rs b/clarity/src/vm/database/mod.rs index ec49f0261d..f0297ef18e 100644 --- a/clarity/src/vm/database/mod.rs +++ b/clarity/src/vm/database/mod.rs @@ -33,5 +33,5 @@ pub mod clarity_store; mod key_value_wrapper; mod sqlite; mod structures; -#[cfg(feature = "testing")] +#[cfg(test)] mod tests; diff --git a/clarity/src/vm/database/tests/clarity_db_tests.rs b/clarity/src/vm/database/tests/clarity_db_tests.rs index 498f74b06b..dfb5043173 100644 --- a/clarity/src/vm/database/tests/clarity_db_tests.rs +++ b/clarity/src/vm/database/tests/clarity_db_tests.rs @@ -1,6 +1,10 @@ use fake::{Fake, Faker}; use rusqlite::NO_PARAMS; use stacks_common::util::hash::Sha512Trunc256Sum; +#[cfg(test)] +use proptest::prelude::*; +#[cfg(test)] +use clarity_proptest::*; use crate::vm::contracts::Contract; use crate::vm::database::clarity_store::ContractCommitment; @@ -11,15 +15,16 @@ use crate::vm::database::{ use crate::vm::fakes::raw::EnglishWord; use crate::vm::Value; -#[test] -fn insert_contract() { - for _ in 0..1000 { +proptest! { + #[test] + fn insert_contract(contract in contract()) { let mut store = MemoryBackingStore::new(); let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); db.begin(); let contract: Contract = Faker.fake(); + let contract_id = contract.contract_context.contract_identifier.clone(); db.insert_contract(&contract_id, contract) From 0bfd47d9d899d9df5e8b75d8599d212a5899e33e Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Wed, 6 Mar 2024 18:03:56 +0100 Subject: [PATCH 19/28] wip: migrating from fake to proptest for generation --- Cargo.lock | 15 +- Cargo.toml | 3 +- clarity-proptest/Cargo.toml | 16 - clarity-proptest/src/lib.rs | 548 ------- clarity-proptest/src/tests.rs | 57 - clarity/Cargo.toml | 11 +- clarity/src/libclarity.rs | 3 + clarity/src/proptesting/callables.rs | 118 ++ clarity/src/proptesting/contracts.rs | 106 ++ clarity/src/proptesting/mod.rs | 22 + clarity/src/proptesting/representations.rs | 61 + clarity/src/proptesting/types.rs | 95 ++ clarity/src/proptesting/values.rs | 230 +++ clarity/src/vm/callables.rs | 6 +- clarity/src/vm/contexts.rs | 1 - clarity/src/vm/contracts.rs | 1 - clarity/src/vm/database/structures.rs | 4 - .../clarity_db_tests.proptest-regressions | 7 + .../src/vm/database/tests/clarity_db_tests.rs | 74 +- clarity/src/vm/fakes.rs | 1408 ----------------- clarity/src/vm/mod.rs | 3 - clarity/src/vm/types/mod.rs | 4 - clarity/src/vm/types/signatures.rs | 2 - clarity/src/vm/version.rs | 1 - stacks-common/Cargo.toml | 4 +- stacks-common/src/libcommon.rs | 7 + stacks-common/src/proptesting/hashmap.rs | 99 ++ stacks-common/src/proptesting/hashset.rs | 89 ++ stacks-common/src/proptesting/mod.rs | 16 + stacks-common/src/types/hashmap.rs | 19 +- stacks-common/src/types/hashset.rs | 19 +- 31 files changed, 900 insertions(+), 2149 deletions(-) delete mode 100644 clarity-proptest/Cargo.toml delete mode 100644 clarity-proptest/src/lib.rs delete mode 100644 clarity-proptest/src/tests.rs create mode 100644 clarity/src/proptesting/callables.rs create mode 100644 clarity/src/proptesting/contracts.rs create mode 100644 clarity/src/proptesting/mod.rs create mode 100644 clarity/src/proptesting/representations.rs create mode 100644 clarity/src/proptesting/types.rs create mode 100644 clarity/src/proptesting/values.rs create mode 100644 clarity/src/vm/database/tests/clarity_db_tests.proptest-regressions delete mode 100644 clarity/src/vm/fakes.rs create mode 100644 stacks-common/src/proptesting/hashmap.rs create mode 100644 stacks-common/src/proptesting/hashset.rs create mode 100644 stacks-common/src/proptesting/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 8d19ae60d2..865027ddd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -729,8 +729,7 @@ name = "clarity" version = "0.0.1" dependencies = [ "assert-json-diff", - "clarity-proptest", - "fake", + "clarity", "hashbrown 0.14.3", "integer-sqrt", "lazy_static", @@ -750,16 +749,6 @@ dependencies = [ "time 0.2.27", ] -[[package]] -name = "clarity-proptest" -version = "0.1.0" -dependencies = [ - "clarity", - "proptest", - "rusqlite", - "stacks-common", -] - [[package]] name = "colorchoice" version = "1.0.0" @@ -3528,12 +3517,12 @@ dependencies = [ "chrono", "curve25519-dalek 2.0.0", "ed25519-dalek", - "fake", "hashbrown 0.14.3", "lazy_static", "libc", "nix", "percent-encoding", + "proptest", "rand 0.8.5", "rand_core 0.6.4", "ripemd", diff --git a/Cargo.toml b/Cargo.toml index a3643ac0d8..2c054d9756 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,7 @@ members = [ "contrib/tools/relay-server", "libsigner", "stacks-signer", - "testnet/stacks-node", - "clarity-proptest" + "testnet/stacks-node" ] # Dependencies we want to keep the same between workspace members diff --git a/clarity-proptest/Cargo.toml b/clarity-proptest/Cargo.toml deleted file mode 100644 index 0339d16988..0000000000 --- a/clarity-proptest/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "clarity-proptest" -version = "0.1.0" -edition = "2021" - -[lib] -path = "src/lib.rs" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -clarity = { path = "../clarity" } -stacks_common = { path = "../stacks-common", package = "stacks-common" } -proptest = { version = "1.4" } -rusqlite = { version = "=0.24.2", features = ["blob", "serde_json", "i128_blob", "bundled", "trace"] } - diff --git a/clarity-proptest/src/lib.rs b/clarity-proptest/src/lib.rs deleted file mode 100644 index 47dec8a60d..0000000000 --- a/clarity-proptest/src/lib.rs +++ /dev/null @@ -1,548 +0,0 @@ -use clarity::types::{StacksHashMap, StacksHashSet}; -use clarity::vm::contracts::Contract; -use clarity::vm::types::{ - ASCIIData, BuffData, CharType, ListData, ListTypeData, OptionalData, PrincipalData, - QualifiedContractIdentifier, ResponseData, SequenceData, SequenceSubtype, - StandardPrincipalData, StringSubtype, StringUTF8Length, TupleData, TupleTypeSignature, - TypeSignature, UTF8Data, Value, MAX_VALUE_SIZE, -}; -use clarity::vm::{ClarityName, ContractContext, ContractName}; -use proptest::prelude::*; - -mod tests; - -pub fn contract() -> impl Strategy { - fn clarity_name() -> impl Strategy { - "[a-z]{40}".prop_map(|s| s.try_into().unwrap()) - } - - ( - // contract_identifier - qualified_principal().prop_map(|p| match p { - Value::Principal(PrincipalData::Contract(qual)) => qual, - _ => unreachable!(), - }), - // variables - prop::collection::vec((clarity_name(), PropValue::any().prop_map_into()), 0..8) - .prop_map(|v| StacksHashMap(v.into_iter().collect())), - // functions - Just(StacksHashMap::new()), - // defined_traits - Just(StacksHashMap::new()), - // implemented_traits - Just(StacksHashSet::new()), - // persisted_names - Just(StacksHashSet::new()), - // meta_data_map - Just(StacksHashMap::new()), - // meta_data_var - Just(StacksHashMap::new()), - // meta_nft - Just(StacksHashMap::new()), - // meta_ft - Just(StacksHashMap::new()), - // data_size - 0u64..64, - // clarity_version - Just(clarity::vm::ClarityVersion::Clarity2), - ) - .prop_map( - |( - contract_identifier, - variables, - functions, - defined_traits, - implemented_traits, - persisted_names, - meta_data_map, - meta_data_var, - meta_nft, - meta_ft, - data_size, - clarity_version, - )| { - let mut cc = ContractContext::new(contract_identifier, clarity_version); - cc.variables = variables; - cc.functions = functions; - cc.defined_traits = defined_traits; - cc.implemented_traits = implemented_traits; - cc.persisted_names = persisted_names; - cc.meta_data_map = meta_data_map; - cc.meta_data_var = meta_data_var; - cc.meta_nft = meta_nft; - cc.meta_ft = meta_ft; - cc.data_size = data_size; - Contract { - contract_context: cc, - } - }, - ) -} - -pub fn prop_signature() -> impl Strategy { - let leaf = prop_oneof![ - Just(TypeSignature::IntType), - Just(TypeSignature::UIntType), - Just(TypeSignature::BoolType), - (0u32..128).prop_map(|s| TypeSignature::SequenceType(SequenceSubtype::BufferType( - s.try_into().unwrap() - ))), - (0u32..128).prop_map(|s| TypeSignature::SequenceType(SequenceSubtype::StringType( - StringSubtype::ASCII(s.try_into().unwrap()) - ))), - Just(TypeSignature::PrincipalType), - (0u32..32).prop_map(|s| TypeSignature::SequenceType(SequenceSubtype::StringType( - StringSubtype::UTF8(s.try_into().unwrap()) - ))) - ]; - leaf.prop_recursive(5, 64, 10, |inner| { - prop_oneof![ - // optional type: 10% NoType + 90% any other type - prop_oneof![ - 1 => Just(TypeSignature::NoType), - 9 => inner.clone(), - ] - .prop_map(|t| TypeSignature::new_option(t).unwrap()), - // response type: 20% (NoType, any) + 20% (any, NoType) + 60% (any, any) - prop_oneof![ - 1 => inner.clone().prop_map(|ok_ty| TypeSignature::new_response(ok_ty, TypeSignature::NoType).unwrap()), - 1 => inner.clone().prop_map(|err_ty| TypeSignature::new_response(TypeSignature::NoType, err_ty).unwrap()), - 3 => (inner.clone(), inner.clone()).prop_map(|(ok_ty, err_ty)| TypeSignature::new_response(ok_ty, err_ty).unwrap()), - ], - // tuple type - prop::collection::btree_map( - r#"[a-zA-Z]{1,16}"#.prop_map(|name| name.try_into().unwrap()), - inner.clone(), - 1..8 - ) - .prop_map(|btree| TypeSignature::TupleType(btree.try_into().unwrap())), - // list type - (8u32..32, inner.clone()).prop_map(|(s, ty)| (ListTypeData::new_list(ty, s).unwrap()).into()), - ] - }) -} - -#[derive(Clone, PartialEq, Eq)] -pub struct PropValue(Value); - -impl From for PropValue { - fn from(value: Value) -> Self { - PropValue(value) - } -} - -impl From for Value { - fn from(value: PropValue) -> Self { - value.0 - } -} - -impl std::fmt::Debug for PropValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("PropValue") - .field("value", &self.to_string()) - .field("type", &self.type_string()) - .finish() - } -} - -impl std::fmt::Display for PropValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match &self.0 { - Value::Sequence(SequenceData::String(clarity::vm::types::CharType::ASCII( - ASCIIData { data }, - ))) => { - write!(f, "\"")?; - for b in data { - if [b'\\', b'"'].contains(b) { - write!(f, "\\")?; - } - write!(f, "{}", *b as char)?; - } - write!(f, "\"") - } - Value::Sequence(SequenceData::String(CharType::UTF8(UTF8Data { data }))) => { - write!(f, "u\"")?; - for bytes in data { - // SAFETY: a utf8 sequence always contains a valid sequence of utf8 chars as vec of bytes - let c = unsafe { std::str::from_utf8_unchecked(bytes).chars().next().unwrap() }; - match c { - '\\' | '\"' => write!(f, "\\{c}")?, - _ if c.is_ascii_graphic() => write!(f, "{c}")?, - _ => write!(f, r#"\u{{{:X}}}"#, c as u32)?, - } - } - write!(f, "\"") - } - Value::Principal(p) => write!(f, "'{p}"), - Value::Optional(OptionalData { data }) => match data { - Some(inner) => write!(f, "(some {})", PropValue(*inner.clone())), - None => write!(f, "none"), - }, - Value::Response(ResponseData { committed, data }) => { - if *committed { - write!(f, "(ok {})", PropValue(*data.clone())) - } else { - write!(f, "(err {})", PropValue(*data.clone())) - } - } - Value::Sequence(SequenceData::List(ListData { data, .. })) => { - write!(f, "(list")?; - for d in data { - write!(f, " ")?; - write!(f, "{}", PropValue(d.clone()))?; - } - write!(f, ")") - } - Value::Tuple(data) => { - write!(f, "(tuple")?; - for (key, value) in &data.data_map { - write!(f, " ")?; - write!(f, "({} {})", &**key, PropValue(value.clone()))?; - } - write!(f, ")") - } - otherwise => write!(f, "{otherwise}"), - } - } -} - -impl PropValue { - pub fn any() -> impl Strategy { - prop_signature().prop_flat_map(prop_value).prop_map_into() - } - - pub fn from_type(ty: TypeSignature) -> impl Strategy { - prop_value(ty).prop_map_into() - } - - pub fn many_from_type(ty: TypeSignature, count: usize) -> impl Strategy> { - prop::collection::vec(Self::from_type(ty.clone()), count) - } - - pub fn any_sequence(size: usize) -> impl Strategy { - let any_list = prop_signature() - .prop_ind_flat_map2(move |ty| prop::collection::vec(prop_value(ty), size)) - .prop_map(move |(ty, vec)| { - Value::Sequence(SequenceData::List(ListData { - data: vec, - type_signature: ListTypeData::new_list(ty, size as u32).unwrap(), - })) - }); - // TODO: add string-utf8 - prop_oneof![ - // 10% chance for a buffer - 1 => buffer(size as u32), - // 10% chance for a string-ascii - 1 => string_ascii(size as u32), - // 80% chance for a list - 8 => any_list - ] - .prop_map_into() - } -} - -impl TryFrom> for PropValue { - type Error = clarity::vm::errors::Error; - - fn try_from(values: Vec) -> Result { - let values = values.into_iter().map(Value::from).collect(); - Value::cons_list_unsanitized(values).map(PropValue::from) - } -} - -fn prop_value(ty: TypeSignature) -> impl Strategy { - match ty { - TypeSignature::NoType => unreachable!(), - TypeSignature::IntType => int().boxed(), - TypeSignature::UIntType => uint().boxed(), - TypeSignature::BoolType => bool().boxed(), - TypeSignature::OptionalType(ty) => optional(*ty).boxed(), - TypeSignature::ResponseType(ok_err) => response(ok_err.0, ok_err.1).boxed(), - TypeSignature::SequenceType(SequenceSubtype::BufferType(size)) => { - buffer(size.into()).boxed() - } - TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII(size))) => { - string_ascii(size.into()).boxed() - } - TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8(size))) => { - string_utf8(size.into()).boxed() - } - TypeSignature::SequenceType(SequenceSubtype::ListType(list_type_data)) => { - list(list_type_data).boxed() - } - TypeSignature::TupleType(tuple_ty) => tuple(tuple_ty).boxed(), - TypeSignature::PrincipalType => { - prop_oneof![standard_principal(), qualified_principal()].boxed() - } - // TODO - TypeSignature::ListUnionType(_) => todo!(), - TypeSignature::CallableType(_) => todo!(), - TypeSignature::TraitReferenceType(_) => todo!(), - } -} - -fn int() -> impl Strategy { - any::().prop_map(Value::Int) -} - -fn uint() -> impl Strategy { - any::().prop_map(Value::UInt) -} - -fn bool() -> impl Strategy { - any::().prop_map(Value::Bool) -} - -pub fn string_ascii(size: u32) -> impl Strategy { - let size = size as usize; - prop::collection::vec(0x20u8..0x7e, size..=size).prop_map(|bytes| { - Value::Sequence(SequenceData::String(clarity::vm::types::CharType::ASCII( - clarity::vm::types::ASCIIData { data: bytes }, - ))) - }) -} - -pub fn string_utf8(size: u32) -> impl Strategy { - prop::collection::vec(any::(), size as usize).prop_map(|chars| { - let mut data = Vec::with_capacity(chars.len()); - for c in chars { - let mut encoded_char = vec![0; c.len_utf8()]; - c.encode_utf8(encoded_char.as_mut()); - data.push(encoded_char); - } - Value::Sequence(SequenceData::String(CharType::UTF8(UTF8Data { data }))) - }) -} - -fn buffer(size: u32) -> impl Strategy { - let size = size as usize; - prop::collection::vec(any::(), size..=size) - .prop_map(|bytes| Value::Sequence(SequenceData::Buffer(BuffData { data: bytes }))) -} - -fn optional(inner_ty: TypeSignature) -> impl Strategy { - match inner_ty { - TypeSignature::NoType => Just(Value::none()).boxed(), - _ => prop::option::of(prop_value(inner_ty)) - .prop_map(|v| { - Value::Optional(OptionalData { - data: v.map(Box::new), - }) - }) - .boxed(), - } -} - -fn response(ok_ty: TypeSignature, err_ty: TypeSignature) -> impl Strategy { - match (ok_ty, err_ty) { - (TypeSignature::NoType, err_ty) => prop_value(err_ty) - .prop_map(|err| { - Value::Response(ResponseData { - committed: false, - data: Box::new(err), - }) - }) - .boxed(), - (ok_ty, TypeSignature::NoType) => prop_value(ok_ty) - .prop_map(|ok| { - Value::Response(ResponseData { - committed: true, - data: Box::new(ok), - }) - }) - .boxed(), - (ok_ty, err_ty) => prop::result::maybe_err(prop_value(ok_ty), prop_value(err_ty)) - .prop_map(|res| { - Value::Response(ResponseData { - committed: res.is_ok(), - data: res.map_or_else(Box::new, Box::new), - }) - }) - .boxed(), - } -} - -fn list(list_type_data: ListTypeData) -> impl Strategy { - prop::collection::vec( - prop_value(list_type_data.get_list_item_type().clone()), - 0..=list_type_data.get_max_len() as usize, - ) - .prop_map(move |v| { - Value::Sequence(SequenceData::List(ListData { - data: v, - type_signature: list_type_data.clone(), - })) - }) -} - -fn tuple(tuple_ty: TupleTypeSignature) -> impl Strategy { - let fields: Vec<_> = tuple_ty.get_type_map().keys().cloned().collect(); - let strategies: Vec<_> = tuple_ty - .get_type_map() - .values() - .cloned() - .map(prop_value) - .collect(); - strategies.prop_map(move |vec_values| { - TupleData { - type_signature: tuple_ty.clone(), - data_map: fields.clone().into_iter().zip(vec_values).collect(), - } - .into() - }) -} - -fn standard_principal() -> impl Strategy { - (0u8..32, prop::collection::vec(any::(), 20)) - .prop_map(|(v, hash)| { - Value::Principal(PrincipalData::Standard(StandardPrincipalData( - v, - hash.try_into().unwrap(), - ))) - }) - .no_shrink() -} - -fn qualified_principal() -> impl Strategy { - (standard_principal(), "[a-zA-Z]{1,40}").prop_map(|(issuer_value, name)| { - let Value::Principal(PrincipalData::Standard(issuer)) = issuer_value else { - unreachable!() - }; - let name = ContractName::from(&*name); - Value::Principal(PrincipalData::Contract(QualifiedContractIdentifier { - issuer, - name, - })) - }) -} - -trait TypePrinter { - fn type_string(&self) -> String; -} - -impl TypePrinter for PropValue { - fn type_string(&self) -> String { - self.0.type_string() - } -} - -impl TypePrinter for Value { - fn type_string(&self) -> String { - match &self { - Value::Int(_) => type_string(&TypeSignature::IntType), - Value::UInt(_) => type_string(&TypeSignature::UIntType), - Value::Bool(_) => type_string(&TypeSignature::BoolType), - Value::Sequence(SequenceData::Buffer(length)) => { - type_string(&TypeSignature::SequenceType(SequenceSubtype::BufferType( - length - .len() - .expect("Failed to get buffer length from sequence data"), - ))) - } - Value::Sequence(SequenceData::String(CharType::ASCII(data))) => type_string( - &TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII( - data.len() - .expect("Failed to get ASCII string length from sequence data"), - ))), - ), - Value::Sequence(SequenceData::String(CharType::UTF8(data))) => type_string( - &TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8( - StringUTF8Length::try_from(u32::from( - data.len() - .expect("Failed to get UTF8 string length from sequence data"), - )) - .unwrap_or(StringUTF8Length::try_from(MAX_VALUE_SIZE / 4).unwrap()), - ))), - ), - Value::Optional(inner) => inner.type_string(), - Value::Response(inner) => inner.type_string(), - Value::Sequence(SequenceData::List(list_data)) => list_data.type_string(), - Value::Tuple(data) => data.type_string(), - Value::Principal(_) => type_string(&TypeSignature::PrincipalType), - Value::CallableContract(_) => type_string(&TypeSignature::PrincipalType), - } - } -} - -impl TypePrinter for OptionalData { - fn type_string(&self) -> String { - let inner = match self.data { - Some(ref inner) => inner.type_string(), - None => "int".to_owned(), // We need to default to something here - }; - format!("(optional {inner})") - } -} - -impl TypePrinter for ResponseData { - fn type_string(&self) -> String { - let (ok_string, err_string) = if self.committed { - (self.data.type_string(), "int".to_owned()) - } else { - ("int".to_owned(), self.data.type_string()) - }; - format!("(response {} {})", ok_string, err_string) - } -} - -impl TypePrinter for ListData { - fn type_string(&self) -> String { - format!( - "(list {} {})", - self.data.len(), - type_string(self.type_signature.get_list_item_type()) - ) - } -} - -impl TypePrinter for TupleData { - fn type_string(&self) -> String { - type_string(&TypeSignature::TupleType(self.type_signature.clone())) - } -} - -pub fn type_string(ty: &TypeSignature) -> String { - match ty { - TypeSignature::IntType => "int".to_owned(), - TypeSignature::UIntType => "uint".to_owned(), - TypeSignature::BoolType => "bool".to_owned(), - TypeSignature::OptionalType(inner) => format!("(optional {})", type_string(inner)), - TypeSignature::ResponseType(inner) => format!( - "(response {} {})", - type_string(&inner.0), - type_string(&inner.1) - ), - TypeSignature::SequenceType(SequenceSubtype::BufferType(len)) => format!("(buff {len})"), - TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII(len))) => { - format!("(string-ascii {len})") - } - TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8(len))) => { - format!("(string-utf8 {len})") - } - TypeSignature::SequenceType(SequenceSubtype::ListType(list_type_data)) => { - format!( - "(list {} {})", - list_type_data.get_max_len(), - type_string(list_type_data.get_list_item_type()) - ) - } - TypeSignature::TupleType(tuple_ty) => { - let mut s = String::new(); - s.push('{'); - for (key, value) in tuple_ty.get_type_map() { - s.push_str(key); - s.push(':'); - s.push_str(&type_string(value)); - s.push(','); - } - s.push('}'); - s - } - TypeSignature::PrincipalType => "principal".to_owned(), - TypeSignature::CallableType(_) => "principal".to_owned(), - TypeSignature::TraitReferenceType(_) => "principal".to_owned(), - TypeSignature::NoType => "int".to_owned(), // Use "int" as a default type - TypeSignature::ListUnionType(_) => unreachable!(), - } -} diff --git a/clarity-proptest/src/tests.rs b/clarity-proptest/src/tests.rs deleted file mode 100644 index 6d9c0a1466..0000000000 --- a/clarity-proptest/src/tests.rs +++ /dev/null @@ -1,57 +0,0 @@ -use proptest::prelude::*; -use clarity::vm::database::{ClarityBackingStore, ClarityDatabase, MemoryBackingStore, NULL_HEADER_DB, NULL_BURN_STATE_DB}; -use rusqlite::NO_PARAMS; - -use crate::contract; - -proptest! { - #[test] - fn insert_contract(contract in contract()) { - let mut store = MemoryBackingStore::new(); - let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - - db.begin(); - - //let contract: Contract = Faker.fake(); - - let contract_id = contract.contract_context.contract_identifier.clone(); - - db.insert_contract(&contract_id, contract) - .expect("failed to insert contract into backing store"); - - let exists = sql_exists( - &mut store, - &format!( - "SELECT * FROM metadata_table WHERE key LIKE '%{}%'", - contract_id.to_string() - ), - ); - assert!(!exists); - } -} - - -/// Executes the provided SQL query, which is expected to return a positive -/// integer, and returns it as a u32. Panics upon SQL failure. -fn sql_query_u32(store: &mut S, sql: &str) -> u32 { - let sqlite = store.get_side_store(); - sqlite - .query_row(sql, NO_PARAMS, |row| { - let i: u32 = row.get(0)?; - Ok(i) - }) - .expect("failed to verify results in sqlite") -} - -/// Executes the provided SQL query as a subquery within a `SELECT EXISTS(...)` -/// statement. Returns true if the statement returns any rows, false otherwise. -/// Panics upon SQL failure. -fn sql_exists(store: &mut S, sql: &str) -> bool { - let sqlite = store.get_side_store(); - sqlite - .query_row(&format!("SELECT EXISTS({});", sql), NO_PARAMS, |row| { - let exists: bool = row.get(0)?; - Ok(exists) - }) - .expect("failed to verify results in sqlite") -} diff --git a/clarity/Cargo.toml b/clarity/Cargo.toml index d0446e5cba..4b4b3338ea 100644 --- a/clarity/Cargo.toml +++ b/clarity/Cargo.toml @@ -31,7 +31,6 @@ stacks_common = { package = "stacks-common", path = "../stacks-common" } rstest = "0.17.0" rstest_reuse = "0.5.0" hashbrown = { workspace = true } -fake = { workspace = true, optional = true } [dependencies.serde_json] version = "1.0" @@ -48,14 +47,14 @@ features = ["std"] [dev-dependencies] assert-json-diff = "1.0.0" proptest = { workspace = true } -clarity-proptest = { path = "../clarity-proptest" } -# a nightly rustc regression (35dbef235 2021-03-02) prevents criterion from compiling -# but it isn't necessary for tests: only benchmarks. therefore, commenting out for now. -# criterion = "0.3" +clarity = { path = "./", features = ["testing"] } +# This ensures that `stacks-common` is built using the `testing` feature +# when we build this crate in dev/test. +stacks_common = { package = "stacks-common", path = "../stacks-common", features = ["testing"] } [features] default = [] developer-mode = [] slog_json = ["stacks_common/slog_json"] -testing = ["dep:fake"] +testing = ["stacks_common/testing"] diff --git a/clarity/src/libclarity.rs b/clarity/src/libclarity.rs index daae7dcfd7..9f46691f93 100644 --- a/clarity/src/libclarity.rs +++ b/clarity/src/libclarity.rs @@ -41,6 +41,9 @@ pub extern crate rstest_reuse; #[macro_use] extern crate stacks_common; +#[cfg(test)] +pub mod proptesting; + pub use stacks_common::{ codec, consts, impl_array_hexstring_fmt, impl_array_newtype, impl_byte_array_message_codec, impl_byte_array_serde, types, util, diff --git a/clarity/src/proptesting/callables.rs b/clarity/src/proptesting/callables.rs new file mode 100644 index 0000000000..c0b904ffd5 --- /dev/null +++ b/clarity/src/proptesting/callables.rs @@ -0,0 +1,118 @@ +use proptest::prelude::*; +use rand::distributions::uniform::SampleRange; +use serde::de::value; + +use crate::vm::{callables::{DefineType, DefinedFunction, FunctionIdentifier}, database::{DataMapMetadata, DataVariableMetadata, FungibleTokenMetadata, NonFungibleTokenMetadata}, representations::TraitDefinition, types::FunctionSignature}; + +use super::*; + +pub fn function_identifier_user() -> impl Strategy { + ( + clarity_name(), + clarity_name() + ) + .prop_map(|(name, context)| + FunctionIdentifier::new_user_function(&context.to_string(), &name.to_string()) + ) +} + +pub fn function_identifier_native() -> impl Strategy { + ( + clarity_name() + ) + .prop_map(|name| + FunctionIdentifier::new_native_function(&name.to_string()) + ) +} + +pub fn function_identifier() -> impl Strategy { + prop_oneof![ + function_identifier_user(), + function_identifier_native() + ] +} + +pub fn define_type() -> impl Strategy { + prop_oneof![ + Just(DefineType::Public), + Just(DefineType::Private), + Just(DefineType::ReadOnly) + ] +} + +pub fn data_variable_metadata() -> impl Strategy { + type_signature() + .prop_map(|value_type| + DataVariableMetadata { value_type } + ) + +} + +pub fn data_map_metadata() -> impl Strategy { + ( + type_signature(), + type_signature() + ) + .prop_map(|(key_type, value_type)| + DataMapMetadata { + key_type, + value_type + } + ) +} + +pub fn nft_metadata() -> impl Strategy { + type_signature().prop_map(|key_type| + NonFungibleTokenMetadata { key_type } + ) +} + +pub fn ft_metadata() -> impl Strategy { + any::>().prop_map(|total_supply| + FungibleTokenMetadata { total_supply } + ) +} + +pub fn function_signature() -> impl Strategy { + ( + // arg_types + prop::collection::vec(type_signature(), 0..3), + // return_type + type_signature() + ) + .prop_map(|(args, returns)| + FunctionSignature { + args, + returns + } + ) +} + +pub fn defined_function() -> impl Strategy { + let x: usize = (0..3).sample_single(&mut rand::thread_rng()); + + ( + // identifier + function_identifier(), + // name + clarity_name(), + // arg_types + prop::collection::vec(type_signature(), x..=x), + // define_type + define_type(), + // arguments + prop::collection::vec(clarity_name(), x..=x), + // body + symbolic_expression(), + ) + .prop_map(|(identifier, name, arg_types, define_type, arguments, body)| + DefinedFunction { + identifier, + name, + arg_types, + define_type, + arguments, + body + } + ) +} \ No newline at end of file diff --git a/clarity/src/proptesting/contracts.rs b/clarity/src/proptesting/contracts.rs new file mode 100644 index 0000000000..69d241d64d --- /dev/null +++ b/clarity/src/proptesting/contracts.rs @@ -0,0 +1,106 @@ +use proptest::collection::btree_map; +use proptest::prelude::*; +use stacks_common::proptesting::*; + +use crate::vm::contracts::Contract; +use crate::vm::{types::PrincipalData, ClarityVersion, ContractContext, Value}; +use crate::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; + +use super::*; + +pub fn contract_context(clarity_version: ClarityVersion) -> impl Strategy { + ( + // contract_identifier + principal_contract().prop_map(|p| match p { + Value::Principal(PrincipalData::Contract(qual)) => qual, + _ => unreachable!(), + }), + // variables + prop::collection::vec( + (clarity_name(), PropValue::any().prop_map_into()), + 0..8 + ).prop_map(|v| + HashMap(v.into_iter().collect() + ) + ), + // functions + stacks_hash_map( + clarity_name(), + defined_function(), 1..5 + ), + // defined_traits + stacks_hash_map( + clarity_name(), + btree_map( + clarity_name(), + function_signature(), + 1..5), + 1..5 + ), + // implemented_traits + stacks_hash_set(trait_identifier(), 0..3), + // persisted_names + stacks_hash_set(clarity_name(), 0..5), + // meta_data_map + stacks_hash_map( + clarity_name(), + data_map_metadata(), + 1..5 + ), + // meta_data_var + stacks_hash_map( + clarity_name(), + data_variable_metadata(), + 1..5 + ), + // meta_nft + stacks_hash_map( + clarity_name(), + nft_metadata(), + 1..5 + ), + // meta_ft + stacks_hash_map( + clarity_name(), + ft_metadata(), + 1..5 + ), + // data_size + 0u64..64, + ) + .prop_map( + move |( + contract_identifier, + variables, + functions, + defined_traits, + implemented_traits, + persisted_names, + meta_data_map, + meta_data_var, + meta_nft, + meta_ft, + data_size, + )| { + let mut cc = ContractContext::new(contract_identifier, clarity_version); + cc.variables = variables; + cc.functions = functions; + cc.defined_traits = defined_traits; + cc.implemented_traits = implemented_traits; + cc.persisted_names = persisted_names; + cc.meta_data_map = meta_data_map; + cc.meta_data_var = meta_data_var; + cc.meta_nft = meta_nft; + cc.meta_ft = meta_ft; + cc.data_size = data_size; + cc + }, + ) +} + +pub fn contract() -> impl Strategy { + clarity_version() + .prop_flat_map(contract_context) + .prop_map(|contract_context| + Contract { contract_context }) +} \ No newline at end of file diff --git a/clarity/src/proptesting/mod.rs b/clarity/src/proptesting/mod.rs new file mode 100644 index 0000000000..1ffba30e24 --- /dev/null +++ b/clarity/src/proptesting/mod.rs @@ -0,0 +1,22 @@ +use proptest::{prop_oneof, strategy::{Just, Strategy, ValueTree}, test_runner::{Config, RngAlgorithm, TestRng, TestRunner}}; +use rand::Rng; +use stacks_common::types::StacksHashMap as HashMap; + +pub mod types; +pub mod values; +pub mod callables; +pub mod representations; +pub mod contracts; + +pub use types::*; +pub use values::*; +pub use callables::*; +pub use representations::*; +pub use contracts::*; + +pub fn clarity_version() -> impl Strategy { + prop_oneof![ + Just(crate::vm::ClarityVersion::Clarity1), + Just(crate::vm::ClarityVersion::Clarity2), + ] +} \ No newline at end of file diff --git a/clarity/src/proptesting/representations.rs b/clarity/src/proptesting/representations.rs new file mode 100644 index 0000000000..b9db8f8c7f --- /dev/null +++ b/clarity/src/proptesting/representations.rs @@ -0,0 +1,61 @@ +use proptest::prelude::*; + +use crate::vm::{representations::{Span, TraitDefinition}, ClarityName, ContractName, SymbolicExpression, SymbolicExpressionType}; + +use super::*; + +pub fn clarity_name() -> impl Strategy { + "[a-z]{40}".prop_map(|s| s.try_into().unwrap()) +} + +pub fn contract_name() -> impl Strategy { + "[a-zA-Z]{1,40}".prop_map(|s| s.try_into().unwrap()) +} + +pub fn trait_definition() -> impl Strategy { + prop_oneof![ + trait_identifier().prop_map(TraitDefinition::Defined), + trait_identifier().prop_map(TraitDefinition::Imported) + ] +} + +pub fn symbolic_expression() -> impl Strategy { + ( + symbolic_expression_type(), + 0u64..u64::MAX, + Just(Span::zero()), + Just(Vec::<(String, Span)>::new()), + Just(None::), + Just(Vec::<(String, Span)>::new()), + ) + .prop_map(|(expr, id, span, pre_comments, end_line_comment, post_comments)| + SymbolicExpression { + expr, + id, + #[cfg(feature = "developer-mode")] + span, + #[cfg(feature = "developer-mode")] + pre_comments, + #[cfg(feature = "developer-mode")] + end_line_comment, + #[cfg(feature = "developer-mode")] + post_comments, + } + ) +} + +pub fn symbolic_expression_type() -> impl Strategy { + prop_oneof![ + // Atom + clarity_name().prop_map(SymbolicExpressionType::Atom), + // AtomValue + PropValue::any().prop_map(|val| SymbolicExpressionType::AtomValue(val.into())), + // LiteralValue + PropValue::any().prop_map(|val| SymbolicExpressionType::LiteralValue(val.into())), + // Field + trait_identifier().prop_map(SymbolicExpressionType::Field), + // TraitReference + (clarity_name(), trait_definition()) + .prop_map(|(n, t)| SymbolicExpressionType::TraitReference(n, t)), + ] +} \ No newline at end of file diff --git a/clarity/src/proptesting/types.rs b/clarity/src/proptesting/types.rs new file mode 100644 index 0000000000..66c4ec2824 --- /dev/null +++ b/clarity/src/proptesting/types.rs @@ -0,0 +1,95 @@ +use proptest::prelude::*; +use proptest::string::string_regex; + +use crate::types::{StacksHashMap, StacksHashSet}; +use crate::vm::contracts::Contract; +use crate::vm::types::{ + ASCIIData, BuffData, CharType, ListData, ListTypeData, OptionalData, PrincipalData, + QualifiedContractIdentifier, ResponseData, SequenceData, SequenceSubtype, + StandardPrincipalData, StringSubtype, StringUTF8Length, TupleData, TupleTypeSignature, + TypeSignature, UTF8Data, Value, MAX_VALUE_SIZE, TraitIdentifier +}; +use crate::vm::callables::{DefinedFunction, FunctionIdentifier, DefineType}; +use crate::vm::{ClarityName, ClarityVersion, ContractContext, ContractName}; +use crate::vm::representations::{Span, SymbolicExpression, SymbolicExpressionType, TraitDefinition}; + +use super::*; + +pub fn standard_principal_data() -> impl Strategy { + ( + 0u8..32, + prop::collection::vec(any::(), 20) + ) + .prop_map(|(v, hash)| + StandardPrincipalData(v, hash.try_into().unwrap()) + ) +} + +pub fn qualified_contract_identifier() -> impl Strategy { + ( + standard_principal_data(), + contract_name() + ) + .prop_map(|(issuer, name)| + QualifiedContractIdentifier { + issuer, + name + } + ) +} + +pub fn trait_identifier() -> impl Strategy { + ( + clarity_name(), + qualified_contract_identifier() + ) + .prop_map(|(name, contract_identifier)| + TraitIdentifier { + name, + contract_identifier + } + ) +} + +pub fn type_signature() -> impl Strategy { + let leaf = prop_oneof![ + Just(TypeSignature::IntType), + Just(TypeSignature::UIntType), + Just(TypeSignature::BoolType), + (0u32..128).prop_map(|s| TypeSignature::SequenceType(SequenceSubtype::BufferType( + s.try_into().unwrap() + ))), + (0u32..128).prop_map(|s| TypeSignature::SequenceType(SequenceSubtype::StringType( + StringSubtype::ASCII(s.try_into().unwrap()) + ))), + Just(TypeSignature::PrincipalType), + (0u32..32).prop_map(|s| TypeSignature::SequenceType(SequenceSubtype::StringType( + StringSubtype::UTF8(s.try_into().unwrap()) + ))) + ]; + + leaf.prop_recursive(5, 64, 10, |inner| prop_oneof![ + // optional type: 10% NoType + 90% any other type + prop_oneof![ + 1 => Just(TypeSignature::NoType), + 9 => inner.clone(), + ] + .prop_map(|t| TypeSignature::new_option(t).unwrap()), + // response type: 20% (NoType, any) + 20% (any, NoType) + 60% (any, any) + prop_oneof![ + 1 => inner.clone().prop_map(|ok_ty| TypeSignature::new_response(ok_ty, TypeSignature::NoType).unwrap()), + 1 => inner.clone().prop_map(|err_ty| TypeSignature::new_response(TypeSignature::NoType, err_ty).unwrap()), + 3 => (inner.clone(), inner.clone()).prop_map(|(ok_ty, err_ty)| TypeSignature::new_response(ok_ty, err_ty).unwrap()), + ], + // tuple type + prop::collection::btree_map( + r#"[a-zA-Z]{1,16}"#.prop_map(|name| name.try_into().unwrap()), + inner.clone(), + 1..8 + ) + .prop_map(|btree| TypeSignature::TupleType(btree.try_into().unwrap())), + // list type + (8u32..32, inner.clone()).prop_map(|(s, ty)| (ListTypeData::new_list(ty, s).unwrap()).into()), + ]) +} + diff --git a/clarity/src/proptesting/values.rs b/clarity/src/proptesting/values.rs new file mode 100644 index 0000000000..2b92052114 --- /dev/null +++ b/clarity/src/proptesting/values.rs @@ -0,0 +1,230 @@ +use proptest::prelude::*; + +use crate::vm::{types::{BuffData, CharType, ListData, ListTypeData, OptionalData, PrincipalData, QualifiedContractIdentifier, ResponseData, SequenceData, SequenceSubtype, StandardPrincipalData, StringSubtype, TupleData, TupleTypeSignature, TypeSignature, UTF8Data}, ContractName, Value}; + +use super::*; + +pub fn value(ty: TypeSignature) -> impl Strategy { + match ty { + TypeSignature::NoType => unreachable!(), + TypeSignature::IntType => int().boxed(), + TypeSignature::UIntType => uint().boxed(), + TypeSignature::BoolType => bool().boxed(), + TypeSignature::OptionalType(ty) => optional(*ty).boxed(), + TypeSignature::ResponseType(ok_err) => response(ok_err.0, ok_err.1).boxed(), + TypeSignature::SequenceType(SequenceSubtype::BufferType(size)) => { + buffer(size.into()).boxed() + } + TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII(size))) => { + string_ascii(size.into()).boxed() + } + TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8(size))) => { + string_utf8(size.into()).boxed() + } + TypeSignature::SequenceType(SequenceSubtype::ListType(list_type_data)) => { + list(list_type_data).boxed() + } + TypeSignature::TupleType(tuple_ty) => tuple(tuple_ty).boxed(), + TypeSignature::PrincipalType => { + prop_oneof![principal_standard(), principal_contract()].boxed() + } + // TODO + TypeSignature::ListUnionType(_) => todo!(), + TypeSignature::CallableType(_) => todo!(), + TypeSignature::TraitReferenceType(_) => todo!(), + } +} + +pub fn int() -> impl Strategy { + any::().prop_map(Value::Int) +} + +pub fn uint() -> impl Strategy { + any::().prop_map(Value::UInt) +} + +pub fn bool() -> impl Strategy { + any::().prop_map(Value::Bool) +} + +pub fn string_ascii(size: u32) -> impl Strategy { + let size = size as usize; + prop::collection::vec(0x20u8..0x7e, size..=size).prop_map(|bytes| { + Value::Sequence(SequenceData::String(crate::vm::types::CharType::ASCII( + crate::vm::types::ASCIIData { data: bytes }, + ))) + }) +} + +pub fn string_utf8(size: u32) -> impl Strategy { + prop::collection::vec(any::(), size as usize).prop_map(|chars| { + let mut data = Vec::with_capacity(chars.len()); + for c in chars { + let mut encoded_char = vec![0; c.len_utf8()]; + c.encode_utf8(encoded_char.as_mut()); + data.push(encoded_char); + } + Value::Sequence(SequenceData::String(CharType::UTF8(UTF8Data { data }))) + }) +} + +pub fn buffer(size: u32) -> impl Strategy { + let size = size as usize; + prop::collection::vec(any::(), size..=size) + .prop_map(|bytes| Value::Sequence(SequenceData::Buffer(BuffData { data: bytes }))) +} + +pub fn optional(inner_ty: TypeSignature) -> impl Strategy { + match inner_ty { + TypeSignature::NoType => Just(Value::none()).boxed(), + _ => prop::option::of(value(inner_ty)) + .prop_map(|v| { + Value::Optional(OptionalData { + data: v.map(Box::new), + }) + }) + .boxed(), + } +} + +pub fn response(ok_ty: TypeSignature, err_ty: TypeSignature) -> impl Strategy { + match (ok_ty, err_ty) { + (TypeSignature::NoType, err_ty) => value(err_ty) + .prop_map(|err| { + Value::Response(ResponseData { + committed: false, + data: Box::new(err), + }) + }) + .boxed(), + (ok_ty, TypeSignature::NoType) => value(ok_ty) + .prop_map(|ok| { + Value::Response(ResponseData { + committed: true, + data: Box::new(ok), + }) + }) + .boxed(), + (ok_ty, err_ty) => prop::result::maybe_err(value(ok_ty), value(err_ty)) + .prop_map(|res| { + Value::Response(ResponseData { + committed: res.is_ok(), + data: res.map_or_else(Box::new, Box::new), + }) + }) + .boxed(), + } +} + +pub fn list(list_type_data: ListTypeData) -> impl Strategy { + prop::collection::vec( + value(list_type_data.get_list_item_type().clone()), + 0..=list_type_data.get_max_len() as usize, + ) + .prop_map(move |v| { + Value::Sequence(SequenceData::List(ListData { + data: v, + type_signature: list_type_data.clone(), + })) + }) +} + +pub fn tuple(tuple_ty: TupleTypeSignature) -> impl Strategy { + let fields: Vec<_> = tuple_ty.get_type_map().keys().cloned().collect(); + let strategies: Vec<_> = tuple_ty + .get_type_map() + .values() + .cloned() + .map(value) + .collect(); + strategies.prop_map(move |vec_values| { + TupleData { + type_signature: tuple_ty.clone(), + data_map: fields.clone().into_iter().zip(vec_values).collect(), + } + .into() + }) +} + +pub fn principal_standard() -> impl Strategy { + (0u8..32, prop::collection::vec(any::(), 20)) + .prop_map(|(v, hash)| { + Value::Principal(PrincipalData::Standard(StandardPrincipalData( + v, + hash.try_into().unwrap(), + ))) + }) + .no_shrink() +} + +pub fn principal_contract() -> impl Strategy { + (principal_standard(), "[a-zA-Z]{1,40}").prop_map(|(issuer_value, name)| { + let Value::Principal(PrincipalData::Standard(issuer)) = issuer_value else { + unreachable!() + }; + let name = ContractName::from(&*name); + Value::Principal(PrincipalData::Contract(QualifiedContractIdentifier { + issuer, + name, + })) + }) +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PropValue(Value); + +impl From for PropValue { + fn from(value: Value) -> Self { + PropValue(value) + } +} + +impl From for Value { + fn from(value: PropValue) -> Self { + value.0 + } +} + +impl PropValue { + pub fn any() -> impl Strategy { + type_signature().prop_flat_map(value).prop_map_into() + } + + pub fn from_type(ty: TypeSignature) -> impl Strategy { + value(ty).prop_map_into() + } + + pub fn many_from_type(ty: TypeSignature, count: usize) -> impl Strategy> { + prop::collection::vec(Self::from_type(ty.clone()), count) + } + + pub fn any_sequence(size: usize) -> impl Strategy { + let any_list = type_signature() + .prop_ind_flat_map2(move |ty| prop::collection::vec(value(ty), size)) + .prop_map(move |(ty, vec)| { + Value::Sequence(SequenceData::List(ListData { + data: vec, + type_signature: ListTypeData::new_list(ty, size as u32).unwrap(), + })) + }); + // TODO: add string-utf8 + prop_oneof![ + // 10% chance for a buffer + 1 => buffer(size as u32), + // 10% chance for a string-ascii + 1 => string_ascii(size as u32), + // 80% chance for a list + 8 => any_list + ] + .prop_map_into() + } +} + +impl TryFrom> for PropValue { + type Error = crate::vm::errors::Error; + + fn try_from(values: Vec) -> Result { + let values = values.into_iter().map(Value::from).collect(); + Value::cons_list_unsanitized(values).map(PropValue::from) + } +} \ No newline at end of file diff --git a/clarity/src/vm/callables.rs b/clarity/src/vm/callables.rs index a5e074d688..a99d0d3700 100644 --- a/clarity/src/vm/callables.rs +++ b/clarity/src/vm/callables.rs @@ -56,7 +56,6 @@ pub enum CallableType { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum DefineType { ReadOnly, Public, @@ -121,7 +120,6 @@ pub fn cost_input_sized_vararg(args: &[Value]) -> Result { } #[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct FunctionIdentifier { identifier: String, } @@ -393,14 +391,14 @@ impl CallableType { } impl FunctionIdentifier { - fn new_native_function(name: &str) -> FunctionIdentifier { + pub fn new_native_function(name: &str) -> FunctionIdentifier { let identifier = format!("_native_:{}", name); FunctionIdentifier { identifier: identifier, } } - fn new_user_function(name: &str, context: &str) -> FunctionIdentifier { + pub fn new_user_function(name: &str, context: &str) -> FunctionIdentifier { let identifier = format!("{}:{}", context, name); FunctionIdentifier { identifier: identifier, diff --git a/clarity/src/vm/contexts.rs b/clarity/src/vm/contexts.rs index d263fa5ec8..15dce23356 100644 --- a/clarity/src/vm/contexts.rs +++ b/clarity/src/vm/contexts.rs @@ -205,7 +205,6 @@ pub struct GlobalContext<'a, 'hooks> { } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct ContractContext { pub contract_identifier: QualifiedContractIdentifier, pub variables: HashMap, diff --git a/clarity/src/vm/contracts.rs b/clarity/src/vm/contracts.rs index be86d7a5e7..b636325cc4 100644 --- a/clarity/src/vm/contracts.rs +++ b/clarity/src/vm/contracts.rs @@ -26,7 +26,6 @@ use crate::vm::version::ClarityVersion; use crate::vm::{apply, eval_all, Value}; #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct Contract { pub contract_context: ContractContext, } diff --git a/clarity/src/vm/database/structures.rs b/clarity/src/vm/database/structures.rs index b8fb414950..937eda2bdc 100644 --- a/clarity/src/vm/database/structures.rs +++ b/clarity/src/vm/database/structures.rs @@ -74,7 +74,6 @@ macro_rules! clarity_serializable { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct FungibleTokenMetadata { pub total_supply: Option, } @@ -82,7 +81,6 @@ pub struct FungibleTokenMetadata { clarity_serializable!(FungibleTokenMetadata); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct NonFungibleTokenMetadata { pub key_type: TypeSignature, } @@ -90,7 +88,6 @@ pub struct NonFungibleTokenMetadata { clarity_serializable!(NonFungibleTokenMetadata); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct DataMapMetadata { pub key_type: TypeSignature, pub value_type: TypeSignature, @@ -99,7 +96,6 @@ pub struct DataMapMetadata { clarity_serializable!(DataMapMetadata); #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct DataVariableMetadata { pub value_type: TypeSignature, } diff --git a/clarity/src/vm/database/tests/clarity_db_tests.proptest-regressions b/clarity/src/vm/database/tests/clarity_db_tests.proptest-regressions new file mode 100644 index 0000000000..d33e1207fa --- /dev/null +++ b/clarity/src/vm/database/tests/clarity_db_tests.proptest-regressions @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 44a2de005734c41ec4acdb6ee75d149396bd7eef4da14a5394136bf2709c57bc # shrinks to contract = Contract { contract_context: ContractContext { contract_identifier: QualifiedContractIdentifier { issuer: StandardPrincipalData(SFZ9QYBVSPEMR0N5TNE04KKADNKK5CC4WGPVJ9E3), name: ContractName("a") }, variables: StacksHashMap({}), functions: StacksHashMap({ClarityName("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"): DefinedFunction { identifier: FunctionIdentifier { identifier: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, name: ClarityName("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), arg_types: [], define_type: Public, arguments: [ClarityName("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")], body: SymbolicExpression { expr: Field(TraitIdentifier { name: ClarityName("aaaqxfqzdtenocsexxufoapwudixroehnpfrwejw"), contract_identifier: QualifiedContractIdentifier { issuer: StandardPrincipalData(SXVR4HA3ZP608RM0VW842ME3MBGPPGME3AXR05PG), name: ContractName("CIzVzDUEJpztkQgAnXpbQ") } }), id: 8322152634755796411 } }}), defined_traits: StacksHashMap({ClarityName("yqjoixyngkmxxymzotyuprvihevanobhauphmaea"): {ClarityName("fwnbpjiolicgdlvidojzwsxnukukgnorxftwxxib"): FunctionSignature { args: [OptionalType(BoolType), ResponseType((IntType, NoType))], returns: OptionalType(SequenceType(StringType(UTF8(StringUTF8Length(14))))) }}}), implemented_traits: StacksHashSet({TraitIdentifier { name: ClarityName("amuosfpuavlsrfxrjgpiovauqrrbztmrdeyvowae"), contract_identifier: QualifiedContractIdentifier { issuer: StandardPrincipalData(SP1J7XCE1PBAP3T5RXQB198714S6VB5NCWC15XWWH), name: ContractName("ohTSbunZmLnHHLKmOXW") } }, TraitIdentifier { name: ClarityName("btsssgqmytkeuvrcevlvfjubrqgidbaiyfhbpeqf"), contract_identifier: QualifiedContractIdentifier { issuer: StandardPrincipalData(S02599A868C3Z6JZSTED37HHKV3XTT4QVS80JEYMR), name: ContractName("MgMNMSrWqgrXYaDBPHkFWVZ") } }}), persisted_names: StacksHashSet({ClarityName("vwmatxcbwcqikstlcpobbbgrwkztotfvtqbvrwws"), ClarityName("bnvgwubsasnhjsgxqyqaigaxgnxvmttrlzphzhgu"), ClarityName("edjpvbitaeszopxsyfeecylkhwiudexmklwbnzrt")}), meta_data_map: StacksHashMap({ClarityName("rccoqoirtsdyqkctrbsvoakrhbzufgbhsborwbxz"): DataMapMetadata { key_type: TupleType(TupleTypeSignature { "IzFLwirBWTTeQxCW": (buff 114), "KpRwliLw": uint, "SpPPzWMrDrYq": (buff 62), "UGwUCEU": (buff 61), "kstVrzo": (string-utf8 31), "yFtTFUqvIRm": (string-utf8 17),}), value_type: ResponseType((PrincipalType, SequenceType(StringType(UTF8(StringUTF8Length(22)))))) }, ClarityName("hzimmazvkedqordbdaywazyskqdhdzzqusdnedwo"): DataMapMetadata { key_type: ResponseType((UIntType, BoolType)), value_type: TupleType(TupleTypeSignature { "DXboPISrAIudN": int, "PRhPHewsyHFff": (response (string-utf8 20) (string-utf8 15)), "lIO": (string-ascii 127), "mvQRanZgRpcGcct": uint,}) }, ClarityName("txwizbtmdrypbggfmnuqergiszydhxnlorlsbtwa"): DataMapMetadata { key_type: OptionalType(SequenceType(StringType(ASCII(BufferLength(79))))), value_type: ResponseType((NoType, SequenceType(StringType(ASCII(BufferLength(123)))))) }}), meta_data_var: StacksHashMap({ClarityName("kevhnvabdsujgvsxnixkcnjxlsaqwmwcdhjrrwfi"): DataVariableMetadata { value_type: SequenceType(ListType(ListTypeData { max_len: 12, entry_type: SequenceType(BufferType(BufferLength(100))) })) }, ClarityName("kifjvjytlvijyxnnhdbpmdppttpbugjtvpcjspvv"): DataVariableMetadata { value_type: OptionalType(SequenceType(StringType(ASCII(BufferLength(88))))) }}), meta_nft: StacksHashMap({ClarityName("flnkzucidxkpmohmioosxupwhvaugcczrexdxyky"): NonFungibleTokenMetadata { key_type: OptionalType(UIntType) }, ClarityName("zualwtsklswtrycjhvzajfhjikeayznwxavurltn"): NonFungibleTokenMetadata { key_type: UIntType }}), meta_ft: StacksHashMap({ClarityName("raaodzfstgmvfmhmzpbkmolwmuwlymlbalsntqme"): FungibleTokenMetadata { total_supply: None }}), data_size: 20, clarity_version: Clarity1 } } diff --git a/clarity/src/vm/database/tests/clarity_db_tests.rs b/clarity/src/vm/database/tests/clarity_db_tests.rs index dfb5043173..3855b06672 100644 --- a/clarity/src/vm/database/tests/clarity_db_tests.rs +++ b/clarity/src/vm/database/tests/clarity_db_tests.rs @@ -1,10 +1,8 @@ -use fake::{Fake, Faker}; use rusqlite::NO_PARAMS; +use stacks_common::proptesting::sha_512_trunc_256_sum; use stacks_common::util::hash::Sha512Trunc256Sum; -#[cfg(test)] use proptest::prelude::*; -#[cfg(test)] -use clarity_proptest::*; +use crate::proptesting::*; use crate::vm::contracts::Contract; use crate::vm::database::clarity_store::ContractCommitment; @@ -12,7 +10,6 @@ use crate::vm::database::{ ClarityBackingStore, ClarityDatabase, ClaritySerializable, MemoryBackingStore, NULL_BURN_STATE_DB, NULL_HEADER_DB, }; -use crate::vm::fakes::raw::EnglishWord; use crate::vm::Value; proptest! { @@ -22,8 +19,6 @@ proptest! { let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); db.begin(); - - let contract: Contract = Faker.fake(); let contract_id = contract.contract_context.contract_identifier.clone(); @@ -39,17 +34,14 @@ proptest! { ); assert!(!exists); } -} -#[test] -fn get_contract() { - for _ in 0..1000 { + #[test] + fn get_contract(contract in contract()) { let mut store = MemoryBackingStore::new(); let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); db.begin(); - let contract: Contract = Faker.fake(); let contract_id = contract.contract_context.contract_identifier.clone(); db.insert_contract(&contract_id, contract.clone()) @@ -61,31 +53,25 @@ fn get_contract() { assert_eq!(contract, retrieved_contract); } -} -#[test] -fn insert_contract_without_begin_should_fail() { - for _ in 0..1000 { + #[test] + fn insert_contract_without_begin_should_fail(contract in contract()) { let mut store = MemoryBackingStore::new(); let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - let contract: Contract = Faker.fake(); let contract_id = contract.contract_context.contract_identifier.clone(); db.insert_contract(&contract_id, contract) .expect_err("inserting contract without a begin should fail"); } -} -#[test] -fn insert_contract_with_commit_should_exist_in_backing_store() { - for _ in 0..1000 { + #[test] + fn insert_contract_with_commit_should_exist_in_backing_store(contract in contract()) { let mut store = MemoryBackingStore::new(); let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); db.begin(); - let contract: Contract = Faker.fake(); let contract_id = contract.contract_context.contract_identifier.clone(); db.insert_contract(&contract_id, contract.clone()) @@ -106,18 +92,16 @@ fn insert_contract_with_commit_should_exist_in_backing_store() { assert_eq!(1, count); } -} -#[test] -fn put_data_no_commit() { - for _ in 0..1000 { + #[test] + fn put_data_no_commit(key in any::()) { let mut store = MemoryBackingStore::new(); let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); db.begin(); db.put( - "hello", + &key, &ContractCommitment { block_height: 1, hash: Sha512Trunc256Sum::from_data(&[1, 2, 3, 4]), @@ -128,22 +112,23 @@ fn put_data_no_commit() { let count = sql_query_u32(&mut store, "SELECT COUNT(*) FROM data_table"); assert_eq!(0, count); } -} -#[test] -fn put_data_with_commit_should_exist_in_backing_store() { - for _ in 0..1000 { + #[test] + fn put_data_with_commit_should_exist_in_backing_store( + key in any::(), + block_height in any::(), + hash in sha_512_trunc_256_sum() + ) { let mut store = MemoryBackingStore::new(); let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); db.begin(); - let key = Faker.fake::(); db.put( &key, &ContractCommitment { - block_height: Faker.fake(), - hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()), + block_height, + hash, }, ) .expect("failed to put data"); @@ -156,26 +141,33 @@ fn put_data_with_commit_should_exist_in_backing_store() { ); assert_eq!(1, count); } -} -#[test] -fn put_data_without_begin_fails() { - for _ in 0..1000 { + #[test] + fn put_data_without_begin_fails( + key in any::(), + block_height in any::(), + hash in sha_512_trunc_256_sum() + ) { let mut store = MemoryBackingStore::new(); let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); - let key = Faker.fake::(); db.put( &key, &ContractCommitment { - block_height: Faker.fake(), - hash: Sha512Trunc256Sum::from_data(&Faker.fake::>()), + block_height, + hash, }, ) .expect_err("expected not-nested error"); } } + + + + + + /// Executes the provided SQL query, which is expected to return a positive /// integer, and returns it as a u32. Panics upon SQL failure. fn sql_query_u32(store: &mut S, sql: &str) -> u32 { diff --git a/clarity/src/vm/fakes.rs b/clarity/src/vm/fakes.rs deleted file mode 100644 index ab9dd2d5df..0000000000 --- a/clarity/src/vm/fakes.rs +++ /dev/null @@ -1,1408 +0,0 @@ -// Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation -// Copyright (C) 2020 Stacks Open Internet Foundation -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use fake::locales::EN; -use fake::Dummy; -use rand::Rng; -use stacks_common::types::chainstate::StacksAddress; -use stacks_common::types::Address; -use stacks_common::util::hash::Hash160; - -use self::raw::*; - -pub mod raw { - use std::collections::BTreeMap; - - use fake::locales::EN; - use fake::{Dummy, Fake, Faker}; - use rand::Rng; - use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; - - use super::ENGLISH_WORDS; - use crate::vm::callables::DefinedFunction; - use crate::vm::representations::Span; - use crate::vm::types::signatures::{CallableSubtype, FunctionArgSignature}; - use crate::vm::types::{ - ASCIIData, BuffData, BufferLength, CharType, FixedFunction, FunctionArg, FunctionSignature, - FunctionType, ListData, ListTypeData, OptionalData, ResponseData, SequenceData, - SequenceSubtype, StandardPrincipalData, StringSubtype, StringUTF8Length, TraitIdentifier, - TupleData, TupleTypeSignature, TypeSignature, UTF8Data, - }; - use crate::vm::{ClarityName, ContractName, SymbolicExpression, SymbolicExpressionType, Value}; - - const MAX_RECURSION_LEVEL: u32 = 1; - - impl Dummy for StandardPrincipalData { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - StandardPrincipalData(1, rng.gen()) - } - } - - pub struct EnglishWord(pub L); - impl Dummy> for &'static str { - fn dummy_with_rng(_: &EnglishWord, rng: &mut R) -> Self { - ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)] - } - } - - impl Dummy> for String { - fn dummy_with_rng(_: &EnglishWord, rng: &mut R) -> Self { - ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)].into() - } - } - - impl Dummy for ClarityName { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - ClarityName::from(ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)]) - } - } - - impl Dummy for ContractName { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - ContractName::from(ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)]) - } - } - - impl Dummy for UTF8Data { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - let val = Value::string_utf8_from_string_utf8_literal( - ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)].to_string(), - ) - .expect("failed to fake utf8 string literal"); - - if let Value::Sequence(SequenceData::String(CharType::UTF8(utf8_data))) = val { - utf8_data - } else { - panic!("failed to fake utf8 string literal") - } - } - } - - impl Dummy for ASCIIData { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - ASCIIData { - data: ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)] - .as_bytes() - .to_vec(), - } - } - } - - impl Dummy for DefinedFunction { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - let arg_types: Vec = (0..rng.gen_range(1..3)) - .into_iter() - .map(|_| random_type_signature(None, rng)) - .collect(); - - let arguments: Vec = (0..arg_types.len()) - .into_iter() - .map(|_| Faker.fake_with_rng(rng)) - .collect(); - - DefinedFunction { - define_type: Faker.fake_with_rng(rng), - name: Faker.fake_with_rng(rng), - arg_types, - arguments, - body: Faker.fake_with_rng(rng), - identifier: Faker.fake_with_rng(rng), - } - } - } - - impl Dummy for TypeSignature { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - random_type_signature(None, rng) - } - } - - /// Generate a random `TypeSignature` instance. - fn random_type_signature(level: Option, rng: &mut R) -> TypeSignature { - let next_level = Some(level.unwrap_or_default() + 1); - - let mut signatures = vec![ - TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII( - BufferLength(rng.gen_range(5..50)), - ))), - TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8( - StringUTF8Length(rng.gen_range(5..50)), - ))), - TypeSignature::PrincipalType, - TypeSignature::BoolType, - TypeSignature::IntType, - TypeSignature::UIntType, - TypeSignature::SequenceType(SequenceSubtype::BufferType(BufferLength( - rng.gen_range(50..100), - ))), - TypeSignature::CallableType(CallableSubtype::Principal(Faker.fake_with_rng(rng))), - TypeSignature::TraitReferenceType(TraitIdentifier { - name: Faker.fake_with_rng(rng), - contract_identifier: Faker.fake_with_rng(rng), - }), - TypeSignature::ListUnionType( - (0..rng.gen_range(1..3)) - .into_iter() - .map(|_| Faker.fake_with_rng(rng)) - .collect(), - ), - ]; - - if let Some(level) = level { - if level < MAX_RECURSION_LEVEL { - let mut recursive_signatures = vec![ - TypeSignature::SequenceType(SequenceSubtype::ListType(ListTypeData { - max_len: rng.gen_range(1..5), - entry_type: Box::new(random_type_signature(next_level, rng)), - })), - TypeSignature::OptionalType(Box::new(random_type_signature(next_level, rng))), - TypeSignature::ResponseType(Box::new(( - random_type_signature(next_level, rng), - random_type_signature(next_level, rng), - ))), - TypeSignature::TupleType(TupleTypeSignature { - type_map: (0..rng.gen_range(1..3)) - .map(|_| { - ( - Faker.fake_with_rng(rng), - random_type_signature(next_level, rng), - ) - }) - .collect(), - }), - ]; - - signatures.append(&mut recursive_signatures); - } - } - - signatures[rng.gen_range(0..signatures.len())].clone() - } - - impl Dummy for SymbolicExpressionType { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - random_symbolic_expression_type(None, rng) - } - } - - /// Generate a random `SymbolicExpressionType` instance. - fn random_symbolic_expression_type( - level: Option, - rng: &mut R, - ) -> SymbolicExpressionType { - let next_level = Some(level.unwrap_or_default() + 1); - - let mut types = vec![ - SymbolicExpressionType::Atom(Faker.fake_with_rng(rng)), - SymbolicExpressionType::LiteralValue(random_value(next_level, rng)), - ]; - - if let Some(level) = level { - if level < MAX_RECURSION_LEVEL { - let mut recursive_types = vec![SymbolicExpressionType::List( - (1..rng.gen_range(1..3)) - .into_iter() - .map(|_| Faker.fake_with_rng(rng)) - .collect(), - )]; - - types.append(&mut recursive_types); - } - } - - types[rng.gen_range(0..types.len())].clone() - } - - impl Dummy for Value { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - random_value(None, rng) - } - } - - /// Generate a random `Value` instance. - fn random_value(level: Option, rng: &mut R) -> Value { - let next_level = Some(level.unwrap_or_default() + 1); - - let mut values = vec![ - Value::Bool(Faker.fake_with_rng(rng)), - Value::Int(Faker.fake_with_rng(rng)), - Value::UInt(Faker.fake_with_rng(rng)), - Value::Principal(Faker.fake_with_rng(rng)), - Value::CallableContract(Faker.fake_with_rng(rng)), - ]; - - if let Some(lvl) = level { - if lvl < MAX_RECURSION_LEVEL { - let mut recursive_vals = vec![ - Value::Tuple(TupleData { - data_map: (0..rng.gen_range(1..3)) - .into_iter() - .map(|_| (Faker.fake_with_rng(rng), random_value(next_level, rng))) - .collect(), - type_signature: TupleTypeSignature { - type_map: (0..rng.gen_range(1..3)) - .map(|_| { - ( - Faker.fake_with_rng(rng), - random_type_signature(next_level, rng), - ) - }) - .collect(), - }, - }), - Value::Optional(OptionalData { - data: if level.is_none() { - Some(Box::new(random_value(next_level, rng))) - } else { - None - }, - }), - Value::Response(ResponseData { - committed: Faker.fake_with_rng(rng), - data: Box::new(random_value(next_level, rng)), - }), - Value::string_utf8_from_string_utf8_literal( - ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)].to_string(), - ) - .expect("failed to fake utf8 string literal"), - Value::string_ascii_from_bytes( - ENGLISH_WORDS[rng.gen_range(0..ENGLISH_WORDS.len() - 1)] - .as_bytes() - .to_vec(), - ) - .expect("failed to fake ascii string literal"), - Value::Sequence(SequenceData::List(ListData { - data: (0..rng.gen_range(1..3)) - .into_iter() - .map(|_| random_value(next_level, rng)) - .collect(), - type_signature: ListTypeData { - max_len: rng.gen_range(1..3), - entry_type: Box::new(random_type_signature(next_level, rng)), - }, - })), - Value::Sequence(SequenceData::Buffer(BuffData { - data: (10..rng.gen_range(20..40)) - .into_iter() - .map(|_| rng.gen()) - .collect(), - })), - ]; - - values.append(&mut recursive_vals); - } - } - - values[rng.gen_range(0..values.len())].clone() - } - - impl Dummy for FunctionSignature { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - FunctionSignature { - args: (0..rng.gen_range(1..3)) - .into_iter() - .map(|_| (random_type_signature(None, rng))) - .collect(), - returns: random_type_signature(None, rng), - } - } - } - - impl Dummy for FixedFunction { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - FixedFunction { - args: (0..rng.gen_range(1..3)) - .into_iter() - .map(|_| Faker.fake_with_rng(rng)) - .collect(), - returns: random_type_signature(None, rng), - } - } - } - - impl Dummy for FunctionArg { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - FunctionArg { - name: Faker.fake_with_rng(rng), - signature: random_type_signature(None, rng), - } - } - } - - impl Dummy for FunctionArgSignature { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - let sigs = vec![ - FunctionArgSignature::Union( - (0..rng.gen_range(1..2)) - .into_iter() - .map(|_| random_type_signature(None, rng)) - .collect(), - ), - FunctionArgSignature::Single(random_type_signature(None, rng)), - ]; - - sigs[rng.gen_range(0..sigs.len())].clone() - } - } - - impl Dummy for FunctionType { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - let fn_types = vec![ - FunctionType::Fixed(Faker.fake_with_rng(rng)), - FunctionType::Variadic(Faker.fake_with_rng(rng), Faker.fake_with_rng(rng)), - FunctionType::UnionArgs( - (0..rng.gen_range(1..2)) - .into_iter() - .map(|_| random_type_signature(None, rng)) - .collect(), - random_type_signature(None, rng), - ), - FunctionType::ArithmeticBinary, - FunctionType::ArithmeticUnary, - FunctionType::ArithmeticComparison, - FunctionType::ArithmeticVariadic, - FunctionType::Binary( - Faker.fake_with_rng(rng), - Faker.fake_with_rng(rng), - Faker.fake_with_rng(rng), - ), - ]; - - fn_types[rng.gen_range(0..fn_types.len())].clone() - } - } - - impl Dummy for SymbolicExpression { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - SymbolicExpression { - expr: random_symbolic_expression_type(None, rng), - id: rng.gen(), - #[cfg(feature = "developer-mode")] - end_line_comment: None, - #[cfg(feature = "developer-mode")] - span: Span::zero(), - #[cfg(feature = "developer-mode")] - post_comments: Default::default(), - #[cfg(feature = "developer-mode")] - pre_comments: Default::default(), - } - } - } -} - -/// A list of random English words which can be used when generating fake data. -const ENGLISH_WORDS: &'static [&'static str] = &[ - "glancing", - "gwaith", - "defines", - "panel", - "manitowoc", - "uspto", - "iseries", - "cations", - "create", - "harms", - "columbian", - "moonlight", - "fansite", - "pomegranate", - "lynnwood", - "finalist", - "survivor", - "veggie", - "haymarket", - "certainly", - "lubricant", - "guarded", - "challenges", - "pelican", - "heidegger", - "puccini", - "louisa", - "newsday", - "subjects", - "dances", - "mutex", - "apathy", - "rhodium", - "tumbled", - "takers", - "incline", - "screenshots", - "gangbangs", - "curled", - "orchestral", - "nerve", - "maude", - "cassettes", - "sonne", - "cried", - "shops", - "plantar", - "confirming", - "intestinal", - "nosed", - "waistband", - "prosecutor", - "newborns", - "cupcakes", - "crisis", - "travail", - "heaton", - "edgewood", - "diazepam", - "yahoogroups", - "implicit", - "endpoints", - "unequivocally", - "abilene", - "idiom", - "larynx", - "caloric", - "datagrams", - "alphabets", - "belcher", - "alright", - "assist", - "petitioned", - "mortimer", - "ruled", - "congruent", - "thankful", - "goulburn", - "reset", - "cornell", - "launchers", - "sovereignty", - "landers", - "mediums", - "limitation", - "appreciates", - "workstation", - "preparations", - "decimation", - "relocate", - "remembrance", - "discoverer", - "overriding", - "person", - "dudes", - "authenticate", - "researchers", - "native", - "northerly", - "tablatures", - "thanh", - "kiowa", - "kaplan", - "cooke", - "buckles", - "schoolgirls", - "capitalizing", - "brdrnone", - "artest", - "motorized", - "daniela", - "scrolling", - "squaretrade", - "fahrenheit", - "putters", - "runoff", - "taranaki", - "lexical", - "beginners", - "emeritus", - "artistry", - "fulfills", - "taxable", - "weakens", - "choline", - "workplace", - "sumitomo", - "glues", - "spake", - "camshaft", - "satellite", - "tougher", - "tahitian", - "withdraws", - "mistaken", - "glutamine", - "midst", - "adelaide", - "demeter", - "slightly", - "discusses", - "theatrical", - "routine", - "scare", - "awareness", - "counselors", - "vented", - "covered", - "shale", - "downstairs", - "commodores", - "dimensionname", - "brothel", - "declination", - "things", - "randy", - "suggesting", - "burdens", - "spartan", - "padre", - "adirondack", - "zacks", - "alvarez", - "neutrino", - "hessen", - "decimals", - "crafts", - "rocklin", - "suture", - "stakeholders", - "finalizing", - "fireworks", - "constructed", - "perfumed", - "sparked", - "anydvd", - "originality", - "interrupted", - "certs", - "multipliers", - "visualization", - "newlines", - "accueil", - "moment", - "leagues", - "capitalists", - "staffordshire", - "appellees", - "witches", - "alpaca", - "ahora", - "altitudes", - "stinger", - "avanti", - "catfish", - "shakur", - "trying", - "suburbia", - "maximilian", - "optometrists", - "overtime", - "domicile", - "spouses", - "hoyer", - "gracefully", - "searched", - "croupier", - "obscured", - "newsroom", - "streams", - "torrie", - "unproven", - "significantly", - "downloaden", - "heifer", - "bumble", - "wizard", - "deerfield", - "abysmal", - "shenyang", - "bunch", - "resale", - "delegation", - "indepth", - "powerseller", - "doped", - "davids", - "wilkins", - "blockbuster", - "postponed", - "pueblo", - "pence", - "blight", - "bastille", - "demanding", - "lifedrive", - "dilated", - "spheres", - "decreased", - "kagan", - "savor", - "sticky", - "homeschooling", - "teachings", - "sudanese", - "tapestry", - "statutory", - "parkersburg", - "declaration", - "concatenation", - "tacacs", - "incomparable", - "emigrants", - "ullman", - "playa", - "cardiopulmonary", - "slows", - "washes", - "rayburn", - "sagan", - "webbing", - "glass", - "kathy", - "screenings", - "stamina", - "dramas", - "jordans", - "fixings", - "alongside", - "apnea", - "choreography", - "counters", - "loire", - "silvio", - "lighters", - "disadvantage", - "kentucky", - "levine", - "hodge", - "eigen", - "buffets", - "bookseller", - "shiki", - "disqualify", - "distinctions", - "wheelers", - "dominique", - "etoile", - "inside", - "bookshelf", - "cranial", - "cessation", - "hydrographic", - "doctrinal", - "tankers", - "pickett", - "obliged", - "united", - "papua", - "darnell", - "dominica", - "apotheon", - "johnstown", - "forzieri", - "martens", - "armoured", - "mckean", - "centrifugal", - "avalanche", - "customs", - "gilmour", - "pharm", - "trajectory", - "lipoprotein", - "fomit", - "flush", - "dissatisfaction", - "facial", - "glitches", - "bookshot", - "patten", - "behaviors", - "adjacency", - "quadrangle", - "autoconf", - "countenance", - "sperm", - "jetblue", - "craven", - "genera", - "uclibc", - "optional", - "maritime", - "biloxi", - "gareth", - "camberley", - "aerodynamics", - "tomlin", - "compton", - "replicating", - "unlicensed", - "mongolia", - "shelter", - "trois", - "executable", - "danes", - "unlimited", - "nogroup", - "specificity", - "mercedes", - "oswald", - "larnaca", - "middleton", - "chatboard", - "uncovered", - "regal", - "costing", - "compasses", - "chart", - "separated", - "aligning", - "raster", - "concurrently", - "francesca", - "fittings", - "coopers", - "potters", - "technologist", - "washington", - "leiter", - "perfected", - "burying", - "strict", - "therefrom", - "freezer", - "souvenirs", - "interdependent", - "herrick", - "palais", - "brianna", - "juneau", - "edina", - "folate", - "remus", - "manilow", - "abdul", - "accepts", - "payday", - "pussycat", - "relativism", - "mandatory", - "cashing", - "kinder", - "pornos", - "stops", - "material", - "bigalow", - "plainly", - "perpetuate", - "flammability", - "astor", - "cairns", - "romance", - "mathias", - "distro", - "mackinac", - "meeks", - "multilayer", - "reproduction", - "broom", - "retailers", - "dunlop", - "blower", - "mooring", - "rhoda", - "phyto", - "bechtel", - "medalist", - "stipulate", - "restriction", - "leominster", - "regulating", - "assortment", - "complicity", - "holding", - "equinox", - "instructors", - "boland", - "ciprofloxacin", - "desoto", - "sucker", - "managment", - "guiana", - "starfleet", - "shout", - "disclosed", - "leningrad", - "useable", - "enotes", - "carpool", - "cherries", - "venous", - "hannah", - "suicides", - "toolkit", - "earnings", - "herder", - "halting", - "mehmet", - "shallow", - "astonishing", - "mollie", - "decoration", - "slowly", - "ioffer", - "messageboards", - "breaks", - "snipe", - "agencies", - "danger", - "boiler", - "jewelry", - "multiplexing", - "bianco", - "threatened", - "inhabitants", - "planar", - "brownfield", - "epinephrine", - "chopard", - "modifiers", - "pseudomonas", - "crafting", - "endpoint", - "rhododendron", - "phosphorylation", - "declared", - "artist", - "breathless", - "measures", - "limitations", - "grassley", - "cerritos", - "americana", - "premierguide", - "peruvian", - "marla", - "creatively", - "letzte", - "tabasco", - "reykjavik", - "centrist", - "liste", - "deuteronomy", - "babydoll", - "angie", - "commodity", - "morten", - "circulars", - "emperor", - "meridian", - "gecko", - "parti", - "revamp", - "convene", - "share", - "decree", - "littered", - "varieties", - "culvert", - "carta", - "contention", - "diffuser", - "philosophies", - "socialism", - "morrell", - "institutional", - "administrations", - "seize", - "macleod", - "irradiated", - "turnovr", - "federations", - "affaires", - "diameters", - "sensuous", - "madness", - "philanthropy", - "substr", - "cerruti", - "amstrad", - "gulfstream", - "transposition", - "parlour", - "fleet", - "sounded", - "beech", - "anglesey", - "regulators", - "intellectually", - "reiterated", - "stirling", - "knockout", - "allow", - "implantation", - "tingling", - "abstain", - "soundboard", - "mcalester", - "disassembly", - "catered", - "officejet", - "agreed", - "grievous", - "slated", - "octane", - "adventurers", - "thirteenth", - "molto", - "peacekeepers", - "provocative", - "tournament", - "caching", - "reasonableness", - "aneurysm", - "groundwork", - "salvatore", - "narayan", - "conventionally", - "itasca", - "techie", - "roscommon", - "jossey", - "interlude", - "kravitz", - "goings", - "parenting", - "founding", - "vegetation", - "showers", - "cities", - "chewable", - "condi", - "lookups", - "flashes", - "zydeco", - "pandas", - "ministers", - "beasty", - "inventors", - "londonderry", - "driver", - "freshest", - "jscript", - "lends", - "cowboys", - "stopping", - "doanh", - "militia", - "frankly", - "sensei", - "these", - "gandalf", - "meditation", - "spell", - "quasar", - "lugano", - "selectively", - "garnish", - "impartial", - "gilberto", - "collie", - "subcommittee", - "milestone", - "originators", - "swimwear", - "clint", - "dieser", - "profess", - "transsexual", - "myspace", - "gwendolyn", - "oppose", - "cypher", - "commit", - "flood", - "baroque", - "augustin", - "quicksearch", - "transylvania", - "roots", - "happen", - "informationhide", - "frazier", - "foreseen", - "recycle", - "electrics", - "unrelated", - "knicks", - "sedation", - "italians", - "thrive", - "rectory", - "dungeon", - "racquet", - "paraiso", - "alumnus", - "shorts", - "softening", - "uplink", - "theorists", - "cubes", - "ecampus", - "arrives", - "adipose", - "ultralight", - "barricades", - "transparencies", - "cites", - "landings", - "broderick", - "fifths", - "racking", - "graduate", - "gauteng", - "tained", - "crosby", - "coated", - "nance", - "furman", - "careerbuilder", - "magnetics", - "bleeds", - "quickest", - "peptidase", - "woody", - "amara", - "windscreen", - "greyhounds", - "mastering", - "clauses", - "atrios", - "neurology", - "proton", - "conseil", - "katja", - "offbeat", - "antagonists", - "unfpa", - "conduction", - "nieuw", - "slept", - "inositol", - "cheeses", - "akita", - "beverly", - "behaving", - "reserved", - "developmentally", - "curiosities", - "bayes", - "moorings", - "osgood", - "azres", - "veranda", - "mhonarc", - "festival", - "cartwright", - "filigree", - "helical", - "fluids", - "dorchester", - "carbine", - "shortly", - "thrusting", - "villeneuve", - "willem", - "guardia", - "cortisol", - "defibrillators", - "malta", - "marigold", - "twofold", - "assigned", - "feeble", - "gateshead", - "harcore", - "determinations", - "approximations", - "kites", - "rollins", - "mpltext", - "militaria", - "circulation", - "diabetics", - "coexistence", - "dominguez", - "ellyn", - "subcellular", - "villages", - "cautious", - "diagnosing", - "reassurance", - "diligence", - "tokyo", - "apacer", - "scratch", - "tooled", - "catagory", - "sumptuous", - "covalent", - "surgery", - "magazin", - "enjoying", - "criminal", - "preowned", - "cornwall", - "conversions", - "attire", - "masterbation", - "johnston", - "amarillo", - "lifehouse", - "applescript", - "coldwell", - "mating", - "plate", - "idyllic", - "cobalt", - "appear", - "knitting", - "alluvial", - "trainees", - "membrane", - "famous", - "overtly", - "rumble", - "multiplying", - "amour", - "mixtures", - "rubies", - "mascot", - "waits", - "calypso", - "dissociation", - "acknowledges", - "calabasas", - "selangor", - "staggering", - "horton", - "sevilla", - "zyxel", - "rebounding", - "dremel", - "ruling", - "restricts", - "salon", - "ruined", - "supermodels", - "evaluates", - "reforming", - "worden", - "undesirable", - "artista", - "englishman", - "transdermal", - "sally", - "doris", - "baits", - "reinforce", - "internets", - "readings", - "neutrons", - "donde", - "convened", - "brodie", - "mohan", - "nailing", - "normally", - "aristocrats", - "father", - "longwood", - "dreamweaver", - "bowels", - "quando", - "solves", - "expenses", - "appealing", - "knowit", - "jeeves", - "provided", - "spanking", - "caldera", - "kronos", - "hookers", - "rulemaking", - "tuscan", - "psychiatric", - "retails", - "horny", - "announcer", - "calvary", - "skaters", - "pimpin", - "cairn", - "wayne", - "shave", - "genealogy", - "titusville", - "equator", - "unicorn", - "pickabook", - "reservations", - "bottomed", - "meilleurs", - "intraday", - "hemoglobin", - "construed", - "intrusion", - "internat", - "mcmullen", - "epcot", - "iraqi", - "patrolling", - "murad", - "geographic", - "ecnext", - "toughness", - "steiner", - "musicals", - "micronesia", - "grantham", - "physicists", - "gratuit", - "inhabit", - "carter", - "shimizu", - "forcefully", - "batters", - "mcelroy", - "prefered", - "crickets", - "hatfield", - "buisness", - "deputy", - "disclosure", - "emulators", - "undertook", - "myths", - "grisham", - "lovely", - "postcards", - "blackfoot", - "knoll", - "gritty", - "suppressing", - "willard", - "slipping", - "morrisville", - "cynical", - "constitution", - "avenida", - "sociale", - "liguria", - "horrendous", - "behav", - "storefront", - "brought", - "irritability", - "neuroblastoma", - "torrent", - "bedlam", - "titled", - "topic", - "automakers", - "behemoth", - "popping", - "cobbler", - "warhead", - "emissions", - "handwritten", - "dividers", - "pooled", - "virginian", - "stays", - "psycho", - "carlos", - "mailroom", - "confirmed", - "buckley", - "materialized", - "varadero", - "mnogosearch", - "granada", - "ambiente", - "mississauga", - "grundy", - "unverified", - "exercises", - "lasagna", - "truckee", - "puppies", - "truce", - "cluster", - "kirkwood", - "bigpond", - "entail", - "scribes", - "minerals", - "vidio", - "tostring", - "tariq", - "vivian", - "foolishness", - "osborne", - "steamy", - "stonehenge", - "breathe", - "loosening", - "euchre", - "krazy", - "cyclades", - "stains", - "proponent", - "sterility", - "carmine", - "wisely", - "locations", - "migratory", - "hemisphere", - "foraging", - "tomaso", - "cured", - "playmobil", - "mania", - "treks", - "distinct", - "carded", - "ativan", - "darden", - "stunt", - "mingle", - "datasheet", - "kleine", - "hynes", - "biofuels", - "confiscated", - "blasted", - "mater", - "jayhawks", - "wanadoo", - "portions", - "holmes", - "fatty", - "cello", - "trafic", - "warfare", - "slugger", - "exiting", - "ascend", -]; diff --git a/clarity/src/vm/mod.rs b/clarity/src/vm/mod.rs index 876553df16..b5a8fe1cc8 100644 --- a/clarity/src/vm/mod.rs +++ b/clarity/src/vm/mod.rs @@ -47,9 +47,6 @@ pub mod tests; #[cfg(any(test, feature = "testing"))] pub mod test_util; -#[cfg(feature = "testing")] -pub mod fakes; - pub mod clarity; use std::collections::BTreeMap; diff --git a/clarity/src/vm/types/mod.rs b/clarity/src/vm/types/mod.rs index c5428cdea7..6a988fd59a 100644 --- a/clarity/src/vm/types/mod.rs +++ b/clarity/src/vm/types/mod.rs @@ -84,7 +84,6 @@ impl StandardPrincipalData { } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct QualifiedContractIdentifier { pub issuer: StandardPrincipalData, pub name: ContractName, @@ -131,7 +130,6 @@ impl fmt::Display for QualifiedContractIdentifier { } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum PrincipalData { Standard(StandardPrincipalData), Contract(QualifiedContractIdentifier), @@ -154,14 +152,12 @@ pub struct ResponseData { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct CallableData { pub contract_identifier: QualifiedContractIdentifier, pub trait_identifier: Option, } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub struct TraitIdentifier { pub name: ClarityName, pub contract_identifier: QualifiedContractIdentifier, diff --git a/clarity/src/vm/types/signatures.rs b/clarity/src/vm/types/signatures.rs index c1ad2bd4d5..05c8e722dc 100644 --- a/clarity/src/vm/types/signatures.rs +++ b/clarity/src/vm/types/signatures.rs @@ -151,7 +151,6 @@ pub enum StringSubtype { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum CallableSubtype { Principal(QualifiedContractIdentifier), Trait(TraitIdentifier), @@ -245,7 +244,6 @@ pub enum FunctionArgSignature { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum FunctionReturnsSignature { TypeOfArgAtPosition(usize), Fixed(TypeSignature), diff --git a/clarity/src/vm/version.rs b/clarity/src/vm/version.rs index 64d28ff961..f64d4ee878 100644 --- a/clarity/src/vm/version.rs +++ b/clarity/src/vm/version.rs @@ -6,7 +6,6 @@ use stacks_common::types::StacksEpochId; use crate::vm::errors::{Error, RuntimeErrorType}; #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, PartialOrd)] -#[cfg_attr(feature = "testing", derive(fake::Dummy))] pub enum ClarityVersion { Clarity1, Clarity2, diff --git a/stacks-common/Cargo.toml b/stacks-common/Cargo.toml index 38b1d89728..8d61e9b29a 100644 --- a/stacks-common/Cargo.toml +++ b/stacks-common/Cargo.toml @@ -33,7 +33,7 @@ chrono = "0.4.19" libc = "0.2.82" wsts = { workspace = true } hashbrown = { workspace = true } -fake = { workspace = true, optional = true } +proptest = { workspace = true, optional = true } [target.'cfg(unix)'.dependencies] nix = "0.23" @@ -78,7 +78,7 @@ stacks-common = { path = ".", features = ["testing"] } default = ["developer-mode"] developer-mode = [] slog_json = ["slog-json"] -testing = ["dep:fake"] +testing = ["dep:proptest"] [target.'cfg(all(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"), not(target_env = "msvc")))'.dependencies] sha2 = { version = "0.10", features = ["asm"] } diff --git a/stacks-common/src/libcommon.rs b/stacks-common/src/libcommon.rs index 2f7221bd59..234f4375e9 100644 --- a/stacks-common/src/libcommon.rs +++ b/stacks-common/src/libcommon.rs @@ -35,6 +35,13 @@ pub mod bitvec; use crate::types::chainstate::{BlockHeaderHash, BurnchainHeaderHash, SortitionId, StacksBlockId}; +#[cfg(any(test, feature = "testing"))] +#[macro_use] +extern crate proptest; + +#[cfg(any(test, feature = "testing"))] +pub mod proptesting; + pub mod consts { use crate::types::chainstate::{BlockHeaderHash, ConsensusHash}; diff --git a/stacks-common/src/proptesting/hashmap.rs b/stacks-common/src/proptesting/hashmap.rs new file mode 100644 index 0000000000..e277671db2 --- /dev/null +++ b/stacks-common/src/proptesting/hashmap.rs @@ -0,0 +1,99 @@ +use std::hash::Hash; + +use proptest::strategy::{statics, Strategy, ValueTree, NewTree}; +use proptest::collection::{VecStrategy, VecValueTree, SizeRange}; +use proptest::tuple::TupleValueTree; +use proptest::test_runner::TestRunner; + +use crate::types::StacksHashMap; + + +#[derive(Debug, Clone, Copy)] +struct MinSize(usize); + +#[derive(Clone, Debug)] +pub struct StacksHashMapStrategy( + statics::Filter, VecToStacksHashMap>, MinSize>, +) +where + K: Strategy, + V: Strategy, + K::Value: Hash + Eq; + +#[derive(Clone, Debug)] +pub struct StacksHashMapValueTree( + statics::Filter< + statics::Map>, VecToStacksHashMap>, + MinSize, + >, +) +where + K: ValueTree, + V: ValueTree, + K::Value: Hash + Eq; + + +impl Strategy for StacksHashMapStrategy +where + K: Strategy, + V: Strategy, + K::Value: Hash + Eq, +{ + type Tree = StacksHashMapValueTree; + type Value = StacksHashMap; + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + self.0.new_tree(runner).map(StacksHashMapValueTree) + } +} + +impl ValueTree for StacksHashMapValueTree +where + K: ValueTree, + V: ValueTree, + K::Value: Hash + Eq, +{ + type Value = StacksHashMap; + fn current(&self) -> Self::Value { + self.0.current() + } + fn simplify(&mut self) -> bool { + self.0.simplify() + } + fn complicate(&mut self) -> bool { + self.0.complicate() + } +} + +#[derive(Clone, Copy, Debug)] +struct VecToStacksHashMap; + +impl + statics::MapFn> for VecToStacksHashMap +{ + type Output = StacksHashMap; + fn apply(&self, vec: Vec<(K, V)>) -> StacksHashMap { + vec.into_iter().collect() + } +} + +pub fn stacks_hash_map( + key: K, + value: V, + size: impl Into, +) -> StacksHashMapStrategy +where + K::Value: Hash + Eq, +{ + let size = size.into(); + StacksHashMapStrategy(statics::Filter::new( + statics::Map::new(proptest::collection::vec((key, value), size.clone()), VecToStacksHashMap), + "HashMap minimum size".into(), + MinSize(size.start()), + )) +} + +impl statics::FilterFn> for MinSize { + fn apply(&self, map: &StacksHashMap) -> bool { + map.len() >= self.0 + } +} \ No newline at end of file diff --git a/stacks-common/src/proptesting/hashset.rs b/stacks-common/src/proptesting/hashset.rs new file mode 100644 index 0000000000..bfba11c64a --- /dev/null +++ b/stacks-common/src/proptesting/hashset.rs @@ -0,0 +1,89 @@ +use std::hash::Hash; + +use proptest::collection::{VecStrategy, VecValueTree, SizeRange}; +use proptest::prelude::*; +use proptest::strategy::{statics, NewTree, ValueTree}; +use proptest::test_runner::TestRunner; + +use crate::types::StacksHashSet; + +#[derive(Clone, Copy, Debug)] +struct MinSize(usize); + +#[derive(Clone, Copy, Debug)] +struct VecToStacksHashSet; + +impl statics::MapFn> + for VecToStacksHashSet +{ + type Output = StacksHashSet; + fn apply(&self, vec: Vec) -> StacksHashSet { + vec.into_iter().collect() + } +} + +#[derive(Clone, Debug)] +pub struct StacksHashSetStrategy( + statics::Filter, VecToStacksHashSet>, MinSize>, +) +where + T: Strategy, + T::Value: Hash + Eq; + +#[derive(Clone, Debug)] +pub struct StacksHashSetValueTree( + statics::Filter, VecToStacksHashSet>, MinSize>, +) +where + T: ValueTree, + T::Value: Hash + Eq; + +impl Strategy for StacksHashSetStrategy +where + T: Strategy, + T::Value: Hash + Eq, +{ + type Tree = StacksHashSetValueTree; + type Value = StacksHashSet; + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + self.0.new_tree(runner).map(StacksHashSetValueTree) + } +} + +impl ValueTree for StacksHashSetValueTree +where + T: ValueTree, + T::Value: Hash + Eq, +{ + type Value = StacksHashSet; + fn current(&self) -> Self::Value { + self.0.current() + } + fn simplify(&mut self) -> bool { + self.0.simplify() + } + fn complicate(&mut self) -> bool { + self.0.complicate() + } +} + +impl statics::FilterFn> for MinSize { + fn apply(&self, set: &StacksHashSet) -> bool { + set.len() >= self.0 + } +} + +pub fn stacks_hash_set( + element: T, + size: impl Into, +) -> StacksHashSetStrategy +where + T::Value: Hash + Eq, +{ + let size = size.into(); + StacksHashSetStrategy(statics::Filter::new( + statics::Map::new(proptest::collection::vec(element, size.clone()), VecToStacksHashSet), + "HashSet minimum size".into(), + MinSize(size.start()), + )) +} \ No newline at end of file diff --git a/stacks-common/src/proptesting/mod.rs b/stacks-common/src/proptesting/mod.rs new file mode 100644 index 0000000000..242b5b7fa2 --- /dev/null +++ b/stacks-common/src/proptesting/mod.rs @@ -0,0 +1,16 @@ +pub mod hashmap; +pub mod hashset; + +pub use hashmap::stacks_hash_map; +pub use hashset::stacks_hash_set; +use proptest::strategy::Strategy; + +use crate::util::hash::Sha512Trunc256Sum; + +pub fn sha_512_trunc_256_sum() -> impl Strategy { + (0..64u8).prop_map(|i| { + let mut arr = [0u8; 64]; + arr[i as usize] = 1; + Sha512Trunc256Sum::from_data(&arr) + }) +} \ No newline at end of file diff --git a/stacks-common/src/types/hashmap.rs b/stacks-common/src/types/hashmap.rs index 924f824fc8..ef47636f4a 100644 --- a/stacks-common/src/types/hashmap.rs +++ b/stacks-common/src/types/hashmap.rs @@ -2,8 +2,6 @@ use std::hash::Hash; use std::iter::{FromIterator, IntoIterator}; use std::ops::{Deref, DerefMut}; -#[cfg(feature = "testing")] -use fake::{Dummy, Fake, Faker}; use hashbrown::HashMap; use rand::Rng; @@ -94,19 +92,4 @@ where } map } -} - -#[cfg(feature = "testing")] -impl Dummy for StacksHashMap -where - K: Eq + Hash + Dummy, - V: Dummy, -{ - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - let mut map = HashMap::::new(); - for _ in 0..rng.gen_range(1..5) { - map.insert(Faker.fake(), Faker.fake()); - } - StacksHashMap(map) - } -} +} \ No newline at end of file diff --git a/stacks-common/src/types/hashset.rs b/stacks-common/src/types/hashset.rs index 340c21afbf..825a144041 100644 --- a/stacks-common/src/types/hashset.rs +++ b/stacks-common/src/types/hashset.rs @@ -2,8 +2,6 @@ use std::hash::Hash; use std::iter::{FromIterator, IntoIterator}; use std::ops::{Deref, DerefMut}; -#[cfg(feature = "testing")] -use fake::{Dummy, Fake, Faker}; use hashbrown::HashSet; use rand::Rng; @@ -94,19 +92,4 @@ where fn into(self) -> HashSet { self.0 } -} - -#[cfg(feature = "testing")] -impl Dummy for StacksHashSet -where - T: Dummy + Eq + Hash, -{ - fn dummy_with_rng(config: &Faker, rng: &mut R) -> Self { - let len = rng.gen_range(1..5); - let mut set = StacksHashSet::new(); - for _ in 0..len { - set.insert(T::dummy_with_rng(&config, rng)); - } - set - } -} +} \ No newline at end of file From 6f2ec6d97c0d0f75c680f132e328a2b2baa75c6c Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Wed, 6 Mar 2024 18:32:28 +0100 Subject: [PATCH 20/28] wip: fix for random usize within a range --- clarity/src/proptesting/callables.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/clarity/src/proptesting/callables.rs b/clarity/src/proptesting/callables.rs index c0b904ffd5..b64c010090 100644 --- a/clarity/src/proptesting/callables.rs +++ b/clarity/src/proptesting/callables.rs @@ -89,29 +89,28 @@ pub fn function_signature() -> impl Strategy { } pub fn defined_function() -> impl Strategy { - let x: usize = (0..3).sample_single(&mut rand::thread_rng()); - ( // identifier function_identifier(), // name clarity_name(), - // arg_types - prop::collection::vec(type_signature(), x..=x), + // arg_types + arguments, which must have the same length + (0usize..3usize).prop_flat_map(|x| ( + prop::collection::vec(type_signature(), x..=x), + prop::collection::vec(clarity_name(), x..=x) + )), // define_type define_type(), - // arguments - prop::collection::vec(clarity_name(), x..=x), // body symbolic_expression(), ) - .prop_map(|(identifier, name, arg_types, define_type, arguments, body)| + .prop_map(|(identifier, name, args, define_type, body)| DefinedFunction { identifier, name, - arg_types, + arg_types: args.0, define_type, - arguments, + arguments: args.1, body } ) From 290684aa8bda682ab5c7f00460cd5fd64627cead Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Thu, 7 Mar 2024 08:32:20 +0100 Subject: [PATCH 21/28] replace fake with proptest --- Cargo.lock | 80 +---------------- Cargo.toml | 1 - clarity/Cargo.toml | 3 +- clarity/src/proptesting/callables.rs | 18 ++++ clarity/src/proptesting/mod.rs | 5 +- clarity/src/proptesting/representations.rs | 58 +++++------- clarity/src/proptesting/types.rs | 4 +- clarity/src/proptesting/values.rs | 21 +++++ .../src/vm/database/tests/clarity_db_tests.rs | 90 +++++++++---------- stackslib/Cargo.toml | 4 +- 10 files changed, 114 insertions(+), 170 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 865027ddd1..08db258094 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -703,7 +703,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.0", + "strsim", ] [[package]] @@ -1002,41 +1002,6 @@ dependencies = [ "syn 2.0.52", ] -[[package]] -name = "darling" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 2.0.52", -] - -[[package]] -name = "darling_macro" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.52", -] - [[package]] name = "data-encoding" version = "2.5.0" @@ -1062,12 +1027,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "deunicode" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94" - [[package]] name = "digest" version = "0.8.1" @@ -1123,18 +1082,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" -[[package]] -name = "dummy" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e57e12b69e57fad516e01e2b3960f122696fdb13420e1a88ed8e210316f2876" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.52", -] - [[package]] name = "ed25519" version = "2.2.3" @@ -1252,17 +1199,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "fake" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c25829bde82205da46e1823b2259db6273379f626fc211f126f65654a2669be" -dependencies = [ - "deunicode", - "dummy", - "rand 0.8.5", -] - [[package]] name = "fallible-iterator" version = "0.2.0" @@ -1798,12 +1734,6 @@ dependencies = [ "cc", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "0.5.0" @@ -3626,7 +3556,6 @@ dependencies = [ "criterion", "curve25519-dalek 2.0.0", "ed25519-dalek", - "fake", "hashbrown 0.14.3", "integer-sqrt", "lazy_static", @@ -3658,6 +3587,7 @@ dependencies = [ "slog-json", "slog-term", "stacks-common", + "stackslib", "stdext", "stx-genesis", "tikv-jemallocator", @@ -3737,12 +3667,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index 2c054d9756..24b9f333f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,6 @@ rand = "0.8" rand_chacha = "0.3.1" tikv-jemallocator = "0.5.4" wsts = { version = "8.1", default-features = false } -fake = { version = "2.9.2", features = ["derive"] } proptest = { version = "1.4.0" } # Use a bit more than default optimization for diff --git a/clarity/Cargo.toml b/clarity/Cargo.toml index 4b4b3338ea..ed66ad1e47 100644 --- a/clarity/Cargo.toml +++ b/clarity/Cargo.toml @@ -49,7 +49,8 @@ assert-json-diff = "1.0.0" proptest = { workspace = true } clarity = { path = "./", features = ["testing"] } # This ensures that `stacks-common` is built using the `testing` feature -# when we build this crate in dev/test. +# when we build this crate in dev/test. Note that the --features flag +# doesn't need to be provideed then. stacks_common = { package = "stacks-common", path = "../stacks-common", features = ["testing"] } [features] diff --git a/clarity/src/proptesting/callables.rs b/clarity/src/proptesting/callables.rs index b64c010090..564c8b7402 100644 --- a/clarity/src/proptesting/callables.rs +++ b/clarity/src/proptesting/callables.rs @@ -6,6 +6,8 @@ use crate::vm::{callables::{DefineType, DefinedFunction, FunctionIdentifier}, da use super::*; +/// Returns a [`Strategy`] for randomly generating a [`FunctionIdentifier`] instance +/// representing a user-defined function. pub fn function_identifier_user() -> impl Strategy { ( clarity_name(), @@ -16,6 +18,8 @@ pub fn function_identifier_user() -> impl Strategy { ) } +/// Returns a [`Strategy`] for randomly generating a [`FunctionIdentifier`] instance +/// representing a native function. pub fn function_identifier_native() -> impl Strategy { ( clarity_name() @@ -25,6 +29,8 @@ pub fn function_identifier_native() -> impl Strategy ) } +/// Returns a [`Strategy`] for randomly generating a [`FunctionIdentifier`] +/// instance representing a function of any kind, user-defined or native. pub fn function_identifier() -> impl Strategy { prop_oneof![ function_identifier_user(), @@ -32,6 +38,7 @@ pub fn function_identifier() -> impl Strategy { ] } +/// Returns a [`Strategy`] for randomly generating a [`DefineType`] variant. pub fn define_type() -> impl Strategy { prop_oneof![ Just(DefineType::Public), @@ -40,6 +47,8 @@ pub fn define_type() -> impl Strategy { ] } +/// Returns a [`Strategy`] for randomly generating a [`DataVariableMetadata`] +/// instance. pub fn data_variable_metadata() -> impl Strategy { type_signature() .prop_map(|value_type| @@ -48,6 +57,7 @@ pub fn data_variable_metadata() -> impl Strategy { } +/// Returns a [`Strategy`] for randomly generating a [`DataMapMetadata`] instance. pub fn data_map_metadata() -> impl Strategy { ( type_signature(), @@ -61,18 +71,24 @@ pub fn data_map_metadata() -> impl Strategy { ) } +/// Returns a [`Strategy`] for randomly generating a [`NonFungibleTokenMetadata`] +/// instance. pub fn nft_metadata() -> impl Strategy { type_signature().prop_map(|key_type| NonFungibleTokenMetadata { key_type } ) } +/// Returns a [`Strategy`] for randomly generating a [`FungibleTokenMetadata`] +/// instance. pub fn ft_metadata() -> impl Strategy { any::>().prop_map(|total_supply| FungibleTokenMetadata { total_supply } ) } +/// Returns a [`Strategy`] for randomly generating a [`FunctionSignature`] +/// instance. pub fn function_signature() -> impl Strategy { ( // arg_types @@ -88,6 +104,8 @@ pub fn function_signature() -> impl Strategy { ) } +/// Returns a [`Strategy`] for randomly generating a [`DefinedFunction`] +/// instance. pub fn defined_function() -> impl Strategy { ( // identifier diff --git a/clarity/src/proptesting/mod.rs b/clarity/src/proptesting/mod.rs index 1ffba30e24..492fa2b288 100644 --- a/clarity/src/proptesting/mod.rs +++ b/clarity/src/proptesting/mod.rs @@ -14,7 +14,10 @@ pub use callables::*; pub use representations::*; pub use contracts::*; -pub fn clarity_version() -> impl Strategy { +use crate::vm::ClarityVersion; + +/// Returns a [`Strategy`] for randomly generating a [`ClarityVersion`] instance. +pub fn clarity_version() -> impl Strategy { prop_oneof![ Just(crate::vm::ClarityVersion::Clarity1), Just(crate::vm::ClarityVersion::Clarity2), diff --git a/clarity/src/proptesting/representations.rs b/clarity/src/proptesting/representations.rs index b9db8f8c7f..3db1d18226 100644 --- a/clarity/src/proptesting/representations.rs +++ b/clarity/src/proptesting/representations.rs @@ -4,14 +4,17 @@ use crate::vm::{representations::{Span, TraitDefinition}, ClarityName, ContractN use super::*; +/// Returns a [`Strategy`] for randomly generating a [`ClarityName`]. pub fn clarity_name() -> impl Strategy { "[a-z]{40}".prop_map(|s| s.try_into().unwrap()) } +/// Returns a [`Strategy`] for randomly generating a [`ContractName`]. pub fn contract_name() -> impl Strategy { "[a-zA-Z]{1,40}".prop_map(|s| s.try_into().unwrap()) } +/// Returns a [`Strategy`] for randomly generating a [`TraitDefinition`]. pub fn trait_definition() -> impl Strategy { prop_oneof![ trait_identifier().prop_map(TraitDefinition::Defined), @@ -19,43 +22,24 @@ pub fn trait_definition() -> impl Strategy { ] } +/// Returns a [`Strategy`] for randomly generating a [`SymbolicExpression`]. pub fn symbolic_expression() -> impl Strategy { - ( - symbolic_expression_type(), - 0u64..u64::MAX, - Just(Span::zero()), - Just(Vec::<(String, Span)>::new()), - Just(None::), - Just(Vec::<(String, Span)>::new()), - ) - .prop_map(|(expr, id, span, pre_comments, end_line_comment, post_comments)| - SymbolicExpression { - expr, - id, - #[cfg(feature = "developer-mode")] - span, - #[cfg(feature = "developer-mode")] - pre_comments, - #[cfg(feature = "developer-mode")] - end_line_comment, - #[cfg(feature = "developer-mode")] - post_comments, - } - ) -} - -pub fn symbolic_expression_type() -> impl Strategy { - prop_oneof![ - // Atom - clarity_name().prop_map(SymbolicExpressionType::Atom), - // AtomValue - PropValue::any().prop_map(|val| SymbolicExpressionType::AtomValue(val.into())), - // LiteralValue - PropValue::any().prop_map(|val| SymbolicExpressionType::LiteralValue(val.into())), - // Field - trait_identifier().prop_map(SymbolicExpressionType::Field), - // TraitReference + let leaf = prop_oneof![ + clarity_name().prop_map(|name| SymbolicExpression::atom(name)), + PropValue::any().prop_map(|val| SymbolicExpression::atom_value(val.into())), + PropValue::any().prop_map(|val| SymbolicExpression::literal_value(val.into())), + trait_identifier().prop_map(|name| SymbolicExpression::field(name)), (clarity_name(), trait_definition()) - .prop_map(|(n, t)| SymbolicExpressionType::TraitReference(n, t)), - ] + .prop_map(|(n, t)| SymbolicExpression::trait_reference(n, t)), + ]; + + leaf.prop_recursive( + 3, + 64, + 5, + |inner| + prop::collection::vec(inner, 1..3) + .prop_map(|list| + SymbolicExpression::list(list.into_boxed_slice())) + ) } \ No newline at end of file diff --git a/clarity/src/proptesting/types.rs b/clarity/src/proptesting/types.rs index 66c4ec2824..12adc8e7b1 100644 --- a/clarity/src/proptesting/types.rs +++ b/clarity/src/proptesting/types.rs @@ -68,7 +68,7 @@ pub fn type_signature() -> impl Strategy { ))) ]; - leaf.prop_recursive(5, 64, 10, |inner| prop_oneof![ + leaf.prop_recursive(3, 32, 5, |inner| prop_oneof![ // optional type: 10% NoType + 90% any other type prop_oneof![ 1 => Just(TypeSignature::NoType), @@ -89,7 +89,7 @@ pub fn type_signature() -> impl Strategy { ) .prop_map(|btree| TypeSignature::TupleType(btree.try_into().unwrap())), // list type - (8u32..32, inner.clone()).prop_map(|(s, ty)| (ListTypeData::new_list(ty, s).unwrap()).into()), + (1u32..8, inner.clone()).prop_map(|(s, ty)| (ListTypeData::new_list(ty, s).unwrap()).into()), ]) } diff --git a/clarity/src/proptesting/values.rs b/clarity/src/proptesting/values.rs index 2b92052114..da5e9d23e1 100644 --- a/clarity/src/proptesting/values.rs +++ b/clarity/src/proptesting/values.rs @@ -4,6 +4,8 @@ use crate::vm::{types::{BuffData, CharType, ListData, ListTypeData, OptionalData use super::*; +/// Returns a [`Strategy`] for generating a randomized [`Value`] instance of a +/// the specified ([`TypeSignature`]). pub fn value(ty: TypeSignature) -> impl Strategy { match ty { TypeSignature::NoType => unreachable!(), @@ -35,18 +37,26 @@ pub fn value(ty: TypeSignature) -> impl Strategy { } } +/// Returns a [`Strategy`] for generating a randomized [`Value`] instance of variant +/// [`Value::Int`]. pub fn int() -> impl Strategy { any::().prop_map(Value::Int) } +/// Returns a [`Strategy`] for generating a randomized [`Value`] instance of variant +/// [`Value::UInt`]. pub fn uint() -> impl Strategy { any::().prop_map(Value::UInt) } +/// Returns a [`Strategy`] for generating a randomized [`Value`] instance of variant +/// [`Value::Bool`]. pub fn bool() -> impl Strategy { any::().prop_map(Value::Bool) } +/// Returns a [`Strategy`] for generating a randomized [`Value`] instance of variant +/// [`Value::None`]. pub fn string_ascii(size: u32) -> impl Strategy { let size = size as usize; prop::collection::vec(0x20u8..0x7e, size..=size).prop_map(|bytes| { @@ -56,6 +66,8 @@ pub fn string_ascii(size: u32) -> impl Strategy { }) } +/// Returns a [`Strategy`] for generating a randomized [`Value`] instance of variant +/// [`Value::Sequence`] with an inner type of [`UTF8Data`]. pub fn string_utf8(size: u32) -> impl Strategy { prop::collection::vec(any::(), size as usize).prop_map(|chars| { let mut data = Vec::with_capacity(chars.len()); @@ -68,12 +80,16 @@ pub fn string_utf8(size: u32) -> impl Strategy { }) } +/// Returns a [`Strategy`] for generating a randomized [`Value`] instance of variant +/// [`Value::Sequence`] with an inner type of [`BuffData`]. pub fn buffer(size: u32) -> impl Strategy { let size = size as usize; prop::collection::vec(any::(), size..=size) .prop_map(|bytes| Value::Sequence(SequenceData::Buffer(BuffData { data: bytes }))) } +/// Returns a [`Strategy`] for generating a randomized [`Value`] instance of variant +/// [`Value::Optional`], with the inner type being the specified [`TypeSignature`]. pub fn optional(inner_ty: TypeSignature) -> impl Strategy { match inner_ty { TypeSignature::NoType => Just(Value::none()).boxed(), @@ -87,6 +103,8 @@ pub fn optional(inner_ty: TypeSignature) -> impl Strategy { } } +/// Returns a [`Strategy`] for generating a randomized [`Value`] instance of variant +/// [`Value::Response`], with the ok/err types being the specified [`TypeSignature`]s. pub fn response(ok_ty: TypeSignature, err_ty: TypeSignature) -> impl Strategy { match (ok_ty, err_ty) { (TypeSignature::NoType, err_ty) => value(err_ty) @@ -116,6 +134,9 @@ pub fn response(ok_ty: TypeSignature, err_ty: TypeSignature) -> impl Strategy impl Strategy { prop::collection::vec( value(list_type_data.get_list_item_type().clone()), diff --git a/clarity/src/vm/database/tests/clarity_db_tests.rs b/clarity/src/vm/database/tests/clarity_db_tests.rs index 3855b06672..47563313ef 100644 --- a/clarity/src/vm/database/tests/clarity_db_tests.rs +++ b/clarity/src/vm/database/tests/clarity_db_tests.rs @@ -25,13 +25,7 @@ proptest! { db.insert_contract(&contract_id, contract) .expect("failed to insert contract into backing store"); - let exists = sql_exists( - &mut store, - &format!( - "SELECT * FROM metadata_table WHERE key LIKE '%{}%'", - contract_id.to_string() - ), - ); + let exists = sql_metadata_table_key_count(&mut store, &contract_id.to_string()) > 0; assert!(!exists); } @@ -79,22 +73,22 @@ proptest! { db.commit().expect("failed to commit to backing store"); - let count = sql_query_u32( - &mut store, - &format!( - "SELECT COUNT(*) FROM metadata_table WHERE key LIKE '{}'", - format!( - "clr-meta::{}::vm-metadata::9::contract", - contract_id.to_string() - ) - ), + let contract_key = format!( + "clr-meta::{}::vm-metadata::9::contract", + contract_id.to_string() ); + let count = sql_metadata_table_key_count(&mut store, &contract_key); + assert_eq!(1, count); } #[test] - fn put_data_no_commit(key in any::()) { + fn put_data_no_commit( + key in any::(), + block_height in any::(), + hash in sha_512_trunc_256_sum() + ) { let mut store = MemoryBackingStore::new(); let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); @@ -103,13 +97,13 @@ proptest! { db.put( &key, &ContractCommitment { - block_height: 1, - hash: Sha512Trunc256Sum::from_data(&[1, 2, 3, 4]), + block_height, + hash, }, ) .expect("failed to put data"); - let count = sql_query_u32(&mut store, "SELECT COUNT(*) FROM data_table"); + let count = sql_data_table_key_count(&mut store, &key.to_string()); assert_eq!(0, count); } @@ -135,10 +129,7 @@ proptest! { db.commit().expect("failed to commit to backing store"); - let count = sql_query_u32( - &mut store, - &format!("SELECT COUNT(*) FROM data_table where key = '{}'", key), - ); + let count = sql_data_table_key_count(&mut store, &key.to_string()); assert_eq!(1, count); } @@ -164,31 +155,34 @@ proptest! { - - - - -/// Executes the provided SQL query, which is expected to return a positive -/// integer, and returns it as a u32. Panics upon SQL failure. -fn sql_query_u32(store: &mut S, sql: &str) -> u32 { +/// Returns the number of rows in the metadata table for the provided key. +fn sql_metadata_table_key_count(store: &mut S, key: &str) -> u32 { let sqlite = store.get_side_store(); - sqlite - .query_row(sql, NO_PARAMS, |row| { - let i: u32 = row.get(0)?; - Ok(i) - }) - .expect("failed to verify results in sqlite") + let count = sqlite + .query_row( + "SELECT COUNT(*) FROM metadata_table WHERE key = ?1;", + &[key], + |row| { + let i: u32 = row.get(0)?; + Ok(i) + }, + ) + .expect("failed to verify results in sqlite"); + count } -/// Executes the provided SQL query as a subquery within a `SELECT EXISTS(...)` -/// statement. Returns true if the statement returns any rows, false otherwise. -/// Panics upon SQL failure. -fn sql_exists(store: &mut S, sql: &str) -> bool { +/// Returns the number of rows in the `data_table` with the given key. +fn sql_data_table_key_count(store: &mut S, key: &str) -> u32 { let sqlite = store.get_side_store(); - sqlite - .query_row(&format!("SELECT EXISTS({});", sql), NO_PARAMS, |row| { - let exists: bool = row.get(0)?; - Ok(exists) - }) - .expect("failed to verify results in sqlite") -} + let count = sqlite + .query_row( + "SELECT COUNT(*) FROM data_table WHERE key = ?1;", + &[key], + |row| { + let i: u32 = row.get(0)?; + Ok(i) + }, + ) + .expect("failed to verify results in sqlite"); + count +} \ No newline at end of file diff --git a/stackslib/Cargo.toml b/stackslib/Cargo.toml index e3a20d11a2..438118db69 100644 --- a/stackslib/Cargo.toml +++ b/stackslib/Cargo.toml @@ -58,7 +58,6 @@ libstackerdb = { path = "../libstackerdb" } siphasher = "0.3.7" wsts = { workspace = true } hashbrown = { workspace = true } -fake = { workspace = true, optional = true } [target.'cfg(not(target_env = "msvc"))'.dependencies] tikv-jemallocator = {workspace = true} @@ -96,6 +95,7 @@ version = "0.2.23" features = ["std"] [dev-dependencies] +stackslib = { path = ".", features = ["testing"] } assert-json-diff = "1.0.0" criterion = "0.3.5" stdext = "0.3.1" @@ -113,7 +113,7 @@ disable-costs = [] developer-mode = ["clarity/developer-mode"] monitoring_prom = ["prometheus"] slog_json = ["slog-json", "stacks-common/slog_json", "clarity/slog_json", "pox-locking/slog_json"] -testing = ["dep:fake"] +testing = ["stacks-common/testing", "clarity/testing"] [target.'cfg(all(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"), not(target_env = "msvc")))'.dependencies] sha2 = { version = "0.10", features = ["asm"] } From fce54d6535a1f7480c92b31a47cf056481e8c8b1 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Thu, 7 Mar 2024 08:41:52 +0100 Subject: [PATCH 22/28] chore: cargo fmt-stacks --- clarity/src/proptesting/callables.rs | 103 ++++++---------- clarity/src/proptesting/contracts.rs | 116 +++++++----------- clarity/src/proptesting/mod.rs | 18 +-- clarity/src/proptesting/representations.rs | 19 ++- clarity/src/proptesting/types.rs | 47 +++---- clarity/src/proptesting/values.rs | 12 +- .../src/vm/database/tests/clarity_db_tests.rs | 10 +- stacks-common/src/proptesting/hashmap.rs | 19 +-- stacks-common/src/proptesting/hashset.rs | 13 +- stacks-common/src/proptesting/mod.rs | 2 +- stacks-common/src/types/hashmap.rs | 2 +- stacks-common/src/types/hashset.rs | 2 +- 12 files changed, 147 insertions(+), 216 deletions(-) diff --git a/clarity/src/proptesting/callables.rs b/clarity/src/proptesting/callables.rs index 564c8b7402..52327ff0bd 100644 --- a/clarity/src/proptesting/callables.rs +++ b/clarity/src/proptesting/callables.rs @@ -2,40 +2,32 @@ use proptest::prelude::*; use rand::distributions::uniform::SampleRange; use serde::de::value; -use crate::vm::{callables::{DefineType, DefinedFunction, FunctionIdentifier}, database::{DataMapMetadata, DataVariableMetadata, FungibleTokenMetadata, NonFungibleTokenMetadata}, representations::TraitDefinition, types::FunctionSignature}; - use super::*; +use crate::vm::callables::{DefineType, DefinedFunction, FunctionIdentifier}; +use crate::vm::database::{ + DataMapMetadata, DataVariableMetadata, FungibleTokenMetadata, NonFungibleTokenMetadata, +}; +use crate::vm::representations::TraitDefinition; +use crate::vm::types::FunctionSignature; /// Returns a [`Strategy`] for randomly generating a [`FunctionIdentifier`] instance /// representing a user-defined function. pub fn function_identifier_user() -> impl Strategy { - ( - clarity_name(), - clarity_name() - ) - .prop_map(|(name, context)| + (clarity_name(), clarity_name()).prop_map(|(name, context)| { FunctionIdentifier::new_user_function(&context.to_string(), &name.to_string()) - ) + }) } /// Returns a [`Strategy`] for randomly generating a [`FunctionIdentifier`] instance /// representing a native function. pub fn function_identifier_native() -> impl Strategy { - ( - clarity_name() - ) - .prop_map(|name| - FunctionIdentifier::new_native_function(&name.to_string()) - ) + (clarity_name()).prop_map(|name| FunctionIdentifier::new_native_function(&name.to_string())) } /// Returns a [`Strategy`] for randomly generating a [`FunctionIdentifier`] /// instance representing a function of any kind, user-defined or native. pub fn function_identifier() -> impl Strategy { - prop_oneof![ - function_identifier_user(), - function_identifier_native() - ] + prop_oneof![function_identifier_user(), function_identifier_native()] } /// Returns a [`Strategy`] for randomly generating a [`DefineType`] variant. @@ -50,58 +42,39 @@ pub fn define_type() -> impl Strategy { /// Returns a [`Strategy`] for randomly generating a [`DataVariableMetadata`] /// instance. pub fn data_variable_metadata() -> impl Strategy { - type_signature() - .prop_map(|value_type| - DataVariableMetadata { value_type } - ) - + type_signature().prop_map(|value_type| DataVariableMetadata { value_type }) } /// Returns a [`Strategy`] for randomly generating a [`DataMapMetadata`] instance. pub fn data_map_metadata() -> impl Strategy { - ( - type_signature(), - type_signature() - ) - .prop_map(|(key_type, value_type)| - DataMapMetadata { - key_type, - value_type - } - ) + (type_signature(), type_signature()).prop_map(|(key_type, value_type)| DataMapMetadata { + key_type, + value_type, + }) } -/// Returns a [`Strategy`] for randomly generating a [`NonFungibleTokenMetadata`] +/// Returns a [`Strategy`] for randomly generating a [`NonFungibleTokenMetadata`] /// instance. pub fn nft_metadata() -> impl Strategy { - type_signature().prop_map(|key_type| - NonFungibleTokenMetadata { key_type } - ) + type_signature().prop_map(|key_type| NonFungibleTokenMetadata { key_type }) } -/// Returns a [`Strategy`] for randomly generating a [`FungibleTokenMetadata`] +/// Returns a [`Strategy`] for randomly generating a [`FungibleTokenMetadata`] /// instance. pub fn ft_metadata() -> impl Strategy { - any::>().prop_map(|total_supply| - FungibleTokenMetadata { total_supply } - ) + any::>().prop_map(|total_supply| FungibleTokenMetadata { total_supply }) } -/// Returns a [`Strategy`] for randomly generating a [`FunctionSignature`] +/// Returns a [`Strategy`] for randomly generating a [`FunctionSignature`] /// instance. pub fn function_signature() -> impl Strategy { ( // arg_types prop::collection::vec(type_signature(), 0..3), // return_type - type_signature() - ) - .prop_map(|(args, returns)| - FunctionSignature { - args, - returns - } + type_signature(), ) + .prop_map(|(args, returns)| FunctionSignature { args, returns }) } /// Returns a [`Strategy`] for randomly generating a [`DefinedFunction`] @@ -113,23 +86,25 @@ pub fn defined_function() -> impl Strategy { // name clarity_name(), // arg_types + arguments, which must have the same length - (0usize..3usize).prop_flat_map(|x| ( - prop::collection::vec(type_signature(), x..=x), - prop::collection::vec(clarity_name(), x..=x) - )), + (0usize..3usize).prop_flat_map(|x| { + ( + prop::collection::vec(type_signature(), x..=x), + prop::collection::vec(clarity_name(), x..=x), + ) + }), // define_type define_type(), // body symbolic_expression(), ) - .prop_map(|(identifier, name, args, define_type, body)| - DefinedFunction { - identifier, - name, - arg_types: args.0, - define_type, - arguments: args.1, - body - } - ) -} \ No newline at end of file + .prop_map( + |(identifier, name, args, define_type, body)| DefinedFunction { + identifier, + name, + arg_types: args.0, + define_type, + arguments: args.1, + body, + }, + ) +} diff --git a/clarity/src/proptesting/contracts.rs b/clarity/src/proptesting/contracts.rs index 69d241d64d..c11bc360d2 100644 --- a/clarity/src/proptesting/contracts.rs +++ b/clarity/src/proptesting/contracts.rs @@ -2,11 +2,11 @@ use proptest::collection::btree_map; use proptest::prelude::*; use stacks_common::proptesting::*; -use crate::vm::contracts::Contract; -use crate::vm::{types::PrincipalData, ClarityVersion, ContractContext, Value}; -use crate::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; - use super::*; +use crate::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; +use crate::vm::contracts::Contract; +use crate::vm::types::PrincipalData; +use crate::vm::{ClarityVersion, ContractContext, Value}; pub fn contract_context(clarity_version: ClarityVersion) -> impl Strategy { ( @@ -16,91 +16,63 @@ pub fn contract_context(clarity_version: ClarityVersion) -> impl Strategy unreachable!(), }), // variables - prop::collection::vec( - (clarity_name(), PropValue::any().prop_map_into()), - 0..8 - ).prop_map(|v| - HashMap(v.into_iter().collect() - ) - ), + prop::collection::vec((clarity_name(), PropValue::any().prop_map_into()), 0..8) + .prop_map(|v| HashMap(v.into_iter().collect())), // functions - stacks_hash_map( - clarity_name(), - defined_function(), 1..5 - ), + stacks_hash_map(clarity_name(), defined_function(), 1..5), // defined_traits stacks_hash_map( - clarity_name(), - btree_map( - clarity_name(), - function_signature(), - 1..5), - 1..5 + clarity_name(), + btree_map(clarity_name(), function_signature(), 1..5), + 1..5, ), // implemented_traits stacks_hash_set(trait_identifier(), 0..3), // persisted_names stacks_hash_set(clarity_name(), 0..5), // meta_data_map - stacks_hash_map( - clarity_name(), - data_map_metadata(), - 1..5 - ), + stacks_hash_map(clarity_name(), data_map_metadata(), 1..5), // meta_data_var - stacks_hash_map( - clarity_name(), - data_variable_metadata(), - 1..5 - ), + stacks_hash_map(clarity_name(), data_variable_metadata(), 1..5), // meta_nft - stacks_hash_map( - clarity_name(), - nft_metadata(), - 1..5 - ), + stacks_hash_map(clarity_name(), nft_metadata(), 1..5), // meta_ft - stacks_hash_map( - clarity_name(), - ft_metadata(), - 1..5 - ), + stacks_hash_map(clarity_name(), ft_metadata(), 1..5), // data_size 0u64..64, ) - .prop_map( - move |( - contract_identifier, - variables, - functions, - defined_traits, - implemented_traits, - persisted_names, - meta_data_map, - meta_data_var, - meta_nft, - meta_ft, - data_size, - )| { - let mut cc = ContractContext::new(contract_identifier, clarity_version); - cc.variables = variables; - cc.functions = functions; - cc.defined_traits = defined_traits; - cc.implemented_traits = implemented_traits; - cc.persisted_names = persisted_names; - cc.meta_data_map = meta_data_map; - cc.meta_data_var = meta_data_var; - cc.meta_nft = meta_nft; - cc.meta_ft = meta_ft; - cc.data_size = data_size; - cc - }, - ) + .prop_map( + move |( + contract_identifier, + variables, + functions, + defined_traits, + implemented_traits, + persisted_names, + meta_data_map, + meta_data_var, + meta_nft, + meta_ft, + data_size, + )| { + let mut cc = ContractContext::new(contract_identifier, clarity_version); + cc.variables = variables; + cc.functions = functions; + cc.defined_traits = defined_traits; + cc.implemented_traits = implemented_traits; + cc.persisted_names = persisted_names; + cc.meta_data_map = meta_data_map; + cc.meta_data_var = meta_data_var; + cc.meta_nft = meta_nft; + cc.meta_ft = meta_ft; + cc.data_size = data_size; + cc + }, + ) } pub fn contract() -> impl Strategy { clarity_version() .prop_flat_map(contract_context) - .prop_map(|contract_context| - Contract { contract_context }) -} \ No newline at end of file + .prop_map(|contract_context| Contract { contract_context }) +} diff --git a/clarity/src/proptesting/mod.rs b/clarity/src/proptesting/mod.rs index 492fa2b288..05ca0c58a8 100644 --- a/clarity/src/proptesting/mod.rs +++ b/clarity/src/proptesting/mod.rs @@ -1,18 +1,20 @@ -use proptest::{prop_oneof, strategy::{Just, Strategy, ValueTree}, test_runner::{Config, RngAlgorithm, TestRng, TestRunner}}; +use proptest::prop_oneof; +use proptest::strategy::{Just, Strategy, ValueTree}; +use proptest::test_runner::{Config, RngAlgorithm, TestRng, TestRunner}; use rand::Rng; use stacks_common::types::StacksHashMap as HashMap; -pub mod types; -pub mod values; pub mod callables; -pub mod representations; pub mod contracts; +pub mod representations; +pub mod types; +pub mod values; -pub use types::*; -pub use values::*; pub use callables::*; -pub use representations::*; pub use contracts::*; +pub use representations::*; +pub use types::*; +pub use values::*; use crate::vm::ClarityVersion; @@ -22,4 +24,4 @@ pub fn clarity_version() -> impl Strategy { Just(crate::vm::ClarityVersion::Clarity1), Just(crate::vm::ClarityVersion::Clarity2), ] -} \ No newline at end of file +} diff --git a/clarity/src/proptesting/representations.rs b/clarity/src/proptesting/representations.rs index 3db1d18226..27173f6247 100644 --- a/clarity/src/proptesting/representations.rs +++ b/clarity/src/proptesting/representations.rs @@ -1,8 +1,8 @@ use proptest::prelude::*; -use crate::vm::{representations::{Span, TraitDefinition}, ClarityName, ContractName, SymbolicExpression, SymbolicExpressionType}; - use super::*; +use crate::vm::representations::{Span, TraitDefinition}; +use crate::vm::{ClarityName, ContractName, SymbolicExpression, SymbolicExpressionType}; /// Returns a [`Strategy`] for randomly generating a [`ClarityName`]. pub fn clarity_name() -> impl Strategy { @@ -33,13 +33,8 @@ pub fn symbolic_expression() -> impl Strategy { .prop_map(|(n, t)| SymbolicExpression::trait_reference(n, t)), ]; - leaf.prop_recursive( - 3, - 64, - 5, - |inner| - prop::collection::vec(inner, 1..3) - .prop_map(|list| - SymbolicExpression::list(list.into_boxed_slice())) - ) -} \ No newline at end of file + leaf.prop_recursive(3, 64, 5, |inner| { + prop::collection::vec(inner, 1..3) + .prop_map(|list| SymbolicExpression::list(list.into_boxed_slice())) + }) +} diff --git a/clarity/src/proptesting/types.rs b/clarity/src/proptesting/types.rs index 12adc8e7b1..96f7280ce5 100644 --- a/clarity/src/proptesting/types.rs +++ b/clarity/src/proptesting/types.rs @@ -1,54 +1,38 @@ use proptest::prelude::*; use proptest::string::string_regex; +use super::*; use crate::types::{StacksHashMap, StacksHashSet}; +use crate::vm::callables::{DefineType, DefinedFunction, FunctionIdentifier}; use crate::vm::contracts::Contract; +use crate::vm::representations::{ + Span, SymbolicExpression, SymbolicExpressionType, TraitDefinition, +}; use crate::vm::types::{ ASCIIData, BuffData, CharType, ListData, ListTypeData, OptionalData, PrincipalData, QualifiedContractIdentifier, ResponseData, SequenceData, SequenceSubtype, - StandardPrincipalData, StringSubtype, StringUTF8Length, TupleData, TupleTypeSignature, - TypeSignature, UTF8Data, Value, MAX_VALUE_SIZE, TraitIdentifier + StandardPrincipalData, StringSubtype, StringUTF8Length, TraitIdentifier, TupleData, + TupleTypeSignature, TypeSignature, UTF8Data, Value, MAX_VALUE_SIZE, }; -use crate::vm::callables::{DefinedFunction, FunctionIdentifier, DefineType}; use crate::vm::{ClarityName, ClarityVersion, ContractContext, ContractName}; -use crate::vm::representations::{Span, SymbolicExpression, SymbolicExpressionType, TraitDefinition}; - -use super::*; pub fn standard_principal_data() -> impl Strategy { - ( - 0u8..32, - prop::collection::vec(any::(), 20) - ) - .prop_map(|(v, hash)| - StandardPrincipalData(v, hash.try_into().unwrap()) - ) + (0u8..32, prop::collection::vec(any::(), 20)) + .prop_map(|(v, hash)| StandardPrincipalData(v, hash.try_into().unwrap())) } pub fn qualified_contract_identifier() -> impl Strategy { - ( - standard_principal_data(), - contract_name() - ) - .prop_map(|(issuer, name)| - QualifiedContractIdentifier { - issuer, - name - } - ) + (standard_principal_data(), contract_name()) + .prop_map(|(issuer, name)| QualifiedContractIdentifier { issuer, name }) } pub fn trait_identifier() -> impl Strategy { - ( - clarity_name(), - qualified_contract_identifier() - ) - .prop_map(|(name, contract_identifier)| + (clarity_name(), qualified_contract_identifier()).prop_map(|(name, contract_identifier)| { TraitIdentifier { name, - contract_identifier + contract_identifier, } - ) + }) } pub fn type_signature() -> impl Strategy { @@ -67,7 +51,7 @@ pub fn type_signature() -> impl Strategy { StringSubtype::UTF8(s.try_into().unwrap()) ))) ]; - + leaf.prop_recursive(3, 32, 5, |inner| prop_oneof![ // optional type: 10% NoType + 90% any other type prop_oneof![ @@ -92,4 +76,3 @@ pub fn type_signature() -> impl Strategy { (1u32..8, inner.clone()).prop_map(|(s, ty)| (ListTypeData::new_list(ty, s).unwrap()).into()), ]) } - diff --git a/clarity/src/proptesting/values.rs b/clarity/src/proptesting/values.rs index da5e9d23e1..7131262ae8 100644 --- a/clarity/src/proptesting/values.rs +++ b/clarity/src/proptesting/values.rs @@ -1,8 +1,12 @@ use proptest::prelude::*; -use crate::vm::{types::{BuffData, CharType, ListData, ListTypeData, OptionalData, PrincipalData, QualifiedContractIdentifier, ResponseData, SequenceData, SequenceSubtype, StandardPrincipalData, StringSubtype, TupleData, TupleTypeSignature, TypeSignature, UTF8Data}, ContractName, Value}; - use super::*; +use crate::vm::types::{ + BuffData, CharType, ListData, ListTypeData, OptionalData, PrincipalData, + QualifiedContractIdentifier, ResponseData, SequenceData, SequenceSubtype, + StandardPrincipalData, StringSubtype, TupleData, TupleTypeSignature, TypeSignature, UTF8Data, +}; +use crate::vm::{ContractName, Value}; /// Returns a [`Strategy`] for generating a randomized [`Value`] instance of a /// the specified ([`TypeSignature`]). @@ -135,7 +139,7 @@ pub fn response(ok_ty: TypeSignature, err_ty: TypeSignature) -> impl Strategy impl Strategy { prop::collection::vec( @@ -248,4 +252,4 @@ impl TryFrom> for PropValue { let values = values.into_iter().map(Value::from).collect(); Value::cons_list_unsanitized(values).map(PropValue::from) } -} \ No newline at end of file +} diff --git a/clarity/src/vm/database/tests/clarity_db_tests.rs b/clarity/src/vm/database/tests/clarity_db_tests.rs index 47563313ef..bc3c833c08 100644 --- a/clarity/src/vm/database/tests/clarity_db_tests.rs +++ b/clarity/src/vm/database/tests/clarity_db_tests.rs @@ -1,9 +1,9 @@ +use proptest::prelude::*; use rusqlite::NO_PARAMS; use stacks_common::proptesting::sha_512_trunc_256_sum; use stacks_common::util::hash::Sha512Trunc256Sum; -use proptest::prelude::*; -use crate::proptesting::*; +use crate::proptesting::*; use crate::vm::contracts::Contract; use crate::vm::database::clarity_store::ContractCommitment; use crate::vm::database::{ @@ -19,7 +19,7 @@ proptest! { let mut db = ClarityDatabase::new(&mut store, &NULL_HEADER_DB, &NULL_BURN_STATE_DB); db.begin(); - + let contract_id = contract.contract_context.contract_identifier.clone(); db.insert_contract(&contract_id, contract) @@ -153,8 +153,6 @@ proptest! { } } - - /// Returns the number of rows in the metadata table for the provided key. fn sql_metadata_table_key_count(store: &mut S, key: &str) -> u32 { let sqlite = store.get_side_store(); @@ -185,4 +183,4 @@ fn sql_data_table_key_count(store: &mut S, key: &str) -> ) .expect("failed to verify results in sqlite"); count -} \ No newline at end of file +} diff --git a/stacks-common/src/proptesting/hashmap.rs b/stacks-common/src/proptesting/hashmap.rs index e277671db2..a5888ebfd4 100644 --- a/stacks-common/src/proptesting/hashmap.rs +++ b/stacks-common/src/proptesting/hashmap.rs @@ -1,13 +1,12 @@ use std::hash::Hash; -use proptest::strategy::{statics, Strategy, ValueTree, NewTree}; -use proptest::collection::{VecStrategy, VecValueTree, SizeRange}; -use proptest::tuple::TupleValueTree; +use proptest::collection::{SizeRange, VecStrategy, VecValueTree}; +use proptest::strategy::{statics, NewTree, Strategy, ValueTree}; use proptest::test_runner::TestRunner; +use proptest::tuple::TupleValueTree; use crate::types::StacksHashMap; - #[derive(Debug, Clone, Copy)] struct MinSize(usize); @@ -32,7 +31,6 @@ where V: ValueTree, K::Value: Hash + Eq; - impl Strategy for StacksHashMapStrategy where K: Strategy, @@ -67,8 +65,8 @@ where #[derive(Clone, Copy, Debug)] struct VecToStacksHashMap; -impl - statics::MapFn> for VecToStacksHashMap +impl statics::MapFn> + for VecToStacksHashMap { type Output = StacksHashMap; fn apply(&self, vec: Vec<(K, V)>) -> StacksHashMap { @@ -86,7 +84,10 @@ where { let size = size.into(); StacksHashMapStrategy(statics::Filter::new( - statics::Map::new(proptest::collection::vec((key, value), size.clone()), VecToStacksHashMap), + statics::Map::new( + proptest::collection::vec((key, value), size.clone()), + VecToStacksHashMap, + ), "HashMap minimum size".into(), MinSize(size.start()), )) @@ -96,4 +97,4 @@ impl statics::FilterFn> for MinSize { fn apply(&self, map: &StacksHashMap) -> bool { map.len() >= self.0 } -} \ No newline at end of file +} diff --git a/stacks-common/src/proptesting/hashset.rs b/stacks-common/src/proptesting/hashset.rs index bfba11c64a..c84f4c8ccc 100644 --- a/stacks-common/src/proptesting/hashset.rs +++ b/stacks-common/src/proptesting/hashset.rs @@ -1,6 +1,6 @@ use std::hash::Hash; -use proptest::collection::{VecStrategy, VecValueTree, SizeRange}; +use proptest::collection::{SizeRange, VecStrategy, VecValueTree}; use proptest::prelude::*; use proptest::strategy::{statics, NewTree, ValueTree}; use proptest::test_runner::TestRunner; @@ -13,9 +13,7 @@ struct MinSize(usize); #[derive(Clone, Copy, Debug)] struct VecToStacksHashSet; -impl statics::MapFn> - for VecToStacksHashSet -{ +impl statics::MapFn> for VecToStacksHashSet { type Output = StacksHashSet; fn apply(&self, vec: Vec) -> StacksHashSet { vec.into_iter().collect() @@ -82,8 +80,11 @@ where { let size = size.into(); StacksHashSetStrategy(statics::Filter::new( - statics::Map::new(proptest::collection::vec(element, size.clone()), VecToStacksHashSet), + statics::Map::new( + proptest::collection::vec(element, size.clone()), + VecToStacksHashSet, + ), "HashSet minimum size".into(), MinSize(size.start()), )) -} \ No newline at end of file +} diff --git a/stacks-common/src/proptesting/mod.rs b/stacks-common/src/proptesting/mod.rs index 242b5b7fa2..e9ddbf9c16 100644 --- a/stacks-common/src/proptesting/mod.rs +++ b/stacks-common/src/proptesting/mod.rs @@ -13,4 +13,4 @@ pub fn sha_512_trunc_256_sum() -> impl Strategy { arr[i as usize] = 1; Sha512Trunc256Sum::from_data(&arr) }) -} \ No newline at end of file +} diff --git a/stacks-common/src/types/hashmap.rs b/stacks-common/src/types/hashmap.rs index ef47636f4a..454f0ca4c4 100644 --- a/stacks-common/src/types/hashmap.rs +++ b/stacks-common/src/types/hashmap.rs @@ -92,4 +92,4 @@ where } map } -} \ No newline at end of file +} diff --git a/stacks-common/src/types/hashset.rs b/stacks-common/src/types/hashset.rs index 825a144041..a2f04cb54d 100644 --- a/stacks-common/src/types/hashset.rs +++ b/stacks-common/src/types/hashset.rs @@ -92,4 +92,4 @@ where fn into(self) -> HashSet { self.0 } -} \ No newline at end of file +} From ec8ced63346eb7a0ba7450a6520a1bf441b9bb2b Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Thu, 7 Mar 2024 08:58:36 +0100 Subject: [PATCH 23/28] chore: cleanup, fmt --- contrib/tools/relay-server/src/http.rs | 2 +- contrib/tools/relay-server/src/state.rs | 2 +- contrib/tools/relay-server/src/url.rs | 2 +- stacks-signer/src/client/stackerdb.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/tools/relay-server/src/http.rs b/contrib/tools/relay-server/src/http.rs index c9d40ddbbf..58ee9d2f9d 100644 --- a/contrib/tools/relay-server/src/http.rs +++ b/contrib/tools/relay-server/src/http.rs @@ -1,6 +1,6 @@ use std::io::{Error, Read}; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; +use stacks_common::types::StacksHashMap as HashMap; use crate::to_io_result::ToIoResult; diff --git a/contrib/tools/relay-server/src/state.rs b/contrib/tools/relay-server/src/state.rs index ab526387d5..91696471cd 100644 --- a/contrib/tools/relay-server/src/state.rs +++ b/contrib/tools/relay-server/src/state.rs @@ -1,4 +1,4 @@ -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; +use stacks_common::types::StacksHashMap as HashMap; #[derive(Default)] pub struct State { diff --git a/contrib/tools/relay-server/src/url.rs b/contrib/tools/relay-server/src/url.rs index 0226881495..962ae98e37 100644 --- a/contrib/tools/relay-server/src/url.rs +++ b/contrib/tools/relay-server/src/url.rs @@ -1,4 +1,4 @@ -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; +use stacks_common::types::StacksHashMap as HashMap; pub trait QueryEx { fn url_query(&self) -> HashMap<&str, &str>; diff --git a/stacks-signer/src/client/stackerdb.rs b/stacks-signer/src/client/stackerdb.rs index d43682c56d..cc96697e36 100644 --- a/stacks-signer/src/client/stackerdb.rs +++ b/stacks-signer/src/client/stackerdb.rs @@ -25,7 +25,7 @@ use slog::{slog_debug, slog_warn}; use stacks_common::codec::{read_next, StacksMessageCodec}; use stacks_common::consts::SIGNER_SLOTS_PER_USER; use stacks_common::types::chainstate::StacksPrivateKey; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; +use stacks_common::types::StacksHashMap as HashMap; use stacks_common::{debug, warn}; use super::ClientError; From f0b32a0673115e69e63126352df97f6425b9ece5 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Thu, 7 Mar 2024 09:19:20 +0100 Subject: [PATCH 24/28] chore: rebase on next, cleanup & fmt --- stacks-signer/src/client/stackerdb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stacks-signer/src/client/stackerdb.rs b/stacks-signer/src/client/stackerdb.rs index cc96697e36..f1436ac34d 100644 --- a/stacks-signer/src/client/stackerdb.rs +++ b/stacks-signer/src/client/stackerdb.rs @@ -76,7 +76,7 @@ impl StackerDB { signers_message_stackerdb_sessions.insert( msg_id, StackerDBSession::new( - host.to_string(), + host, QualifiedContractIdentifier::new( stackerdb_issuer.into(), ContractName::from( From 2f22c6cf56b18ec6d256107946d65904fd941b26 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Thu, 7 Mar 2024 15:45:20 +0100 Subject: [PATCH 25/28] added proptest strategy examples in stackslib + dependency issue + fmt-stacks --- Cargo.lock | 5 +-- clarity/Cargo.toml | 5 +-- clarity/src/libclarity.rs | 3 +- contrib/tools/relay-server/Cargo.toml | 1 - stacks-common/src/proptesting/mod.rs | 33 ++++++++++++--- stacks-common/src/proptesting/types.rs | 51 +++++++++++++++++++++++ stackslib/Cargo.toml | 4 +- stackslib/src/lib.rs | 4 ++ stackslib/src/net/atlas/tests.rs | 1 + stackslib/src/proptesting/burnchains.rs | 12 ++++++ stackslib/src/proptesting/mod.rs | 2 + stackslib/src/proptesting/net.rs | 54 +++++++++++++++++++++++++ testnet/stacks-node/Cargo.toml | 1 - 13 files changed, 158 insertions(+), 18 deletions(-) create mode 100644 stacks-common/src/proptesting/types.rs create mode 100644 stackslib/src/proptesting/burnchains.rs create mode 100644 stackslib/src/proptesting/mod.rs create mode 100644 stackslib/src/proptesting/net.rs diff --git a/Cargo.lock b/Cargo.lock index 08db258094..6f72aba99d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -730,7 +730,6 @@ version = "0.0.1" dependencies = [ "assert-json-diff", "clarity", - "hashbrown 0.14.3", "integer-sqrt", "lazy_static", "proptest", @@ -2775,7 +2774,6 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" name = "relay-server" version = "0.0.1" dependencies = [ - "hashbrown 0.14.3", "stacks-common", ] @@ -3485,7 +3483,6 @@ dependencies = [ "base64 0.12.3", "chrono", "clarity", - "hashbrown 0.14.3", "http-types", "lazy_static", "libc", @@ -3556,7 +3553,6 @@ dependencies = [ "criterion", "curve25519-dalek 2.0.0", "ed25519-dalek", - "hashbrown 0.14.3", "integer-sqrt", "lazy_static", "libc", @@ -3567,6 +3563,7 @@ dependencies = [ "percent-encoding", "pox-locking", "prometheus", + "proptest", "rand 0.8.5", "rand_chacha 0.3.1", "rand_core 0.6.4", diff --git a/clarity/Cargo.toml b/clarity/Cargo.toml index ed66ad1e47..b080726636 100644 --- a/clarity/Cargo.toml +++ b/clarity/Cargo.toml @@ -30,7 +30,7 @@ slog = { version = "2.5.2", features = [ "max_level_trace" ] } stacks_common = { package = "stacks-common", path = "../stacks-common" } rstest = "0.17.0" rstest_reuse = "0.5.0" -hashbrown = { workspace = true } +proptest = { workspace = true, optional = true } [dependencies.serde_json] version = "1.0" @@ -46,7 +46,6 @@ features = ["std"] [dev-dependencies] assert-json-diff = "1.0.0" -proptest = { workspace = true } clarity = { path = "./", features = ["testing"] } # This ensures that `stacks-common` is built using the `testing` feature # when we build this crate in dev/test. Note that the --features flag @@ -57,5 +56,5 @@ stacks_common = { package = "stacks-common", path = "../stacks-common", features default = [] developer-mode = [] slog_json = ["stacks_common/slog_json"] -testing = ["stacks_common/testing"] +testing = ["dep:proptest", "stacks_common/testing"] diff --git a/clarity/src/libclarity.rs b/clarity/src/libclarity.rs index 9f46691f93..860a3ab064 100644 --- a/clarity/src/libclarity.rs +++ b/clarity/src/libclarity.rs @@ -41,7 +41,8 @@ pub extern crate rstest_reuse; #[macro_use] extern crate stacks_common; -#[cfg(test)] +#[cfg(any(test, feature = "testing"))] +#[macro_use] pub mod proptesting; pub use stacks_common::{ diff --git a/contrib/tools/relay-server/Cargo.toml b/contrib/tools/relay-server/Cargo.toml index 5c796dcf16..70ee265bfa 100644 --- a/contrib/tools/relay-server/Cargo.toml +++ b/contrib/tools/relay-server/Cargo.toml @@ -8,5 +8,4 @@ name = "relay-server" path = "src/main.rs" [dependencies] -hashbrown = { workspace = true } stacks_common = { path = "../../../stacks-common", package = "stacks-common" } diff --git a/stacks-common/src/proptesting/mod.rs b/stacks-common/src/proptesting/mod.rs index e9ddbf9c16..3e0db46863 100644 --- a/stacks-common/src/proptesting/mod.rs +++ b/stacks-common/src/proptesting/mod.rs @@ -1,16 +1,37 @@ pub mod hashmap; pub mod hashset; +pub mod types; pub use hashmap::stacks_hash_map; pub use hashset::stacks_hash_set; -use proptest::strategy::Strategy; +use proptest::prelude::*; +use proptest::sample::SizeRange; +pub use types::*; -use crate::util::hash::Sha512Trunc256Sum; +use crate::util::hash::{to_hex, Hash160, Sha512Trunc256Sum}; pub fn sha_512_trunc_256_sum() -> impl Strategy { - (0..64u8).prop_map(|i| { - let mut arr = [0u8; 64]; - arr[i as usize] = 1; - Sha512Trunc256Sum::from_data(&arr) + prop::collection::vec(any::(), 32..=32).prop_map(|vec| { + let arr: [u8; 32] = vec.try_into().expect("failed to generate 32-byte array"); + + Sha512Trunc256Sum::from(arr) + }) +} + +/// Generate a random hex string representing a byte array of the given length. +/// i.e. the string will be `2 * byte_len` characters long. +pub fn hex_string(byte_len: impl Into) -> impl Strategy { + prop::collection::vec(any::(), byte_len).prop_map(|vec| to_hex(&vec)) +} + +pub fn bytes(len: impl Into) -> impl Strategy> { + prop::collection::vec(any::(), len) +} + +pub fn hash_160() -> impl Strategy { + prop::collection::vec(any::(), 20..=20).prop_map(|vec| { + let arr: [u8; 20] = vec.try_into().expect("failed to generate 20-byte array"); + + Hash160(arr) }) } diff --git a/stacks-common/src/proptesting/types.rs b/stacks-common/src/proptesting/types.rs new file mode 100644 index 0000000000..d468ddfc3d --- /dev/null +++ b/stacks-common/src/proptesting/types.rs @@ -0,0 +1,51 @@ +use std::any; + +use proptest::prelude::*; + +use super::bytes; +use crate::types::chainstate::{StacksAddress, StacksBlockId}; +use crate::types::net::{PeerAddress, PeerHost}; +use crate::types::StacksPublicKeyBuffer; +use crate::util::hash::Hash160; + +pub fn stacks_public_key_buffer() -> impl Strategy { + bytes(33).prop_map(|vec| { + let arr: [u8; 33] = vec.try_into().expect("failed to generate 33-byte array"); + + StacksPublicKeyBuffer::from(arr) + }) +} + +pub fn stacks_address() -> impl Strategy { + bytes(20).prop_map(|vec| { + let arr: [u8; 20] = vec.try_into().expect("failed to generate 20-byte array"); + + StacksAddress { + version: 1, + bytes: Hash160(arr), + } + }) +} + +pub fn peer_address() -> impl Strategy { + bytes(16).prop_map(|vec| { + let arr: [u8; 16] = vec.try_into().expect("failed to generate 16-byte array"); + + PeerAddress(arr) + }) +} + +pub fn peer_host() -> impl Strategy { + prop_oneof![ + (peer_address(), any::()).prop_map(|(peer, port)| PeerHost::IP(peer, port)), + (any::(), any::()).prop_map(|(host, port)| PeerHost::DNS(host, port)) + ] +} + +pub fn stacks_block_id() -> impl Strategy { + bytes(32).prop_map(|vec| { + let arr: [u8; 32] = vec.try_into().expect("failed to generate 32-byte array"); + + StacksBlockId(arr) + }) +} diff --git a/stackslib/Cargo.toml b/stackslib/Cargo.toml index 438118db69..d95492e2c3 100644 --- a/stackslib/Cargo.toml +++ b/stackslib/Cargo.toml @@ -57,7 +57,7 @@ pox-locking = { path = "../pox-locking" } libstackerdb = { path = "../libstackerdb" } siphasher = "0.3.7" wsts = { workspace = true } -hashbrown = { workspace = true } +proptest = { workspace = true, optional = true } [target.'cfg(not(target_env = "msvc"))'.dependencies] tikv-jemallocator = {workspace = true} @@ -113,7 +113,7 @@ disable-costs = [] developer-mode = ["clarity/developer-mode"] monitoring_prom = ["prometheus"] slog_json = ["slog-json", "stacks-common/slog_json", "clarity/slog_json", "pox-locking/slog_json"] -testing = ["stacks-common/testing", "clarity/testing"] +testing = ["dep:proptest", "stacks-common/testing", "clarity/testing"] [target.'cfg(all(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"), not(target_env = "msvc")))'.dependencies] sha2 = { version = "0.10", features = ["asm"] } diff --git a/stackslib/src/lib.rs b/stackslib/src/lib.rs index bd634cef64..7cc7922c55 100644 --- a/stackslib/src/lib.rs +++ b/stackslib/src/lib.rs @@ -71,6 +71,10 @@ pub mod cost_estimates; pub mod clarity_cli; +#[cfg(any(test, feature = "testing"))] +#[macro_use] +pub mod proptesting; + // set via _compile-time_ envars const GIT_BRANCH: Option<&'static str> = option_env!("GIT_BRANCH"); const GIT_COMMIT: Option<&'static str> = option_env!("GIT_COMMIT"); diff --git a/stackslib/src/net/atlas/tests.rs b/stackslib/src/net/atlas/tests.rs index 2ebcb71316..117ada9ba8 100644 --- a/stackslib/src/net/atlas/tests.rs +++ b/stackslib/src/net/atlas/tests.rs @@ -18,6 +18,7 @@ use std::collections::{BinaryHeap, HashMap, HashSet}; use std::{thread, time}; use clarity::vm::types::QualifiedContractIdentifier; +use proptest::prelude::*; use stacks_common::types::chainstate::{BlockHeaderHash, StacksBlockId}; use stacks_common::types::net::{PeerAddress, PeerHost}; use stacks_common::util::hash::Hash160; diff --git a/stackslib/src/proptesting/burnchains.rs b/stackslib/src/proptesting/burnchains.rs new file mode 100644 index 0000000000..9dfed7887b --- /dev/null +++ b/stackslib/src/proptesting/burnchains.rs @@ -0,0 +1,12 @@ +use proptest::prelude::*; +use stacks_common::proptesting::bytes; + +use crate::burnchains::Txid; + +pub fn txid() -> impl Strategy { + bytes(32).prop_map(|vec| { + let arr: [u8; 32] = vec.try_into().expect("failed to generate 32-byte array"); + + Txid(arr) + }) +} diff --git a/stackslib/src/proptesting/mod.rs b/stackslib/src/proptesting/mod.rs new file mode 100644 index 0000000000..7b9319e9e2 --- /dev/null +++ b/stackslib/src/proptesting/mod.rs @@ -0,0 +1,2 @@ +pub mod burnchains; +pub mod net; diff --git a/stackslib/src/proptesting/net.rs b/stackslib/src/proptesting/net.rs new file mode 100644 index 0000000000..eb38f4c94e --- /dev/null +++ b/stackslib/src/proptesting/net.rs @@ -0,0 +1,54 @@ +use clarity::proptesting::qualified_contract_identifier; +use proptest::prelude::*; +use stacks_common::proptesting::{hash_160, stacks_block_id}; + +use super::burnchains::txid; +use crate::net::atlas::{Attachment, AttachmentInstance}; + +pub fn attachment_instance() -> impl Strategy { + ( + // content_hash: Hash160 + hash_160(), + // attachment_index: u32 + any::(), + // stacks_block_height: u64 + any::(), + // index_block_hash: StacksBlockId + stacks_block_id(), + // metadata: String + ".*".prop_map(String::from), + // contract_id: QualifiedContractIdentifier + qualified_contract_identifier(), + // tx_id: Txid + txid(), + // canonical_stacks_tip_height: Option + any::>(), + ) + .prop_map( + |( + content_hash, + attachment_index, + stacks_block_height, + index_block_hash, + metadata, + contract_id, + tx_id, + canonical_stacks_tip_height, + )| { + AttachmentInstance { + content_hash, + attachment_index, + stacks_block_height, + index_block_hash, + metadata, + contract_id, + tx_id, + canonical_stacks_tip_height, + } + }, + ) +} + +pub fn attachment() -> impl Strategy { + prop::collection::vec(any::(), 10..256).prop_map(|content| Attachment { content }) +} diff --git a/testnet/stacks-node/Cargo.toml b/testnet/stacks-node/Cargo.toml index ca88a36189..2e70e1d045 100644 --- a/testnet/stacks-node/Cargo.toml +++ b/testnet/stacks-node/Cargo.toml @@ -30,7 +30,6 @@ libsigner = { path = "../../libsigner" } wsts = { workspace = true } rand = { workspace = true } rand_core = { workspace = true } -hashbrown = { workspace = true } [target.'cfg(not(target_env = "msvc"))'.dependencies] tikv-jemallocator = {workspace = true} From 265ca00ad2f719e93310df64594d4f838efce96c Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Thu, 7 Mar 2024 17:36:26 +0100 Subject: [PATCH 26/28] wip: attempting to locate dkg timeout issue --- libsigner/src/http.rs | 2 +- libsigner/src/messages.rs | 6 ++-- stacks-common/src/types/hashmap.rs | 29 ++++++++++++++++++- stacks-common/src/types/hashset.rs | 11 +++++++ stacks-signer/src/runloop.rs | 14 ++++----- stacks-signer/src/signer.rs | 29 ++++--------------- .../stacks-node/src/nakamoto_node/miner.rs | 5 +--- 7 files changed, 55 insertions(+), 41 deletions(-) diff --git a/libsigner/src/http.rs b/libsigner/src/http.rs index 96f3ab4cff..2618ed5626 100644 --- a/libsigner/src/http.rs +++ b/libsigner/src/http.rs @@ -20,7 +20,7 @@ use std::net::SocketAddr; use stacks_common::codec::MAX_MESSAGE_LEN; use stacks_common::deps_common::httparse; -use stacks_common::types::{StacksHashMap as HashMap, StacksHashSet as HashSet}; +use stacks_common::types::StacksHashMap as HashMap; use stacks_common::util::chunked_encoding::*; use crate::error::{EventError, RPCError}; diff --git a/libsigner/src/messages.rs b/libsigner/src/messages.rs index 7c85758fa0..8ea1d9ab66 100644 --- a/libsigner/src/messages.rs +++ b/libsigner/src/messages.rs @@ -300,7 +300,7 @@ impl StacksMessageCodecExtensions for BadPrivateShare { impl StacksMessageCodecExtensions for HashSet { fn inner_consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { write_next(fd, &(self.len() as u32))?; - for i in self.clone() { + for i in self { write_next(fd, &i)?; } Ok(()) @@ -551,8 +551,8 @@ impl StacksMessageCodecExtensions for DkgPrivateShares { let share: Vec = read_next(fd)?; share_map.insert(id, share); } - let share_map: hashbrown::HashMap<_, _> = share_map.into(); - shares.push((id, share_map)); + //let share_map: hashbrown::HashMap<_, _> = share_map.into(); + shares.push((id, share_map.into())); } Ok(DkgPrivateShares { dkg_id, diff --git a/stacks-common/src/types/hashmap.rs b/stacks-common/src/types/hashmap.rs index 454f0ca4c4..ba6b51751c 100644 --- a/stacks-common/src/types/hashmap.rs +++ b/stacks-common/src/types/hashmap.rs @@ -2,9 +2,11 @@ use std::hash::Hash; use std::iter::{FromIterator, IntoIterator}; use std::ops::{Deref, DerefMut}; -use hashbrown::HashMap; +use hashbrown::{HashMap, HashSet}; use rand::Rng; +use super::StacksHashSet; + #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct StacksHashMap(pub HashMap) where @@ -21,6 +23,14 @@ where pub fn with_capacity(capacity: usize) -> Self { StacksHashMap(HashMap::with_capacity(capacity)) } + + pub fn into_values(self) -> impl Iterator { + self.0.into_values() + } + + pub fn into_keys(self) -> impl Iterator { + self.0.into_keys() + } } impl Default for StacksHashMap @@ -93,3 +103,20 @@ where map } } + +// the trait bound `hashbrown::map::HashMap>: From>>` is not satisfied +// the trait `From<[(u32, hashbrown::set::HashSet); _]>` is implemented for `hashbrown::map::HashMap>` +// for that trait implementation, expected `[(u32, hashbrown::set::HashSet); _]`, found `StacksHashMap>` +// required for `StacksHashMap>` to implement `Into>>`rustcClick for full compiler diagnostic + +impl Into>> for StacksHashMap> +where + T: Eq + Hash + Clone, +{ + fn into(self) -> HashMap> { + self.0 + .into_iter() + .map(|(k, v)| (k, v.into_iter().collect())) + .collect() + } +} \ No newline at end of file diff --git a/stacks-common/src/types/hashset.rs b/stacks-common/src/types/hashset.rs index a2f04cb54d..6bf620a035 100644 --- a/stacks-common/src/types/hashset.rs +++ b/stacks-common/src/types/hashset.rs @@ -54,6 +54,17 @@ where } } +impl Iterator for &StacksHashSet +where + T: Eq + Hash + Clone, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.0.clone().into_iter().next() + } +} + impl FromIterator for StacksHashSet where T: Eq + Hash, diff --git a/stacks-signer/src/runloop.rs b/stacks-signer/src/runloop.rs index 0eb2de5bef..d173b15b22 100644 --- a/stacks-signer/src/runloop.rs +++ b/stacks-signer/src/runloop.rs @@ -92,8 +92,8 @@ impl RunLoop { let mut signer_key_ids = HashMap::with_capacity(signers.len()); let mut signer_ids = HashMap::with_capacity(signers.len()); let mut public_keys = PublicKeys { - signers: HashMap::with_capacity(signers.len()).into(), - key_ids: HashMap::with_capacity(4000).into(), + signers: hashbrown::HashMap::with_capacity(signers.len()), + key_ids: hashbrown::HashMap::with_capacity(4000), }; let mut signer_public_keys = HashMap::with_capacity(signers.len()); for (i, entry) in signers.iter().enumerate() { @@ -213,7 +213,7 @@ impl RunLoop { signer_slot_id: *signer_slot_id, key_ids, signer_entries, - signer_slot_ids: signer_slot_ids.iter().map(|(_, v)| v.clone()).collect(), + signer_slot_ids: signer_slot_ids.into_values().collect(), ecdsa_private_key: self.config.ecdsa_private_key, stacks_private_key: self.config.stacks_private_key, node_host: self.config.node_host.to_string(), @@ -415,11 +415,9 @@ mod tests { let parsed_entries = RunLoop::parse_nakamoto_signer_entries(&signer_entries, false); assert_eq!(parsed_entries.signer_ids.len(), nmb_signers); - let mut signer_ids = parsed_entries - .signer_ids - .iter() - .map(|(_, v)| v.clone()) - .collect::>(); + let mut signer_ids = parsed_entries + .signer_ids + .into_values().collect::>(); signer_ids.sort(); assert_eq!( signer_ids, diff --git a/stacks-signer/src/signer.rs b/stacks-signer/src/signer.rs index d465135d16..18068b9dba 100644 --- a/stacks-signer/src/signer.rs +++ b/stacks-signer/src/signer.rs @@ -177,23 +177,8 @@ impl From for Signer { dkg_end_timeout: signer_config.dkg_end_timeout, nonce_timeout: signer_config.nonce_timeout, sign_timeout: signer_config.sign_timeout, - signer_key_ids: signer_config - .signer_entries - .coordinator_key_ids - .iter() - .map(|(k, v)| { - ( - k.clone(), - v.clone().into_iter().collect::>(), - ) - }) - .collect::>(), - signer_public_keys: signer_config - .signer_entries - .signer_public_keys - .iter() - .map(|(k, v)| (k.clone(), v.clone())) - .collect::>(), + signer_key_ids: signer_config.signer_entries.coordinator_key_ids.into(), + signer_public_keys: signer_config.signer_entries.signer_public_keys.into(), }; let coordinator = FireCoordinator::new(coordinator_config); @@ -227,8 +212,7 @@ impl From for Signer { signer_addresses: signer_config .signer_entries .signer_ids - .iter() - .map(|(k, _)| k.clone()) + .into_keys() .collect(), signer_slot_ids: signer_config.signer_slot_ids.clone(), next_signer_slot_ids: vec![], @@ -764,10 +748,7 @@ impl Signer { transactions, ); // We only allow enforcement of one special cased transaction per signer address per block - Ok(filtered_transactions - .iter() - .map(|(_, v)| v.clone()) - .collect()) + Ok(filtered_transactions.into_values().collect()) } /// Determine the vote for a block and update the block info and nonce request accordingly @@ -922,7 +903,7 @@ impl Signer { epoch, signer_transactions, new_transaction, - ) { + ) { warn!( "Signer #{}: Failed to broadcast DKG public key vote ({dkg_public_key:?}): {e:?}", self.signer_id diff --git a/testnet/stacks-node/src/nakamoto_node/miner.rs b/testnet/stacks-node/src/nakamoto_node/miner.rs index c8b08201f4..d93b6c0991 100644 --- a/testnet/stacks-node/src/nakamoto_node/miner.rs +++ b/testnet/stacks-node/src/nakamoto_node/miner.rs @@ -359,10 +359,7 @@ impl BlockMinerThread { _ => {} // Any other message is ignored } } - Ok(filtered_transactions - .iter() - .map(|(_, v)| v.clone()) - .collect()) + Ok(filtered_transactions.into_values().collect()) } fn wait_for_signer_signature( From ae14e59fce42bb44ae992cdf5bbda69c31779364 Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Thu, 7 Mar 2024 19:04:31 +0100 Subject: [PATCH 27/28] revert wrapper hashmap/set types, caused problems in stackerlib --- clarity/src/proptesting/contracts.rs | 7 +- clarity/src/proptesting/values.rs | 6 +- libsigner/src/messages.rs | 15 ++-- stacks-common/src/types/hashmap.rs | 122 --------------------------- stacks-common/src/types/hashset.rs | 106 ----------------------- stacks-common/src/types/mod.rs | 6 +- 6 files changed, 18 insertions(+), 244 deletions(-) delete mode 100644 stacks-common/src/types/hashmap.rs delete mode 100644 stacks-common/src/types/hashset.rs diff --git a/clarity/src/proptesting/contracts.rs b/clarity/src/proptesting/contracts.rs index c11bc360d2..e372acedc0 100644 --- a/clarity/src/proptesting/contracts.rs +++ b/clarity/src/proptesting/contracts.rs @@ -17,7 +17,12 @@ pub fn contract_context(clarity_version: ClarityVersion) -> impl Strategy>() + + }), // functions stacks_hash_map(clarity_name(), defined_function(), 1..5), // defined_traits diff --git a/clarity/src/proptesting/values.rs b/clarity/src/proptesting/values.rs index 7131262ae8..12e0d0a4c6 100644 --- a/clarity/src/proptesting/values.rs +++ b/clarity/src/proptesting/values.rs @@ -238,8 +238,10 @@ impl PropValue { 1 => buffer(size as u32), // 10% chance for a string-ascii 1 => string_ascii(size as u32), - // 80% chance for a list - 8 => any_list + // 10% change for a string-utf8 + 1 => string_utf8(size as u32), + // 70% chance for a list + 7 => any_list ] .prop_map_into() } diff --git a/libsigner/src/messages.rs b/libsigner/src/messages.rs index 8ea1d9ab66..a5c7fe2ffe 100644 --- a/libsigner/src/messages.rs +++ b/libsigner/src/messages.rs @@ -300,8 +300,8 @@ impl StacksMessageCodecExtensions for BadPrivateShare { impl StacksMessageCodecExtensions for HashSet { fn inner_consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { write_next(fd, &(self.len() as u32))?; - for i in self { - write_next(fd, &i)?; + for i in self.iter() { + write_next(fd, i)?; } Ok(()) } @@ -322,17 +322,14 @@ impl StacksMessageCodecExtensions for DkgFailure { DkgFailure::BadState => write_next(fd, &0u8), DkgFailure::MissingPublicShares(shares) => { write_next(fd, &1u8)?; - let shares: HashSet = shares.into(); shares.inner_consensus_serialize(fd) } DkgFailure::BadPublicShares(shares) => { write_next(fd, &2u8)?; - let shares: HashSet = shares.into(); shares.inner_consensus_serialize(fd) } DkgFailure::MissingPrivateShares(shares) => { write_next(fd, &3u8)?; - let shares: HashSet = shares.into(); shares.inner_consensus_serialize(fd) } DkgFailure::BadPrivateShares(shares) => { @@ -352,15 +349,15 @@ impl StacksMessageCodecExtensions for DkgFailure { 0 => DkgFailure::BadState, 1 => { let set = HashSet::::inner_consensus_deserialize(fd)?; - DkgFailure::MissingPublicShares(set.into()) + DkgFailure::MissingPublicShares(set) } 2 => { let set = HashSet::::inner_consensus_deserialize(fd)?; - DkgFailure::BadPublicShares(set.into()) + DkgFailure::BadPublicShares(set) } 3 => { let set = HashSet::::inner_consensus_deserialize(fd)?; - DkgFailure::MissingPrivateShares(set.into()) + DkgFailure::MissingPrivateShares(set) } 4 => { let mut map = HashMap::new(); @@ -370,7 +367,7 @@ impl StacksMessageCodecExtensions for DkgFailure { let bad_share = BadPrivateShare::inner_consensus_deserialize(fd)?; map.insert(i, bad_share); } - DkgFailure::BadPrivateShares(map.into()) + DkgFailure::BadPrivateShares(map) } _ => { return Err(CodecError::DeserializeError(format!( diff --git a/stacks-common/src/types/hashmap.rs b/stacks-common/src/types/hashmap.rs deleted file mode 100644 index ba6b51751c..0000000000 --- a/stacks-common/src/types/hashmap.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::hash::Hash; -use std::iter::{FromIterator, IntoIterator}; -use std::ops::{Deref, DerefMut}; - -use hashbrown::{HashMap, HashSet}; -use rand::Rng; - -use super::StacksHashSet; - -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -pub struct StacksHashMap(pub HashMap) -where - K: Eq + Hash; - -impl StacksHashMap -where - K: Eq + Hash, -{ - pub fn new() -> Self { - StacksHashMap(HashMap::new()) - } - - pub fn with_capacity(capacity: usize) -> Self { - StacksHashMap(HashMap::with_capacity(capacity)) - } - - pub fn into_values(self) -> impl Iterator { - self.0.into_values() - } - - pub fn into_keys(self) -> impl Iterator { - self.0.into_keys() - } -} - -impl Default for StacksHashMap -where - K: Eq + Hash, -{ - fn default() -> Self { - StacksHashMap(HashMap::::new()) - } -} - -impl From> for StacksHashMap -where - K: Eq + Hash, -{ - fn from(map: HashMap) -> Self { - StacksHashMap(map) - } -} - -impl From<&HashMap> for StacksHashMap -where - K: Eq + Hash + Clone, - V: Clone, -{ - fn from(map: &HashMap) -> Self { - StacksHashMap(map.clone()) - } -} - -impl Into> for StacksHashMap -where - K: Eq + Hash + Clone, - V: Clone, -{ - fn into(self) -> HashMap { - self.0 - } -} - -impl<'a, K, V> Deref for StacksHashMap -where - K: Eq + Hash, -{ - type Target = HashMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for StacksHashMap -where - K: Eq + Hash, -{ - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl FromIterator<(K, V)> for StacksHashMap -where - K: Eq + Hash, -{ - fn from_iter>(iter: I) -> Self { - let mut map = StacksHashMap::new(); - for (key, value) in iter { - map.insert(key, value); - } - map - } -} - -// the trait bound `hashbrown::map::HashMap>: From>>` is not satisfied -// the trait `From<[(u32, hashbrown::set::HashSet); _]>` is implemented for `hashbrown::map::HashMap>` -// for that trait implementation, expected `[(u32, hashbrown::set::HashSet); _]`, found `StacksHashMap>` -// required for `StacksHashMap>` to implement `Into>>`rustcClick for full compiler diagnostic - -impl Into>> for StacksHashMap> -where - T: Eq + Hash + Clone, -{ - fn into(self) -> HashMap> { - self.0 - .into_iter() - .map(|(k, v)| (k, v.into_iter().collect())) - .collect() - } -} \ No newline at end of file diff --git a/stacks-common/src/types/hashset.rs b/stacks-common/src/types/hashset.rs deleted file mode 100644 index 6bf620a035..0000000000 --- a/stacks-common/src/types/hashset.rs +++ /dev/null @@ -1,106 +0,0 @@ -use std::hash::Hash; -use std::iter::{FromIterator, IntoIterator}; -use std::ops::{Deref, DerefMut}; - -use hashbrown::HashSet; -use rand::Rng; - -#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)] -pub struct StacksHashSet(pub hashbrown::HashSet) -where - T: Eq + Hash; - -impl StacksHashSet -where - T: Eq + Hash, -{ - pub fn new() -> Self { - StacksHashSet(hashbrown::HashSet::new()) - } - - pub fn with_capacity(capacity: usize) -> Self { - StacksHashSet(hashbrown::HashSet::with_capacity(capacity)) - } -} - -impl Deref for StacksHashSet -where - T: Eq + Hash, -{ - type Target = hashbrown::HashSet; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for StacksHashSet -where - T: Eq + Hash, -{ - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Iterator for StacksHashSet -where - T: Eq + Hash + Clone, -{ - type Item = T; - - fn next(&mut self) -> Option { - self.0.clone().into_iter().next() - } -} - -impl Iterator for &StacksHashSet -where - T: Eq + Hash + Clone, -{ - type Item = T; - - fn next(&mut self) -> Option { - self.0.clone().into_iter().next() - } -} - -impl FromIterator for StacksHashSet -where - T: Eq + Hash, -{ - fn from_iter>(iter: I) -> Self { - let mut set = StacksHashSet(HashSet::new()); - for item in iter { - set.insert(item); - } - set - } -} - -impl From> for StacksHashSet -where - T: Eq + Hash, -{ - fn from(set: HashSet) -> Self { - StacksHashSet(set) - } -} - -impl From<&HashSet> for StacksHashSet -where - T: Eq + Hash + Clone, -{ - fn from(set: &HashSet) -> Self { - StacksHashSet(set.clone()) - } -} - -impl Into> for StacksHashSet -where - T: Eq + Hash, -{ - fn into(self) -> HashSet { - self.0 - } -} diff --git a/stacks-common/src/types/mod.rs b/stacks-common/src/types/mod.rs index 9615f66171..2f011b63a3 100644 --- a/stacks-common/src/types/mod.rs +++ b/stacks-common/src/types/mod.rs @@ -13,12 +13,10 @@ use crate::util::hash::Hash160; use crate::util::secp256k1::{MessageSignature, Secp256k1PublicKey}; pub mod chainstate; -pub mod hashmap; -pub mod hashset; pub mod net; -pub use hashmap::StacksHashMap; -pub use hashset::StacksHashSet; +pub type StacksHashMap = hashbrown::HashMap; +pub type StacksHashSet = hashbrown::HashSet; /// A container for public keys (compressed secp256k1 public keys) pub struct StacksPublicKeyBuffer(pub [u8; 33]); From a53aeed3a24c02a7035314db0ec266ab0af180ac Mon Sep 17 00:00:00 2001 From: Cyle Witruk Date: Thu, 7 Mar 2024 19:33:26 +0100 Subject: [PATCH 28/28] fmt-stacks --- clarity/src/proptesting/contracts.rs | 8 ++++---- clarity/src/vm/types/mod.rs | 1 - stacks-signer/src/runloop.rs | 4 +--- stacks-signer/src/signer.rs | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/clarity/src/proptesting/contracts.rs b/clarity/src/proptesting/contracts.rs index e372acedc0..364b7bf4b9 100644 --- a/clarity/src/proptesting/contracts.rs +++ b/clarity/src/proptesting/contracts.rs @@ -16,13 +16,13 @@ pub fn contract_context(clarity_version: ClarityVersion) -> impl Strategy unreachable!(), }), // variables - prop::collection::vec((clarity_name(), PropValue::any().prop_map_into()), 0..8) - .prop_map(|v| { + prop::collection::vec((clarity_name(), PropValue::any().prop_map_into()), 0..8).prop_map( + |v| { v.into_iter() .map(|(k, v)| (k, v)) .collect::>() - - }), + }, + ), // functions stacks_hash_map(clarity_name(), defined_function(), 1..5), // defined_traits diff --git a/clarity/src/vm/types/mod.rs b/clarity/src/vm/types/mod.rs index 6a988fd59a..abcb43a6ca 100644 --- a/clarity/src/vm/types/mod.rs +++ b/clarity/src/vm/types/mod.rs @@ -23,7 +23,6 @@ use std::collections::btree_map::Entry; use std::collections::BTreeMap; use std::{char, cmp, fmt, str}; -use hashbrown::hash_map::OccupiedEntry; use regex::Regex; use stacks_common::address::c32; use stacks_common::types::chainstate::StacksAddress; diff --git a/stacks-signer/src/runloop.rs b/stacks-signer/src/runloop.rs index d173b15b22..46228149ab 100644 --- a/stacks-signer/src/runloop.rs +++ b/stacks-signer/src/runloop.rs @@ -415,9 +415,7 @@ mod tests { let parsed_entries = RunLoop::parse_nakamoto_signer_entries(&signer_entries, false); assert_eq!(parsed_entries.signer_ids.len(), nmb_signers); - let mut signer_ids = parsed_entries - .signer_ids - .into_values().collect::>(); + let mut signer_ids = parsed_entries.signer_ids.into_values().collect::>(); signer_ids.sort(); assert_eq!( signer_ids, diff --git a/stacks-signer/src/signer.rs b/stacks-signer/src/signer.rs index 18068b9dba..9bab0ab6ca 100644 --- a/stacks-signer/src/signer.rs +++ b/stacks-signer/src/signer.rs @@ -903,7 +903,7 @@ impl Signer { epoch, signer_transactions, new_transaction, - ) { + ) { warn!( "Signer #{}: Failed to broadcast DKG public key vote ({dkg_public_key:?}): {e:?}", self.signer_id