From ea82a8eb96a06b0e015dfd6057e13113720ae234 Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Mon, 12 Sep 2022 13:59:09 -0400 Subject: [PATCH 01/15] fix: always update original SPV client chain work; also, correctly load headers when base_block is 0 when searching for a reorg --- src/burnchains/bitcoin/indexer.rs | 50 ++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/burnchains/bitcoin/indexer.rs b/src/burnchains/bitcoin/indexer.rs index 6509b0af2..d6d2f643d 100644 --- a/src/burnchains/bitcoin/indexer.rs +++ b/src/burnchains/bitcoin/indexer.rs @@ -472,22 +472,36 @@ impl BitcoinIndexer { let interval_start_block = (start_block / BLOCK_DIFFICULTY_CHUNK_SIZE).saturating_sub(2); let base_block = interval_start_block * BLOCK_DIFFICULTY_CHUNK_SIZE; - let interval_headers = - canonical_spv_client.read_block_headers(base_block, start_block + 1)?; - assert!( - interval_headers.len() >= (start_block - base_block) as usize, - "BUG: missing headers for {}-{}", - base_block, - start_block - ); - test_debug!( - "Copy headers {}-{}", - base_block, - base_block + interval_headers.len() as u64 - ); - reorg_spv_client - .insert_block_headers_before(base_block - 1, interval_headers)?; + if base_block > 0 { + let interval_headers = + canonical_spv_client.read_block_headers(base_block, start_block + 1)?; + assert!( + interval_headers.len() >= (start_block - base_block) as usize, + "BUG: missing headers for {}-{}", + base_block, + start_block + ); + + debug!( + "Copy headers {}-{}", + base_block, + base_block + interval_headers.len() as u64 + ); + reorg_spv_client + .insert_block_headers_before(base_block - 1, interval_headers)?; + } else { + let interval_headers = + canonical_spv_client.read_block_headers(1, start_block + 1)?; + assert!( + interval_headers.len() >= start_block as usize, + "BUG: missing headers for 0-{}", + start_block + ); + + debug!("Copy headers 0-{}", interval_headers.len() as u64); + reorg_spv_client.insert_block_headers_before(0, interval_headers)?; + } let last_interval = canonical_spv_client.find_highest_work_score_interval()?; @@ -545,12 +559,12 @@ impl BitcoinIndexer { let mut new_tip = 0; let mut found_common_ancestor = false; - let orig_spv_client = SpvClient::new( + let mut orig_spv_client = SpvClient::new( canonical_headers_path, 0, None, self.runtime.network_id, - false, + true, false, )?; @@ -718,7 +732,7 @@ impl BitcoinIndexer { if check_chain_work { let reorg_total_work = reorg_spv_client.update_chain_work()?; - let orig_total_work = orig_spv_client.get_chain_work()?; + let orig_total_work = orig_spv_client.update_chain_work()?; debug!("Bitcoin headers history is consistent up to {}", new_tip; "Orig chainwork" => %orig_total_work, From f121469f2709f8107c5b051db979ccf7efa5f628 Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Mon, 12 Sep 2022 14:00:00 -0400 Subject: [PATCH 02/15] chore: cargo fmt --- src/burnchains/burnchain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/burnchains/burnchain.rs b/src/burnchains/burnchain.rs index a11f87c57..ea4c772e2 100644 --- a/src/burnchains/burnchain.rs +++ b/src/burnchains/burnchain.rs @@ -72,11 +72,11 @@ use crate::util_lib::db::Error as db_error; use stacks_common::address::public_keys_to_address_hash; use stacks_common::address::AddressHashMode; use stacks_common::deps_common::bitcoin::util::hash::Sha256dHash as BitcoinSha256dHash; -use stacks_common::util::{get_epoch_time_ms, sleep_ms}; use stacks_common::util::get_epoch_time_secs; use stacks_common::util::hash::to_hex; use stacks_common::util::log; use stacks_common::util::vrf::VRFPublicKey; +use stacks_common::util::{get_epoch_time_ms, sleep_ms}; use crate::burnchains::bitcoin::indexer::BitcoinIndexer; use crate::chainstate::stacks::boot::POX_2_MAINNET_CODE; From 875e96e8234ae16827069fbdf104476156d08f3b Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Mon, 12 Sep 2022 14:01:30 -0400 Subject: [PATCH 03/15] fix: test for nearly-complete and partial SPV difficulty intervals --- .../src/tests/neon_integrations.rs | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/testnet/stacks-node/src/tests/neon_integrations.rs b/testnet/stacks-node/src/tests/neon_integrations.rs index 9e1bfe975..d6674c6ed 100644 --- a/testnet/stacks-node/src/tests/neon_integrations.rs +++ b/testnet/stacks-node/src/tests/neon_integrations.rs @@ -7317,3 +7317,73 @@ fn test_flash_block_skip_tenure() { channel.stop_chains_coordinator(); } + +#[test] +#[ignore] +fn test_chainwork_first_intervals() { + if env::var("BITCOIND_TEST") != Ok("1".into()) { + return; + } + + let (mut conf, miner_account) = neon_integration_test_conf(); + + let mut btcd_controller = BitcoinCoreController::new(conf.clone()); + btcd_controller + .start_bitcoind() + .map_err(|_e| ()) + .expect("Failed starting bitcoind"); + + let mut btc_regtest_controller = BitcoinRegtestController::new(conf.clone(), None); + let http_origin = format!("http://{}", &conf.node.rpc_bind); + + btc_regtest_controller.bootstrap_chain(2016 * 2 - 1); + + eprintln!("Chain bootstrapped..."); + + let mut run_loop = neon::RunLoop::new(conf); + let blocks_processed = run_loop.get_blocks_processed_arc(); + let missed_tenures = run_loop.get_missed_tenures_arc(); + + let channel = run_loop.get_coordinator_channel().unwrap(); + + thread::spawn(move || run_loop.start(None, 0)); + + // give the run loop some time to start up! + wait_for_runloop(&blocks_processed); + channel.stop_chains_coordinator(); +} + +#[test] +#[ignore] +fn test_chainwork_partial_interval() { + if env::var("BITCOIND_TEST") != Ok("1".into()) { + return; + } + + let (mut conf, miner_account) = neon_integration_test_conf(); + + let mut btcd_controller = BitcoinCoreController::new(conf.clone()); + btcd_controller + .start_bitcoind() + .map_err(|_e| ()) + .expect("Failed starting bitcoind"); + + let mut btc_regtest_controller = BitcoinRegtestController::new(conf.clone(), None); + let http_origin = format!("http://{}", &conf.node.rpc_bind); + + btc_regtest_controller.bootstrap_chain(2016 - 1); + + eprintln!("Chain bootstrapped..."); + + let mut run_loop = neon::RunLoop::new(conf); + let blocks_processed = run_loop.get_blocks_processed_arc(); + let missed_tenures = run_loop.get_missed_tenures_arc(); + + let channel = run_loop.get_coordinator_channel().unwrap(); + + thread::spawn(move || run_loop.start(None, 0)); + + // give the run loop some time to start up! + wait_for_runloop(&blocks_processed); + channel.stop_chains_coordinator(); +} From 5666b50dbac0e46b16ec1119bad1f0677cb5297b Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Mon, 12 Sep 2022 14:09:17 -0400 Subject: [PATCH 04/15] fix: run new spv tests --- .github/workflows/bitcoin-tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/bitcoin-tests.yml b/.github/workflows/bitcoin-tests.yml index e5eaf030f..d37e1f5a5 100644 --- a/.github/workflows/bitcoin-tests.yml +++ b/.github/workflows/bitcoin-tests.yml @@ -68,6 +68,8 @@ jobs: - tests::neon_integrations::fuzzed_median_fee_rate_estimation_test_window10 - tests::neon_integrations::use_latest_tip_integration_test - tests::neon_integrations::test_flash_block_skip_tenure + - tests::neon_integrations::test_chainwork_first_intervals + - tests::neon_integrations::test_chainwork_partial_interval - tests::epoch_205::test_dynamic_db_method_costs - tests::epoch_205::transition_empty_blocks - tests::epoch_205::test_cost_limit_switch_version205 From 7ea9baf18b42dd1d4fddcda1c995fac6036ca7c9 Mon Sep 17 00:00:00 2001 From: Pavitthra Pandurangan Date: Mon, 19 Sep 2022 11:14:57 -0400 Subject: [PATCH 05/15] implement replace-at --- .../src/vm/analysis/arithmetic_checker/mod.rs | 2 +- .../vm/analysis/arithmetic_checker/tests.rs | 6 + .../src/vm/analysis/read_only_checker/mod.rs | 2 +- .../vm/analysis/read_only_checker/tests.rs | 4 + .../vm/analysis/type_checker/natives/mod.rs | 1 + .../type_checker/natives/sequences.rs | 25 ++ .../src/vm/analysis/type_checker/tests/mod.rs | 201 +++++++++++++ clarity/src/vm/docs/mod.rs | 22 ++ clarity/src/vm/functions/mod.rs | 2 + clarity/src/vm/functions/sequences.rs | 79 +++++ clarity/src/vm/tests/sequences.rs | 274 ++++++++++++++++++ clarity/src/vm/types/signatures.rs | 7 + src/clarity_vm/tests/costs.rs | 1 + 13 files changed, 624 insertions(+), 2 deletions(-) diff --git a/clarity/src/vm/analysis/arithmetic_checker/mod.rs b/clarity/src/vm/analysis/arithmetic_checker/mod.rs index 42a5d1d60..582cc722c 100644 --- a/clarity/src/vm/analysis/arithmetic_checker/mod.rs +++ b/clarity/src/vm/analysis/arithmetic_checker/mod.rs @@ -185,7 +185,7 @@ impl<'a> ArithmeticOnlyChecker<'a> { return Err(Error::FunctionNotPermitted(function)); } Append | Concat | AsMaxLen | ContractOf | PrincipalOf | ListCons | Print - | AsContract | ElementAt | IndexOf | Map | Filter | Fold | Slice => { + | AsContract | ElementAt | IndexOf | Map | Filter | Fold | Slice | ReplaceAt => { return Err(Error::FunctionNotPermitted(function)); } BuffToIntLe | BuffToUIntLe | BuffToIntBe | BuffToUIntBe => { diff --git a/clarity/src/vm/analysis/arithmetic_checker/tests.rs b/clarity/src/vm/analysis/arithmetic_checker/tests.rs index cfc690ce6..25a365af9 100644 --- a/clarity/src/vm/analysis/arithmetic_checker/tests.rs +++ b/clarity/src/vm/analysis/arithmetic_checker/tests.rs @@ -290,6 +290,9 @@ fn test_functions_clarity1() { ("(define-private (foo (a (list 3 uint))) (slice a u2 u3))", Ok(())), + ("(define-private (foo (a (list 3 uint)) (b uint)) + (replace-at a u1 b))", + Ok(())), ]; for (contract, result) in tests.iter() { @@ -318,6 +321,9 @@ fn test_functions_clarity2() { ("(define-private (foo (a (list 3 uint))) (slice a u2 u3))", Err(FunctionNotPermitted(NativeFunctions::Slice))), + ("(define-private (foo (a (list 3 uint))) + (replace-at a u2 (list u3)))", + Err(FunctionNotPermitted(NativeFunctions::ReplaceAt))), // Clarity1 functions. ("(define-private (foo) (at-block 0x0202020202020202020202020202020202020202020202020202020202020202 (+ 1 2)))", diff --git a/clarity/src/vm/analysis/read_only_checker/mod.rs b/clarity/src/vm/analysis/read_only_checker/mod.rs index 947a5e289..1eeb075cd 100644 --- a/clarity/src/vm/analysis/read_only_checker/mod.rs +++ b/clarity/src/vm/analysis/read_only_checker/mod.rs @@ -286,7 +286,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { | AsMaxLen | ContractOf | PrincipalOf | ListCons | GetBlockInfo | GetBurnBlockInfo | TupleGet | TupleMerge | Len | Print | AsContract | Begin | FetchVar | GetStxBalance | StxGetAccount | GetTokenBalance | GetAssetOwner | GetTokenSupply - | ElementAt | IndexOf | Slice => { + | ElementAt | IndexOf | Slice | ReplaceAt => { // Check all arguments. self.check_each_expression_is_read_only(args) } diff --git a/clarity/src/vm/analysis/read_only_checker/tests.rs b/clarity/src/vm/analysis/read_only_checker/tests.rs index 24c946a6d..a1eae73b4 100644 --- a/clarity/src/vm/analysis/read_only_checker/tests.rs +++ b/clarity/src/vm/analysis/read_only_checker/tests.rs @@ -158,6 +158,10 @@ fn test_simple_read_only_violations() { (define-private (func1) (begin (map-set tokens (tuple (account tx-sender)) (tuple (balance 10))) (list 1 2))) (define-read-only (not-reading-only) (concat (func1) (func1)))", + "(define-map tokens { account: principal } { balance: int }) + (define-private (func1) (begin (map-set tokens (tuple (account tx-sender)) (tuple (balance 10))) (list 1 2))) + (define-read-only (not-reading-only) + (replace-at (func1) u0 3))", "(define-map tokens { account: principal } { balance: int }) (define-private (func1) (begin (map-set tokens (tuple (account tx-sender)) (tuple (balance 10))) (list 1 2))) (define-read-only (not-reading-only) diff --git a/clarity/src/vm/analysis/type_checker/natives/mod.rs b/clarity/src/vm/analysis/type_checker/natives/mod.rs index 444bd4575..0fde0baec 100644 --- a/clarity/src/vm/analysis/type_checker/natives/mod.rs +++ b/clarity/src/vm/analysis/type_checker/natives/mod.rs @@ -850,6 +850,7 @@ impl TypedNativeFunction { ElementAt => Special(SpecialNativeFunction(&sequences::check_special_element_at)), IndexOf => Special(SpecialNativeFunction(&sequences::check_special_index_of)), Slice => Special(SpecialNativeFunction(&sequences::check_special_slice)), + ReplaceAt => Special(SpecialNativeFunction(&sequences::check_special_replace_at)), ListCons => Special(SpecialNativeFunction(&check_special_list_cons)), FetchEntry => Special(SpecialNativeFunction(&maps::check_special_fetch_entry)), SetEntry => Special(SpecialNativeFunction(&maps::check_special_set_entry)), diff --git a/clarity/src/vm/analysis/type_checker/natives/sequences.rs b/clarity/src/vm/analysis/type_checker/natives/sequences.rs index b6fba58c5..38e7252a3 100644 --- a/clarity/src/vm/analysis/type_checker/natives/sequences.rs +++ b/clarity/src/vm/analysis/type_checker/natives/sequences.rs @@ -423,3 +423,28 @@ pub fn check_special_slice( Ok(seq) } + +/// This function type checks the Clarity2 function `replace-at`. +pub fn check_special_replace_at( + checker: &mut TypeChecker, + args: &[SymbolicExpression], + context: &TypingContext, +) -> TypeResult { + check_argument_count(3, args)?; + + runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; + // Check sequence + let seq_type = checker.type_check(&args[0], context)?; + let unit_seq = match &seq_type { + TypeSignature::SequenceType(seq) => seq.unit_type(), + _ => return Err(CheckErrors::ExpectedSequence(seq_type).into()), + }; + + // Check index argument + checker.type_check_expects(&args[1], context, &TypeSignature::UIntType)?; + // Check element argument + let elem_type = checker.type_check(&args[2], context)?; + TypeSignature::least_supertype(&unit_seq, &elem_type)?; + + Ok(seq_type) +} diff --git a/clarity/src/vm/analysis/type_checker/tests/mod.rs b/clarity/src/vm/analysis/type_checker/tests/mod.rs index b5696c091..ed3c9fada 100644 --- a/clarity/src/vm/analysis/type_checker/tests/mod.rs +++ b/clarity/src/vm/analysis/type_checker/tests/mod.rs @@ -1455,6 +1455,207 @@ fn test_slice_utf8() { } } +#[test] +fn test_replace_at_list() { + let good = [ + "(replace-at (list 2 3 4 5 6 7 8) u0 10)", + "(replace-at (list u0 u1 u2 u3 u4) u3 u10)", + "(replace-at (list true) u0 false)", + "(replace-at (list 2 3 4 5 6 7 8) u6 10)", + "(replace-at (list (list 1) (list 2)) u0 (list 33))", + // length issues in the element will be caught at runtime + "(replace-at (list (list 1) (list 2)) u0 (list 33 44))", + ]; + let expected = [ + "(list 7 int)", + "(list 5 uint)", + "(list 1 bool)", + "(list 7 int)", + "(list 2 (list 1 int))", + "(list 2 (list 1 int))", + ]; + + for (good_test, expected) in good.iter().zip(expected.iter()) { + assert_eq!( + expected, + &format!("{}", type_check_helper(&good_test).unwrap()) + ); + } + + let bad = [ + "(replace-at (list 2 3) u0 (list 4))", + "(replace-at (list 2 3) u0 true)", + "(replace-at (list 2 3) 0 4)", + "(replace-at (list 2 3) u0 4 5)", + "(replace-at (list u0) u0)", + ]; + + let bad_expected = [ + CheckErrors::TypeError( + IntType, + SequenceType(ListType(ListTypeData::new_list(IntType, 1).unwrap())), + ), + CheckErrors::TypeError(IntType, BoolType), + CheckErrors::TypeError(UIntType, IntType), + CheckErrors::IncorrectArgumentCount(3, 4), + CheckErrors::IncorrectArgumentCount(3, 2), + ]; + for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { + assert_eq!(expected, &type_check_helper(&bad_test).unwrap_err().err); + } +} + +#[test] +fn test_replace_at_buff() { + let good = [ + "(replace-at 0x00112233 u0 0x44)", + "(replace-at 0x00112233 u3 0x66)", + "(replace-at 0x00 u0 0x22)", + "(replace-at 0x001122334455 u2 0x66)", + // length issues for the element will be found at runtime + "(replace-at 0x001122334455 u2 0x6677)", + ]; + let expected = ["(buff 4)", "(buff 4)", "(buff 1)", "(buff 6)", "(buff 6)"]; + + for (good_test, expected) in good.iter().zip(expected.iter()) { + assert_eq!( + expected, + &format!("{}", type_check_helper(&good_test).unwrap()) + ); + } + + let bad = [ + "(replace-at 0x0011 u0 (list 0))", + "(replace-at 0x0011 u0 \"a\")", + "(replace-at 0x0011 0 0x22)", + "(replace-at 0x0011 u0 0x44 0x55)", + "(replace-at 0x11 u0)", + ]; + + let buff_len = BufferLength::try_from(1u32).unwrap(); + let bad_expected = [ + CheckErrors::TypeError( + SequenceType(BufferType(buff_len.clone())), + SequenceType(ListType(ListTypeData::new_list(IntType, 1).unwrap())), + ), + CheckErrors::TypeError( + SequenceType(BufferType(buff_len.clone())), + SequenceType(StringType(ASCII(buff_len.clone()))), + ), + CheckErrors::TypeError(UIntType, IntType), + CheckErrors::IncorrectArgumentCount(3, 4), + CheckErrors::IncorrectArgumentCount(3, 2), + ]; + for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { + assert_eq!(expected, &type_check_helper(&bad_test).unwrap_err().err); + } +} + +#[test] +fn test_replace_at_ascii() { + let good = [ + "(replace-at \"abcd\" u0 \"f\")", + "(replace-at \"abcd\" u3 \"f\")", + "(replace-at \"a\" u0 \"f\")", + "(replace-at \"abcdefg\" u2 \"h\")", + // length issues for the element will be found at runtime + "(replace-at \"abcdefg\" u2 \"hi\")", + ]; + let expected = [ + "(string-ascii 4)", + "(string-ascii 4)", + "(string-ascii 1)", + "(string-ascii 7)", + "(string-ascii 7)", + ]; + + for (good_test, expected) in good.iter().zip(expected.iter()) { + assert_eq!( + expected, + &format!("{}", type_check_helper(&good_test).unwrap()) + ); + } + + let bad = [ + "(replace-at \"abcd\" u0 (list 0))", + "(replace-at \"abcd\" u0 0x00)", + "(replace-at \"abcd\" 0 \"e\")", + "(replace-at \"abcd\" u0 \"a\" \"d\")", + "(replace-at \"abcd\" u0)", + ]; + + let buff_len = BufferLength::try_from(1u32).unwrap(); + let bad_expected = [ + CheckErrors::TypeError( + SequenceType(StringType(ASCII(buff_len.clone()))), + SequenceType(ListType(ListTypeData::new_list(IntType, 1).unwrap())), + ), + CheckErrors::TypeError( + SequenceType(StringType(ASCII(buff_len.clone()))), + SequenceType(BufferType(buff_len.clone())), + ), + CheckErrors::TypeError(UIntType, IntType), + CheckErrors::IncorrectArgumentCount(3, 4), + CheckErrors::IncorrectArgumentCount(3, 2), + ]; + for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { + assert_eq!(expected, &type_check_helper(&bad_test).unwrap_err().err); + } +} + +#[test] +fn test_replace_at_utf8() { + let good = [ + "(replace-at u\"abcd\" u0 u\"f\")", + "(replace-at u\"abcd\" u3 u\"f\")", + "(replace-at u\"a\" u0 u\"f\")", + "(replace-at u\"abcdefg\" u2 u\"h\")", + // length issues for the element will be found at runtime + "(replace-at u\"abcdefg\" u2 u\"hi\")", + ]; + let expected = [ + "(string-utf8 4)", + "(string-utf8 4)", + "(string-utf8 1)", + "(string-utf8 7)", + "(string-utf8 7)", + ]; + + for (good_test, expected) in good.iter().zip(expected.iter()) { + assert_eq!( + expected, + &format!("{}", type_check_helper(&good_test).unwrap()) + ); + } + + let bad = [ + "(replace-at u\"abcd\" u0 (list 0))", + "(replace-at u\"abcd\" u0 0x00)", + "(replace-at u\"abcd\" 0 u\"a\")", + "(replace-at u\"abcd\" u0 u\"a\" u\"d\")", + "(replace-at u\"abcd\" u0)", + ]; + + let buff_len = BufferLength::try_from(1u32).unwrap(); + let str_len = StringUTF8Length::try_from(1u32).unwrap(); + let bad_expected = [ + CheckErrors::TypeError( + SequenceType(StringType(UTF8(str_len.clone()))), + SequenceType(ListType(ListTypeData::new_list(IntType, 1).unwrap())), + ), + CheckErrors::TypeError( + SequenceType(StringType(UTF8(str_len.clone()))), + SequenceType(BufferType(buff_len.clone())), + ), + CheckErrors::TypeError(UIntType, IntType), + CheckErrors::IncorrectArgumentCount(3, 4), + CheckErrors::IncorrectArgumentCount(3, 2), + ]; + for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { + assert_eq!(expected, &type_check_helper(&bad_test).unwrap_err().err); + } +} + #[test] fn test_native_concat() { let good = ["(concat (list 2 3) (list 4 5))"]; diff --git a/clarity/src/vm/docs/mod.rs b/clarity/src/vm/docs/mod.rs index ea12d21bc..912da403a 100644 --- a/clarity/src/vm/docs/mod.rs +++ b/clarity/src/vm/docs/mod.rs @@ -2061,6 +2061,27 @@ to deserialize the type, the method returns `none`. "#, }; +const REPLACE_AT: SpecialAPI = SpecialAPI { + input_type: "sequence_A, uint, A", + output_type: "sequence_A", + signature: "(replace-at sequence1 index element)", + description: "The `replace-at` function takes in a sequence, an index, and an element, +and returns a new sequence with the data at the index position replaced with the given element. +The given element's type must match the type of the sequence, and must correspond to a single +index of the input sequence. The return type on success is the same type as the input sequence. + +If the provided index is out of bounds, this functions returns `(err u1)`. +", + example: r#" +(replace-at (list 1) u0 10) ;; Returns (list 10) +(replace-at u"ab" u1 u"c") ;; Returns u"ac" +(replace-at 0x00112233 u2 0x44) ;; Returns 0x00114433 +(replace-at "abcd" u3 "e") ;; Returns "abce" +(replace-at (list (list 1) (list 2)) u0 (list 33)) ;; returns (list (list 33) (list 2)) +(replace-at (list 1 2) u3 4) ;; Returns (err u1) +"#, +}; + fn make_api_reference(function: &NativeFunctions) -> FunctionAPI { use crate::vm::functions::NativeFunctions::*; let name = function.get_name(); @@ -2164,6 +2185,7 @@ fn make_api_reference(function: &NativeFunctions) -> FunctionAPI { StxBurn => make_for_simple_native(&STX_BURN, &StxBurn, name), ToConsensusBuff => make_for_special(&TO_CONSENSUS_BUFF, name), FromConsensusBuff => make_for_special(&FROM_CONSENSUS_BUFF, name), + ReplaceAt => make_for_special(&REPLACE_AT, name), } } diff --git a/clarity/src/vm/functions/mod.rs b/clarity/src/vm/functions/mod.rs index 39c110720..3a8312c1a 100644 --- a/clarity/src/vm/functions/mod.rs +++ b/clarity/src/vm/functions/mod.rs @@ -172,6 +172,7 @@ define_versioned_named_enum!(NativeFunctions(ClarityVersion) { Slice("slice", ClarityVersion::Clarity2), ToConsensusBuff("to-consensus-buff", ClarityVersion::Clarity2), FromConsensusBuff("from-consensus-buff", ClarityVersion::Clarity2), + ReplaceAt("replace-at", ClarityVersion::Clarity2), }); impl NativeFunctions { @@ -515,6 +516,7 @@ pub fn lookup_reserved_functions(name: &str, version: &ClarityVersion) -> Option FromConsensusBuff => { SpecialFunction("from_consensus_buff", &conversions::from_consensus_buff) } + ReplaceAt => SpecialFunction("replace_at", &sequences::special_replace_at), }; Some(callable) } else { diff --git a/clarity/src/vm/functions/sequences.rs b/clarity/src/vm/functions/sequences.rs index 030ff59e1..94f252432 100644 --- a/clarity/src/vm/functions/sequences.rs +++ b/clarity/src/vm/functions/sequences.rs @@ -383,3 +383,82 @@ pub fn special_slice( }?; Ok(sliced_seq) } + +pub fn special_replace_at( + args: &[SymbolicExpression], + env: &mut Environment, + context: &LocalContext, +) -> Result { + check_argument_count(3, args)?; + + let seq = eval(&args[0], env, context)?; + let seq_type = TypeSignature::type_of(&seq); + let (expected_elem_type, seq_is_list_type) = + if let TypeSignature::SequenceType(seq_subtype) = seq_type { + (seq_subtype.unit_type(), seq_subtype.is_list_type()) + } else { + return Err(RuntimeErrorType::BadTypeConstruction.into()); + }; + let index = eval(&args[1], env, context)?; + let new_element = eval(&args[2], env, context)?; + + if expected_elem_type != TypeSignature::NoType && !expected_elem_type.admits(&new_element) { + return Err(RuntimeErrorType::BadTypeConstruction.into()); + } + + match (seq, index) { + // todo: update the ClarityCostFunction once the Clarity2 related cost functions are implemented. + (Value::Sequence(seq), Value::UInt(index)) => { + let seq_len = seq.len(); + runtime_cost(ClarityCostFunction::Unimplemented, env, seq_len as u64)?; + + let index = match u32::try_from(index) { + Ok(index) => index as usize, + _ => return Ok(Value::err_uint(1)), + }; + + // check that the index is in bounds + if index >= seq_len { + return Ok(Value::err_uint(1)); + } + + let left_seq_value = seq.clone().slice(0, index)?; + let right_seq_value = seq.slice(index + 1, seq_len)?; + match (left_seq_value, right_seq_value) { + (Value::Sequence(mut left_seq), Value::Sequence(mut right_seq)) => { + let mut elem_seq_data = if !seq_is_list_type { + match new_element { + Value::Sequence(new_element) => { + // check that the element has length 1 + if new_element.len() != 1 { + return Err(RuntimeErrorType::BadTypeConstruction.into()); + } + + new_element + } + _ => return Err(RuntimeErrorType::BadTypeConstruction.into()), + } + } + // This is the list case + else { + if let Value::Sequence(seq_data) = Value::list_from(vec![new_element])? { + seq_data + } else { + return Err(RuntimeErrorType::BadTypeConstruction.into()); + } + }; + + left_seq.append(&mut elem_seq_data)?; + left_seq.append(&mut right_seq)?; + Ok(Value::Sequence(left_seq)) + } + _ => return Err(RuntimeErrorType::BadTypeConstruction.into()), + } + } + _ => { + // todo: update the ClarityCostFunction once the Clarity2 related cost functions are implemented. + runtime_cost(ClarityCostFunction::Unimplemented, env, 0)?; + return Err(RuntimeErrorType::BadTypeConstruction.into()); + } + } +} diff --git a/clarity/src/vm/tests/sequences.rs b/clarity/src/vm/tests/sequences.rs index aed20ddfb..3c88a43eb 100644 --- a/clarity/src/vm/tests/sequences.rs +++ b/clarity/src/vm/tests/sequences.rs @@ -24,6 +24,7 @@ use rstest_reuse::{self, *}; use crate::vm::analysis::errors::CheckError; use crate::vm::errors::{CheckErrors, Error, RuntimeErrorType}; +use crate::vm::types::signatures::SequenceSubtype::ListType; use crate::vm::{execute, execute_v2, ClarityVersion}; use stacks_common::types::StacksEpochId; use std::convert::TryInto; @@ -637,6 +638,279 @@ fn test_simple_buff_concat() { ); } +#[test] +fn test_simple_list_replace_at() { + let tests = [ + "(replace-at (list 1 2) u1 4)", + "(replace-at (list 1) u0 10)", + "(replace-at (list 1 9 0 5) u3 6)", + "(replace-at (list 4 5 6 7 8) u2 11)", + "(replace-at (list (list 1) (list 2)) u0 (list 33))", + ]; + + let expected = [ + Value::list_from(vec![Value::Int(1), Value::Int(4)]).unwrap(), + Value::list_from(vec![Value::Int(10)]).unwrap(), + Value::list_from(vec![ + Value::Int(1), + Value::Int(9), + Value::Int(0), + Value::Int(6), + ]) + .unwrap(), + Value::list_from(vec![ + Value::Int(4), + Value::Int(5), + Value::Int(11), + Value::Int(7), + Value::Int(8), + ]) + .unwrap(), + Value::list_from(vec![ + Value::list_from(vec![Value::Int(33)]).unwrap(), + Value::list_from(vec![Value::Int(2)]).unwrap(), + ]) + .unwrap(), + ]; + + for (test, expected) in tests.iter().zip(expected.iter()) { + assert_eq!(expected.clone(), execute_v2(test).unwrap().unwrap()); + } + + let bad_tests = [ + // index is out of bounds + "(replace-at (list 1 2) u3 4)", + // the sequence is length 0, so the index is out of bounds + "(replace-at (list) u0 6)", + ]; + + let bad_expected = [Value::err_uint(1), Value::err_uint(1)]; + + for (bad_test, bad_expected) in bad_tests.iter().zip(bad_expected.iter()) { + assert_eq!(bad_expected.clone(), execute_v2(bad_test).unwrap().unwrap()); + } + + // The sequence input has the wrong type + assert_eq!( + execute_v2("(replace-at 0 u0 (list 0))").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The type of the index should be uint. + assert_eq!( + execute_v2("(replace-at (list 1) 0 (list 0))").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at (list 2 3) u0 true)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at (list 2 3) u0 0x00)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); +} + +#[test] +fn test_simple_buff_replace_at() { + let tests = [ + "(replace-at 0x3031 u1 0x44)", + "(replace-at 0x00 u0 0x11)", + "(replace-at 0x00112233 u3 0x44)", + "(replace-at 0x00112233 u1 0x44)", + ]; + + let expected = [ + Value::buff_from(vec![48, 68]).unwrap(), + Value::buff_from(vec![17]).unwrap(), + Value::buff_from(vec![0, 17, 34, 68]).unwrap(), + Value::buff_from(vec![0, 68, 34, 51]).unwrap(), + ]; + + for (test, expected) in tests.iter().zip(expected.iter()) { + assert_eq!(expected.clone(), execute_v2(test).unwrap().unwrap()); + } + + let bad_tests = [ + // index is out of bounds + "(replace-at 0x0022 u3 0x44)", + // the sequence is length 0, so the index is out of bounds + "(replace-at 0x u0 0x11)", + ]; + + let bad_expected = [Value::err_uint(1), Value::err_uint(1)]; + + for (bad_test, bad_expected) in bad_tests.iter().zip(bad_expected.iter()) { + assert_eq!(bad_expected.clone(), execute_v2(bad_test).unwrap().unwrap()); + } + + // The sequence input has the wrong type + assert_eq!( + execute_v2("(replace-at 33 u0 0x00)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The type of the index should be uint. + assert_eq!( + execute_v2("(replace-at 0x002244 0 0x99)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at 0x445522 u0 55)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at 0x445522 u0 (list 5))").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type (not length 1) + assert_eq!( + execute_v2("(replace-at 0x445522 u0 0x0044)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); +} + +#[test] +fn test_simple_string_ascii_replace_at() { + let tests = [ + "(replace-at \"ab\" u1 \"c\")", + "(replace-at \"a\" u0 \"c\")", + "(replace-at \"abcd\" u3 \"e\")", + "(replace-at \"abcd\" u1 \"e\")", + ]; + + let expected = [ + Value::string_ascii_from_bytes("ac".into()).unwrap(), + Value::string_ascii_from_bytes("c".into()).unwrap(), + Value::string_ascii_from_bytes("abce".into()).unwrap(), + Value::string_ascii_from_bytes("aecd".into()).unwrap(), + ]; + + for (test, expected) in tests.iter().zip(expected.iter()) { + assert_eq!(expected.clone(), execute_v2(test).unwrap().unwrap()); + } + + let bad_tests = [ + // index is out of bounds + "(replace-at \"ab\" u3 \"c\")", + // the sequence is length 0, so the index is out of bounds + "(replace-at \"\" u0 \"a\")", + ]; + + let bad_expected = [Value::err_uint(1), Value::err_uint(1)]; + + for (bad_test, bad_expected) in bad_tests.iter().zip(bad_expected.iter()) { + assert_eq!(bad_expected.clone(), execute_v2(bad_test).unwrap().unwrap()); + } + + // The sequence input has the wrong type + assert_eq!( + execute_v2("(replace-at 33 u0 \"c\")").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The type of the index should be uint. + assert_eq!( + execute_v2("(replace-at \"abc\" 0 \"c\")").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at \"abc\" u0 55)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at \"abc\" u0 0x00)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at \"abc\" u0 \"de\")").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); +} + +#[test] +fn test_simple_string_utf8_replace_at() { + let tests = [ + "(replace-at u\"ab\" u1 u\"c\")", + "(replace-at u\"a\" u0 u\"c\")", + "(replace-at u\"abcd\" u3 u\"e\")", + "(replace-at u\"abcd\" u1 u\"e\")", + "(replace-at u\"hello\\u{1F98A}\" u5 u\"e\")", + "(replace-at u\"hello\\u{1F98A}\" u2 u\"e\")", + ]; + + let expected = [ + Value::string_utf8_from_bytes("ac".into()).unwrap(), + Value::string_utf8_from_bytes("c".into()).unwrap(), + Value::string_utf8_from_bytes("abce".into()).unwrap(), + Value::string_utf8_from_bytes("aecd".into()).unwrap(), + Value::string_utf8_from_bytes("helloe".into()).unwrap(), + Value::string_utf8_from_bytes("heelo🦊".into()).unwrap(), + ]; + + for (test, expected) in tests.iter().zip(expected.iter()) { + assert_eq!(expected.clone(), execute_v2(test).unwrap().unwrap()); + } + + let bad_tests = [ + // index is out of bounds + "(replace-at u\"ab\" u3 u\"c\")", + // the sequence is length 0, so the index is out of bounds + "(replace-at u\"\" u0 u\"a\")", + ]; + + let bad_expected = [Value::err_uint(1), Value::err_uint(1)]; + + for (bad_test, bad_expected) in bad_tests.iter().zip(bad_expected.iter()) { + assert_eq!(bad_expected.clone(), execute_v2(bad_test).unwrap().unwrap()); + } + + // The sequence input has the wrong type + assert_eq!( + execute_v2("(replace-at 33 u0 u\"c\")").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The type of the index should be uint. + assert_eq!( + execute_v2("(replace-at u\"abc\" 0 u\"c\")").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at u\"abc\" u0 55)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at u\"abc\" u0 0x00)").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); + + // The element input has the wrong type + assert_eq!( + execute_v2("(replace-at u\"abc\" u0 u\"de\")").unwrap_err(), + RuntimeErrorType::BadTypeConstruction.into() + ); +} + #[test] fn test_simple_buff_assert_max_len() { let tests = [ diff --git a/clarity/src/vm/types/signatures.rs b/clarity/src/vm/types/signatures.rs index ee5731dd0..ac08581fa 100644 --- a/clarity/src/vm/types/signatures.rs +++ b/clarity/src/vm/types/signatures.rs @@ -114,6 +114,13 @@ impl SequenceSubtype { SequenceSubtype::StringType(StringSubtype::UTF8(_)) => TypeSignature::min_string_utf8(), } } + + pub fn is_list_type(&self) -> bool { + match &self { + SequenceSubtype::ListType(_) => true, + _ => false, + } + } } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] diff --git a/src/clarity_vm/tests/costs.rs b/src/clarity_vm/tests/costs.rs index 764f24fb0..612ec4166 100644 --- a/src/clarity_vm/tests/costs.rs +++ b/src/clarity_vm/tests/costs.rs @@ -159,6 +159,7 @@ pub fn get_simple_test(function: &NativeFunctions) -> &'static str { Slice => "(slice str-foo u1 u1)", ToConsensusBuff => "(to-consensus-buff u1)", FromConsensusBuff => "(from-consensus-buff bool 0x03)", + ReplaceAt => "(replace-at list-foo 0 false)", } } From e632d7a9dd943381e07e6e796180ad0355741fe0 Mon Sep 17 00:00:00 2001 From: Pavitthra Pandurangan Date: Fri, 23 Sep 2022 18:05:09 -0400 Subject: [PATCH 06/15] updates to typing --- .../type_checker/natives/sequences.rs | 16 +- .../src/vm/analysis/type_checker/tests/mod.rs | 68 +++++--- clarity/src/vm/docs/mod.rs | 15 +- clarity/src/vm/functions/sequences.rs | 22 ++- clarity/src/vm/tests/sequences.rs | 160 ++++++++++++------ 5 files changed, 177 insertions(+), 104 deletions(-) diff --git a/clarity/src/vm/analysis/type_checker/natives/sequences.rs b/clarity/src/vm/analysis/type_checker/natives/sequences.rs index 38e7252a3..67ee01999 100644 --- a/clarity/src/vm/analysis/type_checker/natives/sequences.rs +++ b/clarity/src/vm/analysis/type_checker/natives/sequences.rs @@ -434,17 +434,17 @@ pub fn check_special_replace_at( runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; // Check sequence - let seq_type = checker.type_check(&args[0], context)?; - let unit_seq = match &seq_type { - TypeSignature::SequenceType(seq) => seq.unit_type(), - _ => return Err(CheckErrors::ExpectedSequence(seq_type).into()), + let input_type = checker.type_check(&args[0], context)?; + let seq_type = match input_type.clone() { + TypeSignature::SequenceType(seq) => seq, + _ => return Err(CheckErrors::ExpectedSequence(input_type).into()), }; - + let unit_seq = seq_type.unit_type(); // Check index argument checker.type_check_expects(&args[1], context, &TypeSignature::UIntType)?; // Check element argument - let elem_type = checker.type_check(&args[2], context)?; - TypeSignature::least_supertype(&unit_seq, &elem_type)?; + checker.type_check_expects(&args[2], context, &unit_seq)?; - Ok(seq_type) + let final_type = TypeSignature::new_response(input_type, TypeSignature::UIntType)?; + Ok(final_type) } diff --git a/clarity/src/vm/analysis/type_checker/tests/mod.rs b/clarity/src/vm/analysis/type_checker/tests/mod.rs index ed3c9fada..826c3ff09 100644 --- a/clarity/src/vm/analysis/type_checker/tests/mod.rs +++ b/clarity/src/vm/analysis/type_checker/tests/mod.rs @@ -1463,16 +1463,13 @@ fn test_replace_at_list() { "(replace-at (list true) u0 false)", "(replace-at (list 2 3 4 5 6 7 8) u6 10)", "(replace-at (list (list 1) (list 2)) u0 (list 33))", - // length issues in the element will be caught at runtime - "(replace-at (list (list 1) (list 2)) u0 (list 33 44))", ]; let expected = [ - "(list 7 int)", - "(list 5 uint)", - "(list 1 bool)", - "(list 7 int)", - "(list 2 (list 1 int))", - "(list 2 (list 1 int))", + "(response (list 7 int) uint)", + "(response (list 5 uint) uint)", + "(response (list 1 bool) uint)", + "(response (list 7 int) uint)", + "(response (list 2 (list 1 int)) uint)", ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1488,6 +1485,7 @@ fn test_replace_at_list() { "(replace-at (list 2 3) 0 4)", "(replace-at (list 2 3) u0 4 5)", "(replace-at (list u0) u0)", + "(replace-at (list (list 1) (list 2)) u0 (list 33 44))", ]; let bad_expected = [ @@ -1499,6 +1497,10 @@ fn test_replace_at_list() { CheckErrors::TypeError(UIntType, IntType), CheckErrors::IncorrectArgumentCount(3, 4), CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrors::TypeError( + SequenceType(ListType(ListTypeData::new_list(IntType, 1).unwrap())), + SequenceType(ListType(ListTypeData::new_list(IntType, 2).unwrap())), + ), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(expected, &type_check_helper(&bad_test).unwrap_err().err); @@ -1512,10 +1514,13 @@ fn test_replace_at_buff() { "(replace-at 0x00112233 u3 0x66)", "(replace-at 0x00 u0 0x22)", "(replace-at 0x001122334455 u2 0x66)", - // length issues for the element will be found at runtime - "(replace-at 0x001122334455 u2 0x6677)", ]; - let expected = ["(buff 4)", "(buff 4)", "(buff 1)", "(buff 6)", "(buff 6)"]; + let expected = [ + "(response (buff 4) uint)", + "(response (buff 4) uint)", + "(response (buff 1) uint)", + "(response (buff 6) uint)", + ]; for (good_test, expected) in good.iter().zip(expected.iter()) { assert_eq!( @@ -1530,9 +1535,11 @@ fn test_replace_at_buff() { "(replace-at 0x0011 0 0x22)", "(replace-at 0x0011 u0 0x44 0x55)", "(replace-at 0x11 u0)", + "(replace-at 0x001122334455 u2 0x6677)", ]; let buff_len = BufferLength::try_from(1u32).unwrap(); + let buff_len_two = BufferLength::try_from(2u32).unwrap(); let bad_expected = [ CheckErrors::TypeError( SequenceType(BufferType(buff_len.clone())), @@ -1545,6 +1552,10 @@ fn test_replace_at_buff() { CheckErrors::TypeError(UIntType, IntType), CheckErrors::IncorrectArgumentCount(3, 4), CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrors::TypeError( + SequenceType(BufferType(buff_len.clone())), + SequenceType(BufferType(buff_len_two.clone())), + ), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(expected, &type_check_helper(&bad_test).unwrap_err().err); @@ -1558,15 +1569,13 @@ fn test_replace_at_ascii() { "(replace-at \"abcd\" u3 \"f\")", "(replace-at \"a\" u0 \"f\")", "(replace-at \"abcdefg\" u2 \"h\")", - // length issues for the element will be found at runtime - "(replace-at \"abcdefg\" u2 \"hi\")", ]; let expected = [ - "(string-ascii 4)", - "(string-ascii 4)", - "(string-ascii 1)", - "(string-ascii 7)", - "(string-ascii 7)", + "(response (string-ascii 4) uint)", + "(response (string-ascii 4) uint)", + "(response (string-ascii 1) uint)", + "(response (string-ascii 7) uint)", + "(response (string-ascii 7) uint)", ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1582,9 +1591,11 @@ fn test_replace_at_ascii() { "(replace-at \"abcd\" 0 \"e\")", "(replace-at \"abcd\" u0 \"a\" \"d\")", "(replace-at \"abcd\" u0)", + "(replace-at \"abcdefg\" u2 \"hi\")", ]; let buff_len = BufferLength::try_from(1u32).unwrap(); + let buff_len_two = BufferLength::try_from(2u32).unwrap(); let bad_expected = [ CheckErrors::TypeError( SequenceType(StringType(ASCII(buff_len.clone()))), @@ -1597,6 +1608,10 @@ fn test_replace_at_ascii() { CheckErrors::TypeError(UIntType, IntType), CheckErrors::IncorrectArgumentCount(3, 4), CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrors::TypeError( + SequenceType(StringType(ASCII(buff_len.clone()))), + SequenceType(StringType(ASCII(buff_len_two.clone()))), + ), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(expected, &type_check_helper(&bad_test).unwrap_err().err); @@ -1610,15 +1625,12 @@ fn test_replace_at_utf8() { "(replace-at u\"abcd\" u3 u\"f\")", "(replace-at u\"a\" u0 u\"f\")", "(replace-at u\"abcdefg\" u2 u\"h\")", - // length issues for the element will be found at runtime - "(replace-at u\"abcdefg\" u2 u\"hi\")", ]; let expected = [ - "(string-utf8 4)", - "(string-utf8 4)", - "(string-utf8 1)", - "(string-utf8 7)", - "(string-utf8 7)", + "(response (string-utf8 4) uint)", + "(response (string-utf8 4) uint)", + "(response (string-utf8 1) uint)", + "(response (string-utf8 7) uint)", ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1634,10 +1646,12 @@ fn test_replace_at_utf8() { "(replace-at u\"abcd\" 0 u\"a\")", "(replace-at u\"abcd\" u0 u\"a\" u\"d\")", "(replace-at u\"abcd\" u0)", + "(replace-at u\"abcdefg\" u2 u\"hi\")", ]; let buff_len = BufferLength::try_from(1u32).unwrap(); let str_len = StringUTF8Length::try_from(1u32).unwrap(); + let str_len_two = StringUTF8Length::try_from(2u32).unwrap(); let bad_expected = [ CheckErrors::TypeError( SequenceType(StringType(UTF8(str_len.clone()))), @@ -1650,6 +1664,10 @@ fn test_replace_at_utf8() { CheckErrors::TypeError(UIntType, IntType), CheckErrors::IncorrectArgumentCount(3, 4), CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrors::TypeError( + SequenceType(StringType(UTF8(str_len.clone()))), + SequenceType(StringType(UTF8(str_len_two.clone()))), + ), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(expected, &type_check_helper(&bad_test).unwrap_err().err); diff --git a/clarity/src/vm/docs/mod.rs b/clarity/src/vm/docs/mod.rs index 83acb40b8..edc47b56d 100644 --- a/clarity/src/vm/docs/mod.rs +++ b/clarity/src/vm/docs/mod.rs @@ -2191,8 +2191,9 @@ to deserialize the type, the method returns `none`. const REPLACE_AT: SpecialAPI = SpecialAPI { input_type: "sequence_A, uint, A", - output_type: "sequence_A", - signature: "(replace-at sequence1 index element)", + output_type: "(response sequence_A uint)", + snippet: "replace-at ${1:sequence} ${2:index} ${3:element}", + signature: "(replace-at sequence index element)", description: "The `replace-at` function takes in a sequence, an index, and an element, and returns a new sequence with the data at the index position replaced with the given element. The given element's type must match the type of the sequence, and must correspond to a single @@ -2201,11 +2202,11 @@ index of the input sequence. The return type on success is the same type as the If the provided index is out of bounds, this functions returns `(err u1)`. ", example: r#" -(replace-at (list 1) u0 10) ;; Returns (list 10) -(replace-at u"ab" u1 u"c") ;; Returns u"ac" -(replace-at 0x00112233 u2 0x44) ;; Returns 0x00114433 -(replace-at "abcd" u3 "e") ;; Returns "abce" -(replace-at (list (list 1) (list 2)) u0 (list 33)) ;; returns (list (list 33) (list 2)) +(replace-at u"ab" u1 u"c") ;; Returns (ok u"ac") +(replace-at 0x00112233 u2 0x44) ;; Returns (ok 0x00114433) +(replace-at "abcd" u3 "e") ;; Returns (ok "abce") +(replace-at (list 1) u0 10) ;; Returns (ok (10)) +(replace-at (list (list 1) (list 2)) u0 (list 33)) ;; Returns (ok ((33) (2))) (replace-at (list 1 2) u3 4) ;; Returns (err u1) "#, }; diff --git a/clarity/src/vm/functions/sequences.rs b/clarity/src/vm/functions/sequences.rs index 94f252432..b6517985a 100644 --- a/clarity/src/vm/functions/sequences.rs +++ b/clarity/src/vm/functions/sequences.rs @@ -394,21 +394,27 @@ pub fn special_replace_at( let seq = eval(&args[0], env, context)?; let seq_type = TypeSignature::type_of(&seq); let (expected_elem_type, seq_is_list_type) = - if let TypeSignature::SequenceType(seq_subtype) = seq_type { + if let TypeSignature::SequenceType(seq_subtype) = seq_type.clone() { (seq_subtype.unit_type(), seq_subtype.is_list_type()) } else { - return Err(RuntimeErrorType::BadTypeConstruction.into()); + return Err(CheckErrors::ExpectedSequence(seq_type).into()); }; - let index = eval(&args[1], env, context)?; + let index_val = eval(&args[1], env, context)?; let new_element = eval(&args[2], env, context)?; if expected_elem_type != TypeSignature::NoType && !expected_elem_type.admits(&new_element) { - return Err(RuntimeErrorType::BadTypeConstruction.into()); + return Err(CheckErrors::TypeValueError(expected_elem_type, new_element).into()); } - match (seq, index) { + let index = if let Value::UInt(index) = index_val { + index + } else { + return Err(CheckErrors::TypeValueError(TypeSignature::UIntType, index_val).into()); + }; + + match seq { // todo: update the ClarityCostFunction once the Clarity2 related cost functions are implemented. - (Value::Sequence(seq), Value::UInt(index)) => { + Value::Sequence(seq) => { let seq_len = seq.len(); runtime_cost(ClarityCostFunction::Unimplemented, env, seq_len as u64)?; @@ -450,7 +456,7 @@ pub fn special_replace_at( left_seq.append(&mut elem_seq_data)?; left_seq.append(&mut right_seq)?; - Ok(Value::Sequence(left_seq)) + Ok(Value::okay(Value::Sequence(left_seq))?) } _ => return Err(RuntimeErrorType::BadTypeConstruction.into()), } @@ -458,7 +464,7 @@ pub fn special_replace_at( _ => { // todo: update the ClarityCostFunction once the Clarity2 related cost functions are implemented. runtime_cost(ClarityCostFunction::Unimplemented, env, 0)?; - return Err(RuntimeErrorType::BadTypeConstruction.into()); + return Err(CheckErrors::ExpectedSequence(seq_type).into()); } } } diff --git a/clarity/src/vm/tests/sequences.rs b/clarity/src/vm/tests/sequences.rs index 3c88a43eb..59d8def54 100644 --- a/clarity/src/vm/tests/sequences.rs +++ b/clarity/src/vm/tests/sequences.rs @@ -16,7 +16,7 @@ use crate::vm::types::signatures::{ListTypeData, SequenceSubtype}; use crate::vm::types::TypeSignature::{BoolType, IntType, SequenceType, UIntType}; -use crate::vm::types::{TypeSignature, Value}; +use crate::vm::types::{StringSubtype, StringUTF8Length, TypeSignature, Value}; #[cfg(test)] use rstest::rstest; #[cfg(test)] @@ -24,10 +24,13 @@ use rstest_reuse::{self, *}; use crate::vm::analysis::errors::CheckError; use crate::vm::errors::{CheckErrors, Error, RuntimeErrorType}; -use crate::vm::types::signatures::SequenceSubtype::ListType; +use crate::vm::types::signatures::SequenceSubtype::{BufferType, ListType, StringType}; +use crate::vm::types::signatures::StringSubtype::ASCII; +use crate::vm::types::BufferLength; +use crate::vm::types::CharType::UTF8; use crate::vm::{execute, execute_v2, ClarityVersion}; use stacks_common::types::StacksEpochId; -use std::convert::TryInto; +use std::convert::{TryFrom, TryInto}; #[template] #[rstest] @@ -649,27 +652,36 @@ fn test_simple_list_replace_at() { ]; let expected = [ - Value::list_from(vec![Value::Int(1), Value::Int(4)]).unwrap(), - Value::list_from(vec![Value::Int(10)]).unwrap(), - Value::list_from(vec![ - Value::Int(1), - Value::Int(9), - Value::Int(0), - Value::Int(6), - ]) + Value::okay(Value::list_from(vec![Value::Int(1), Value::Int(4)]).unwrap()).unwrap(), + Value::okay(Value::list_from(vec![Value::Int(10)]).unwrap()).unwrap(), + Value::okay( + Value::list_from(vec![ + Value::Int(1), + Value::Int(9), + Value::Int(0), + Value::Int(6), + ]) + .unwrap(), + ) .unwrap(), - Value::list_from(vec![ - Value::Int(4), - Value::Int(5), - Value::Int(11), - Value::Int(7), - Value::Int(8), - ]) + Value::okay( + Value::list_from(vec![ + Value::Int(4), + Value::Int(5), + Value::Int(11), + Value::Int(7), + Value::Int(8), + ]) + .unwrap(), + ) .unwrap(), - Value::list_from(vec![ - Value::list_from(vec![Value::Int(33)]).unwrap(), - Value::list_from(vec![Value::Int(2)]).unwrap(), - ]) + Value::okay( + Value::list_from(vec![ + Value::list_from(vec![Value::Int(33)]).unwrap(), + Value::list_from(vec![Value::Int(2)]).unwrap(), + ]) + .unwrap(), + ) .unwrap(), ]; @@ -693,25 +705,25 @@ fn test_simple_list_replace_at() { // The sequence input has the wrong type assert_eq!( execute_v2("(replace-at 0 u0 (list 0))").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::ExpectedSequence(IntType).into() ); // The type of the index should be uint. assert_eq!( - execute_v2("(replace-at (list 1) 0 (list 0))").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + execute_v2("(replace-at (list 1) 0 0)").unwrap_err(), + CheckErrors::TypeValueError(UIntType, Value::Int(0)).into() ); // The element input has the wrong type assert_eq!( execute_v2("(replace-at (list 2 3) u0 true)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError(IntType, Value::Bool(true)).into() ); // The element input has the wrong type assert_eq!( execute_v2("(replace-at (list 2 3) u0 0x00)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError(IntType, Value::buff_from_byte(0)).into() ); } @@ -725,10 +737,10 @@ fn test_simple_buff_replace_at() { ]; let expected = [ - Value::buff_from(vec![48, 68]).unwrap(), - Value::buff_from(vec![17]).unwrap(), - Value::buff_from(vec![0, 17, 34, 68]).unwrap(), - Value::buff_from(vec![0, 68, 34, 51]).unwrap(), + Value::okay(Value::buff_from(vec![48, 68]).unwrap()).unwrap(), + Value::okay(Value::buff_from(vec![17]).unwrap()).unwrap(), + Value::okay(Value::buff_from(vec![0, 17, 34, 68]).unwrap()).unwrap(), + Value::okay(Value::buff_from(vec![0, 68, 34, 51]).unwrap()).unwrap(), ]; for (test, expected) in tests.iter().zip(expected.iter()) { @@ -751,31 +763,41 @@ fn test_simple_buff_replace_at() { // The sequence input has the wrong type assert_eq!( execute_v2("(replace-at 33 u0 0x00)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::ExpectedSequence(IntType).into() ); // The type of the index should be uint. assert_eq!( execute_v2("(replace-at 0x002244 0 0x99)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError(UIntType, Value::Int(0)).into() ); // The element input has the wrong type + let buff_len = BufferLength::try_from(1u32).unwrap(); assert_eq!( execute_v2("(replace-at 0x445522 u0 55)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError(SequenceType(BufferType(buff_len.clone())), Value::Int(55)) + .into() ); // The element input has the wrong type assert_eq!( execute_v2("(replace-at 0x445522 u0 (list 5))").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError( + SequenceType(BufferType(buff_len.clone())), + Value::list_from(vec![Value::Int(5)]).unwrap() + ) + .into() ); // The element input has the wrong type (not length 1) assert_eq!( execute_v2("(replace-at 0x445522 u0 0x0044)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError( + SequenceType(BufferType(buff_len.clone())), + Value::buff_from(vec![0, 68]).unwrap() + ) + .into() ); } @@ -789,10 +811,10 @@ fn test_simple_string_ascii_replace_at() { ]; let expected = [ - Value::string_ascii_from_bytes("ac".into()).unwrap(), - Value::string_ascii_from_bytes("c".into()).unwrap(), - Value::string_ascii_from_bytes("abce".into()).unwrap(), - Value::string_ascii_from_bytes("aecd".into()).unwrap(), + Value::okay(Value::string_ascii_from_bytes("ac".into()).unwrap()).unwrap(), + Value::okay(Value::string_ascii_from_bytes("c".into()).unwrap()).unwrap(), + Value::okay(Value::string_ascii_from_bytes("abce".into()).unwrap()).unwrap(), + Value::okay(Value::string_ascii_from_bytes("aecd".into()).unwrap()).unwrap(), ]; for (test, expected) in tests.iter().zip(expected.iter()) { @@ -815,31 +837,44 @@ fn test_simple_string_ascii_replace_at() { // The sequence input has the wrong type assert_eq!( execute_v2("(replace-at 33 u0 \"c\")").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::ExpectedSequence(IntType).into() ); // The type of the index should be uint. assert_eq!( execute_v2("(replace-at \"abc\" 0 \"c\")").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError(UIntType, Value::Int(0)).into() ); // The element input has the wrong type + let buff_len = BufferLength::try_from(1u32).unwrap(); assert_eq!( execute_v2("(replace-at \"abc\" u0 55)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError( + SequenceType(StringType(ASCII(buff_len.clone()))), + Value::Int(55) + ) + .into() ); // The element input has the wrong type assert_eq!( execute_v2("(replace-at \"abc\" u0 0x00)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError( + SequenceType(StringType(ASCII(buff_len.clone()))), + Value::buff_from_byte(0) + ) + .into() ); // The element input has the wrong type assert_eq!( execute_v2("(replace-at \"abc\" u0 \"de\")").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError( + SequenceType(StringType(ASCII(buff_len.clone()))), + Value::string_ascii_from_bytes("de".into()).unwrap() + ) + .into() ); } @@ -855,12 +890,12 @@ fn test_simple_string_utf8_replace_at() { ]; let expected = [ - Value::string_utf8_from_bytes("ac".into()).unwrap(), - Value::string_utf8_from_bytes("c".into()).unwrap(), - Value::string_utf8_from_bytes("abce".into()).unwrap(), - Value::string_utf8_from_bytes("aecd".into()).unwrap(), - Value::string_utf8_from_bytes("helloe".into()).unwrap(), - Value::string_utf8_from_bytes("heelo🦊".into()).unwrap(), + Value::okay(Value::string_utf8_from_bytes("ac".into()).unwrap()).unwrap(), + Value::okay(Value::string_utf8_from_bytes("c".into()).unwrap()).unwrap(), + Value::okay(Value::string_utf8_from_bytes("abce".into()).unwrap()).unwrap(), + Value::okay(Value::string_utf8_from_bytes("aecd".into()).unwrap()).unwrap(), + Value::okay(Value::string_utf8_from_bytes("helloe".into()).unwrap()).unwrap(), + Value::okay(Value::string_utf8_from_bytes("heelo🦊".into()).unwrap()).unwrap(), ]; for (test, expected) in tests.iter().zip(expected.iter()) { @@ -883,31 +918,44 @@ fn test_simple_string_utf8_replace_at() { // The sequence input has the wrong type assert_eq!( execute_v2("(replace-at 33 u0 u\"c\")").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::ExpectedSequence(IntType).into() ); // The type of the index should be uint. assert_eq!( execute_v2("(replace-at u\"abc\" 0 u\"c\")").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError(UIntType, Value::Int(0)).into() ); // The element input has the wrong type + let str_len = StringUTF8Length::try_from(1u32).unwrap(); assert_eq!( execute_v2("(replace-at u\"abc\" u0 55)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError( + TypeSignature::SequenceType(StringType(StringSubtype::UTF8(str_len.clone()))), + Value::Int(55) + ) + .into() ); // The element input has the wrong type assert_eq!( execute_v2("(replace-at u\"abc\" u0 0x00)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError( + TypeSignature::SequenceType(StringType(StringSubtype::UTF8(str_len.clone()))), + Value::buff_from_byte(0) + ) + .into() ); // The element input has the wrong type assert_eq!( execute_v2("(replace-at u\"abc\" u0 u\"de\")").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + CheckErrors::TypeValueError( + TypeSignature::SequenceType(StringType(StringSubtype::UTF8(str_len.clone()))), + Value::string_utf8_from_string_utf8_literal("de".to_string()).unwrap() + ) + .into() ); } From 10735d68bdca88621f7513de1edf5e4a29bde034 Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Tue, 27 Sep 2022 16:05:33 -0400 Subject: [PATCH 07/15] fix: debug statement accuracy --- src/burnchains/bitcoin/indexer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/burnchains/bitcoin/indexer.rs b/src/burnchains/bitcoin/indexer.rs index d6d2f643d..a284cff56 100644 --- a/src/burnchains/bitcoin/indexer.rs +++ b/src/burnchains/bitcoin/indexer.rs @@ -499,7 +499,7 @@ impl BitcoinIndexer { start_block ); - debug!("Copy headers 0-{}", interval_headers.len() as u64); + debug!("Copy headers 1-{}", interval_headers.len() as u64); reorg_spv_client.insert_block_headers_before(0, interval_headers)?; } From 95f8f742442ee59427526b71c971f1ba42a2a359 Mon Sep 17 00:00:00 2001 From: Pavitthra Pandurangan Date: Thu, 29 Sep 2022 18:42:31 -0400 Subject: [PATCH 08/15] Added two test cases --- .../src/vm/analysis/type_checker/tests/mod.rs | 4 ++++ clarity/src/vm/tests/sequences.rs | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/clarity/src/vm/analysis/type_checker/tests/mod.rs b/clarity/src/vm/analysis/type_checker/tests/mod.rs index 826c3ff09..a8fe20de0 100644 --- a/clarity/src/vm/analysis/type_checker/tests/mod.rs +++ b/clarity/src/vm/analysis/type_checker/tests/mod.rs @@ -1463,6 +1463,8 @@ fn test_replace_at_list() { "(replace-at (list true) u0 false)", "(replace-at (list 2 3 4 5 6 7 8) u6 10)", "(replace-at (list (list 1) (list 2)) u0 (list 33))", + "(replace-at (list (list 1 2) (list 3 4)) u0 (list 0))", + "(replace-at (list (list 1 2 3)) u0 (list 0))", ]; let expected = [ "(response (list 7 int) uint)", @@ -1470,6 +1472,8 @@ fn test_replace_at_list() { "(response (list 1 bool) uint)", "(response (list 7 int) uint)", "(response (list 2 (list 1 int)) uint)", + "(response (list 2 (list 2 int)) uint)", + "(response (list 1 (list 3 int)) uint)", ]; for (good_test, expected) in good.iter().zip(expected.iter()) { diff --git a/clarity/src/vm/tests/sequences.rs b/clarity/src/vm/tests/sequences.rs index 59d8def54..c807dbbfb 100644 --- a/clarity/src/vm/tests/sequences.rs +++ b/clarity/src/vm/tests/sequences.rs @@ -649,6 +649,8 @@ fn test_simple_list_replace_at() { "(replace-at (list 1 9 0 5) u3 6)", "(replace-at (list 4 5 6 7 8) u2 11)", "(replace-at (list (list 1) (list 2)) u0 (list 33))", + "(replace-at (list (list 1 2) (list 3 4)) u0 (list 0))", + "(replace-at (list (list 1 2 3)) u0 (list 0))", ]; let expected = [ @@ -683,6 +685,21 @@ fn test_simple_list_replace_at() { .unwrap(), ) .unwrap(), + Value::okay( + Value::list_from(vec![ + Value::list_from(vec![Value::Int(0)]).unwrap(), + Value::list_from(vec![Value::Int(3), Value::Int(4)]).unwrap(), + ]) + .unwrap(), + ) + .unwrap(), + Value::okay( + Value::list_from(vec![ + Value::list_from(vec![Value::Int(0)]).unwrap(), + ]) + .unwrap(), + ) + .unwrap(), ]; for (test, expected) in tests.iter().zip(expected.iter()) { From 4f7070ded841182732350c47894bd7cc276cd608 Mon Sep 17 00:00:00 2001 From: Pavitthra Pandurangan Date: Wed, 5 Oct 2022 15:23:28 -0400 Subject: [PATCH 09/15] Requested changes to replace-at: return optional, and make the function O(1) --- .../type_checker/natives/sequences.rs | 4 +- .../src/vm/analysis/type_checker/tests/mod.rs | 40 +++++----- clarity/src/vm/functions/sequences.rs | 80 +++++-------------- clarity/src/vm/tests/sequences.rs | 50 ++++++------ clarity/src/vm/types/mod.rs | 54 +++++++++++++ 5 files changed, 122 insertions(+), 106 deletions(-) diff --git a/clarity/src/vm/analysis/type_checker/natives/sequences.rs b/clarity/src/vm/analysis/type_checker/natives/sequences.rs index 67ee01999..73fac1946 100644 --- a/clarity/src/vm/analysis/type_checker/natives/sequences.rs +++ b/clarity/src/vm/analysis/type_checker/natives/sequences.rs @@ -435,7 +435,7 @@ pub fn check_special_replace_at( runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; // Check sequence let input_type = checker.type_check(&args[0], context)?; - let seq_type = match input_type.clone() { + let seq_type = match &input_type { TypeSignature::SequenceType(seq) => seq, _ => return Err(CheckErrors::ExpectedSequence(input_type).into()), }; @@ -445,6 +445,6 @@ pub fn check_special_replace_at( // Check element argument checker.type_check_expects(&args[2], context, &unit_seq)?; - let final_type = TypeSignature::new_response(input_type, TypeSignature::UIntType)?; + let final_type = TypeSignature::new_option(input_type)?; Ok(final_type) } diff --git a/clarity/src/vm/analysis/type_checker/tests/mod.rs b/clarity/src/vm/analysis/type_checker/tests/mod.rs index a8fe20de0..9416f6420 100644 --- a/clarity/src/vm/analysis/type_checker/tests/mod.rs +++ b/clarity/src/vm/analysis/type_checker/tests/mod.rs @@ -1467,13 +1467,13 @@ fn test_replace_at_list() { "(replace-at (list (list 1 2 3)) u0 (list 0))", ]; let expected = [ - "(response (list 7 int) uint)", - "(response (list 5 uint) uint)", - "(response (list 1 bool) uint)", - "(response (list 7 int) uint)", - "(response (list 2 (list 1 int)) uint)", - "(response (list 2 (list 2 int)) uint)", - "(response (list 1 (list 3 int)) uint)", + "(optional (list 7 int))", + "(optional (list 5 uint))", + "(optional (list 1 bool))", + "(optional (list 7 int))", + "(optional (list 2 (list 1 int)))", + "(optional (list 2 (list 2 int)))", + "(optional (list 1 (list 3 int)))", ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1520,10 +1520,10 @@ fn test_replace_at_buff() { "(replace-at 0x001122334455 u2 0x66)", ]; let expected = [ - "(response (buff 4) uint)", - "(response (buff 4) uint)", - "(response (buff 1) uint)", - "(response (buff 6) uint)", + "(optional (buff 4))", + "(optional (buff 4))", + "(optional (buff 1))", + "(optional (buff 6))", ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1575,11 +1575,11 @@ fn test_replace_at_ascii() { "(replace-at \"abcdefg\" u2 \"h\")", ]; let expected = [ - "(response (string-ascii 4) uint)", - "(response (string-ascii 4) uint)", - "(response (string-ascii 1) uint)", - "(response (string-ascii 7) uint)", - "(response (string-ascii 7) uint)", + "(optional (string-ascii 4))", + "(optional (string-ascii 4))", + "(optional (string-ascii 1))", + "(optional (string-ascii 7))", + "(optional (string-ascii 7))", ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1631,10 +1631,10 @@ fn test_replace_at_utf8() { "(replace-at u\"abcdefg\" u2 u\"h\")", ]; let expected = [ - "(response (string-utf8 4) uint)", - "(response (string-utf8 4) uint)", - "(response (string-utf8 1) uint)", - "(response (string-utf8 7) uint)", + "(optional (string-utf8 4))", + "(optional (string-utf8 4))", + "(optional (string-utf8 1))", + "(optional (string-utf8 7))", ]; for (good_test, expected) in good.iter().zip(expected.iter()) { diff --git a/clarity/src/vm/functions/sequences.rs b/clarity/src/vm/functions/sequences.rs index b6517985a..3f0817607 100644 --- a/clarity/src/vm/functions/sequences.rs +++ b/clarity/src/vm/functions/sequences.rs @@ -391,11 +391,15 @@ pub fn special_replace_at( ) -> Result { check_argument_count(3, args)?; + // todo: update the ClarityCostFunction once the Clarity2 related cost functions are implemented. + // Set the input to runtime_cost to 0, since replacing an element at an index is an O(1) operation. + runtime_cost(ClarityCostFunction::Unimplemented, env, 0)?; + let seq = eval(&args[0], env, context)?; let seq_type = TypeSignature::type_of(&seq); - let (expected_elem_type, seq_is_list_type) = - if let TypeSignature::SequenceType(seq_subtype) = seq_type.clone() { - (seq_subtype.unit_type(), seq_subtype.is_list_type()) + let expected_elem_type = + if let TypeSignature::SequenceType(seq_subtype) = &seq_type { + seq_subtype.unit_type() } else { return Err(CheckErrors::ExpectedSequence(seq_type).into()); }; @@ -405,66 +409,24 @@ pub fn special_replace_at( if expected_elem_type != TypeSignature::NoType && !expected_elem_type.admits(&new_element) { return Err(CheckErrors::TypeValueError(expected_elem_type, new_element).into()); } - - let index = if let Value::UInt(index) = index_val { - index + + let index = if let Value::UInt(index_u128) = index_val { + if let Ok(index_usize) = usize::try_from(index_u128) { + index_usize + } else { + return Ok(Value::none()); + } } else { return Err(CheckErrors::TypeValueError(TypeSignature::UIntType, index_val).into()); }; - match seq { - // todo: update the ClarityCostFunction once the Clarity2 related cost functions are implemented. - Value::Sequence(seq) => { - let seq_len = seq.len(); - runtime_cost(ClarityCostFunction::Unimplemented, env, seq_len as u64)?; - - let index = match u32::try_from(index) { - Ok(index) => index as usize, - _ => return Ok(Value::err_uint(1)), - }; - - // check that the index is in bounds - if index >= seq_len { - return Ok(Value::err_uint(1)); - } - - let left_seq_value = seq.clone().slice(0, index)?; - let right_seq_value = seq.slice(index + 1, seq_len)?; - match (left_seq_value, right_seq_value) { - (Value::Sequence(mut left_seq), Value::Sequence(mut right_seq)) => { - let mut elem_seq_data = if !seq_is_list_type { - match new_element { - Value::Sequence(new_element) => { - // check that the element has length 1 - if new_element.len() != 1 { - return Err(RuntimeErrorType::BadTypeConstruction.into()); - } - - new_element - } - _ => return Err(RuntimeErrorType::BadTypeConstruction.into()), - } - } - // This is the list case - else { - if let Value::Sequence(seq_data) = Value::list_from(vec![new_element])? { - seq_data - } else { - return Err(RuntimeErrorType::BadTypeConstruction.into()); - } - }; - - left_seq.append(&mut elem_seq_data)?; - left_seq.append(&mut right_seq)?; - Ok(Value::okay(Value::Sequence(left_seq))?) - } - _ => return Err(RuntimeErrorType::BadTypeConstruction.into()), - } - } - _ => { - // todo: update the ClarityCostFunction once the Clarity2 related cost functions are implemented. - runtime_cost(ClarityCostFunction::Unimplemented, env, 0)?; - return Err(CheckErrors::ExpectedSequence(seq_type).into()); + if let Value::Sequence(data) = seq { + let seq_len = data.len(); + if index >= seq_len { + return Ok(Value::none()) } + data.replace_at(index, new_element) + } else { + return Err(CheckErrors::ExpectedSequence(seq_type).into()); } } diff --git a/clarity/src/vm/tests/sequences.rs b/clarity/src/vm/tests/sequences.rs index c807dbbfb..b5a68946a 100644 --- a/clarity/src/vm/tests/sequences.rs +++ b/clarity/src/vm/tests/sequences.rs @@ -654,9 +654,9 @@ fn test_simple_list_replace_at() { ]; let expected = [ - Value::okay(Value::list_from(vec![Value::Int(1), Value::Int(4)]).unwrap()).unwrap(), - Value::okay(Value::list_from(vec![Value::Int(10)]).unwrap()).unwrap(), - Value::okay( + Value::some(Value::list_from(vec![Value::Int(1), Value::Int(4)]).unwrap()).unwrap(), + Value::some(Value::list_from(vec![Value::Int(10)]).unwrap()).unwrap(), + Value::some( Value::list_from(vec![ Value::Int(1), Value::Int(9), @@ -666,7 +666,7 @@ fn test_simple_list_replace_at() { .unwrap(), ) .unwrap(), - Value::okay( + Value::some( Value::list_from(vec![ Value::Int(4), Value::Int(5), @@ -677,7 +677,7 @@ fn test_simple_list_replace_at() { .unwrap(), ) .unwrap(), - Value::okay( + Value::some( Value::list_from(vec![ Value::list_from(vec![Value::Int(33)]).unwrap(), Value::list_from(vec![Value::Int(2)]).unwrap(), @@ -685,7 +685,7 @@ fn test_simple_list_replace_at() { .unwrap(), ) .unwrap(), - Value::okay( + Value::some( Value::list_from(vec![ Value::list_from(vec![Value::Int(0)]).unwrap(), Value::list_from(vec![Value::Int(3), Value::Int(4)]).unwrap(), @@ -693,7 +693,7 @@ fn test_simple_list_replace_at() { .unwrap(), ) .unwrap(), - Value::okay( + Value::some( Value::list_from(vec![ Value::list_from(vec![Value::Int(0)]).unwrap(), ]) @@ -713,7 +713,7 @@ fn test_simple_list_replace_at() { "(replace-at (list) u0 6)", ]; - let bad_expected = [Value::err_uint(1), Value::err_uint(1)]; + let bad_expected = [Value::none(), Value::none()]; for (bad_test, bad_expected) in bad_tests.iter().zip(bad_expected.iter()) { assert_eq!(bad_expected.clone(), execute_v2(bad_test).unwrap().unwrap()); @@ -754,10 +754,10 @@ fn test_simple_buff_replace_at() { ]; let expected = [ - Value::okay(Value::buff_from(vec![48, 68]).unwrap()).unwrap(), - Value::okay(Value::buff_from(vec![17]).unwrap()).unwrap(), - Value::okay(Value::buff_from(vec![0, 17, 34, 68]).unwrap()).unwrap(), - Value::okay(Value::buff_from(vec![0, 68, 34, 51]).unwrap()).unwrap(), + Value::some(Value::buff_from(vec![48, 68]).unwrap()).unwrap(), + Value::some(Value::buff_from(vec![17]).unwrap()).unwrap(), + Value::some(Value::buff_from(vec![0, 17, 34, 68]).unwrap()).unwrap(), + Value::some(Value::buff_from(vec![0, 68, 34, 51]).unwrap()).unwrap(), ]; for (test, expected) in tests.iter().zip(expected.iter()) { @@ -771,7 +771,7 @@ fn test_simple_buff_replace_at() { "(replace-at 0x u0 0x11)", ]; - let bad_expected = [Value::err_uint(1), Value::err_uint(1)]; + let bad_expected = [Value::none(), Value::none()]; for (bad_test, bad_expected) in bad_tests.iter().zip(bad_expected.iter()) { assert_eq!(bad_expected.clone(), execute_v2(bad_test).unwrap().unwrap()); @@ -828,10 +828,10 @@ fn test_simple_string_ascii_replace_at() { ]; let expected = [ - Value::okay(Value::string_ascii_from_bytes("ac".into()).unwrap()).unwrap(), - Value::okay(Value::string_ascii_from_bytes("c".into()).unwrap()).unwrap(), - Value::okay(Value::string_ascii_from_bytes("abce".into()).unwrap()).unwrap(), - Value::okay(Value::string_ascii_from_bytes("aecd".into()).unwrap()).unwrap(), + Value::some(Value::string_ascii_from_bytes("ac".into()).unwrap()).unwrap(), + Value::some(Value::string_ascii_from_bytes("c".into()).unwrap()).unwrap(), + Value::some(Value::string_ascii_from_bytes("abce".into()).unwrap()).unwrap(), + Value::some(Value::string_ascii_from_bytes("aecd".into()).unwrap()).unwrap(), ]; for (test, expected) in tests.iter().zip(expected.iter()) { @@ -845,7 +845,7 @@ fn test_simple_string_ascii_replace_at() { "(replace-at \"\" u0 \"a\")", ]; - let bad_expected = [Value::err_uint(1), Value::err_uint(1)]; + let bad_expected = [Value::none(), Value::none()]; for (bad_test, bad_expected) in bad_tests.iter().zip(bad_expected.iter()) { assert_eq!(bad_expected.clone(), execute_v2(bad_test).unwrap().unwrap()); @@ -907,12 +907,12 @@ fn test_simple_string_utf8_replace_at() { ]; let expected = [ - Value::okay(Value::string_utf8_from_bytes("ac".into()).unwrap()).unwrap(), - Value::okay(Value::string_utf8_from_bytes("c".into()).unwrap()).unwrap(), - Value::okay(Value::string_utf8_from_bytes("abce".into()).unwrap()).unwrap(), - Value::okay(Value::string_utf8_from_bytes("aecd".into()).unwrap()).unwrap(), - Value::okay(Value::string_utf8_from_bytes("helloe".into()).unwrap()).unwrap(), - Value::okay(Value::string_utf8_from_bytes("heelo🦊".into()).unwrap()).unwrap(), + Value::some(Value::string_utf8_from_bytes("ac".into()).unwrap()).unwrap(), + Value::some(Value::string_utf8_from_bytes("c".into()).unwrap()).unwrap(), + Value::some(Value::string_utf8_from_bytes("abce".into()).unwrap()).unwrap(), + Value::some(Value::string_utf8_from_bytes("aecd".into()).unwrap()).unwrap(), + Value::some(Value::string_utf8_from_bytes("helloe".into()).unwrap()).unwrap(), + Value::some(Value::string_utf8_from_bytes("heelo🦊".into()).unwrap()).unwrap(), ]; for (test, expected) in tests.iter().zip(expected.iter()) { @@ -926,7 +926,7 @@ fn test_simple_string_utf8_replace_at() { "(replace-at u\"\" u0 u\"a\")", ]; - let bad_expected = [Value::err_uint(1), Value::err_uint(1)]; + let bad_expected = [Value::none(), Value::none()]; for (bad_test, bad_expected) in bad_tests.iter().zip(bad_expected.iter()) { assert_eq!(bad_expected.clone(), execute_v2(bad_test).unwrap().unwrap()); diff --git a/clarity/src/vm/types/mod.rs b/clarity/src/vm/types/mod.rs index e36cd5a21..a2557f48b 100644 --- a/clarity/src/vm/types/mod.rs +++ b/clarity/src/vm/types/mod.rs @@ -282,6 +282,52 @@ impl SequenceData { Some(result) } + pub fn replace_at(self, index: usize, element: Value) -> Result { + let seq_length = self.len(); + + // Check that the length of the provided element is 1. In the case that SequenceData + // is a list, we check that the provided element is the right type below. + if !self.is_list() { + if let Value::Sequence(data) = &element { + let elem_length = data.len(); + if elem_length != 1 { + return Err(RuntimeErrorType::BadTypeConstruction.into()) + } + } else { + return Err(RuntimeErrorType::BadTypeConstruction.into()) + } + } + if index >= seq_length { + return Err(CheckErrors::ValueOutOfBounds.into()) + } + + let new_seq_data = match (self, element) { + (SequenceData::Buffer(mut data), Value::Sequence(SequenceData::Buffer(elem))) => { + data.data[index] = elem.data[0]; + SequenceData::Buffer(data) + } + (SequenceData::List(mut data), elem) => { + let entry_type = data.type_signature.get_list_item_type(); + if !entry_type.admits(&elem) { + return Err(CheckErrors::ListTypesMustMatch.into()) + } + data.data[index] = elem; + SequenceData::List(data) + } + (SequenceData::String(CharType::ASCII(mut data)), Value::Sequence(SequenceData::String(CharType::ASCII(elem)))) => { + data.data[index] = elem.data[0]; + SequenceData::String(CharType::ASCII(data)) + } + (SequenceData::String(CharType::UTF8(mut data)), Value::Sequence(SequenceData::String(CharType::UTF8(mut elem)))) => { + data.data[index] = elem.data.swap_remove(0); + SequenceData::String(CharType::UTF8(data)) + } + _ => return Err(CheckErrors::ListTypesMustMatch.into()) + }; + + Ok(Value::some(Value::Sequence(new_seq_data))?) + } + pub fn contains(&self, to_find: Value) -> Result> { match self { SequenceData::Buffer(ref data) => { @@ -459,6 +505,14 @@ impl SequenceData { Ok(result) } + + pub fn is_list(&self) -> bool { + if let SequenceData::List(x) = self { + true + } else { + false + } + } } #[derive(Clone, Eq, PartialEq, Serialize, Deserialize)] From 8a064fd69097fa226f5fd31502590cc86bd4ca5f Mon Sep 17 00:00:00 2001 From: Alie Slade Date: Thu, 13 Oct 2022 19:00:20 -0400 Subject: [PATCH 10/15] Ran cargo fmt --- clarity/src/vm/functions/sequences.rs | 17 +++++++-------- clarity/src/vm/tests/sequences.rs | 5 +---- clarity/src/vm/types/mod.rs | 30 ++++++++++++++++----------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/clarity/src/vm/functions/sequences.rs b/clarity/src/vm/functions/sequences.rs index 3f0817607..c59abb951 100644 --- a/clarity/src/vm/functions/sequences.rs +++ b/clarity/src/vm/functions/sequences.rs @@ -397,19 +397,18 @@ pub fn special_replace_at( let seq = eval(&args[0], env, context)?; let seq_type = TypeSignature::type_of(&seq); - let expected_elem_type = - if let TypeSignature::SequenceType(seq_subtype) = &seq_type { - seq_subtype.unit_type() - } else { - return Err(CheckErrors::ExpectedSequence(seq_type).into()); - }; + let expected_elem_type = if let TypeSignature::SequenceType(seq_subtype) = &seq_type { + seq_subtype.unit_type() + } else { + return Err(CheckErrors::ExpectedSequence(seq_type).into()); + }; let index_val = eval(&args[1], env, context)?; let new_element = eval(&args[2], env, context)?; if expected_elem_type != TypeSignature::NoType && !expected_elem_type.admits(&new_element) { return Err(CheckErrors::TypeValueError(expected_elem_type, new_element).into()); } - + let index = if let Value::UInt(index_u128) = index_val { if let Ok(index_usize) = usize::try_from(index_u128) { index_usize @@ -421,9 +420,9 @@ pub fn special_replace_at( }; if let Value::Sequence(data) = seq { - let seq_len = data.len(); + let seq_len = data.len(); if index >= seq_len { - return Ok(Value::none()) + return Ok(Value::none()); } data.replace_at(index, new_element) } else { diff --git a/clarity/src/vm/tests/sequences.rs b/clarity/src/vm/tests/sequences.rs index b5a68946a..d0d1d6e1c 100644 --- a/clarity/src/vm/tests/sequences.rs +++ b/clarity/src/vm/tests/sequences.rs @@ -694,10 +694,7 @@ fn test_simple_list_replace_at() { ) .unwrap(), Value::some( - Value::list_from(vec![ - Value::list_from(vec![Value::Int(0)]).unwrap(), - ]) - .unwrap(), + Value::list_from(vec![Value::list_from(vec![Value::Int(0)]).unwrap()]).unwrap(), ) .unwrap(), ]; diff --git a/clarity/src/vm/types/mod.rs b/clarity/src/vm/types/mod.rs index a2557f48b..b86984c23 100644 --- a/clarity/src/vm/types/mod.rs +++ b/clarity/src/vm/types/mod.rs @@ -283,22 +283,22 @@ impl SequenceData { } pub fn replace_at(self, index: usize, element: Value) -> Result { - let seq_length = self.len(); + let seq_length = self.len(); - // Check that the length of the provided element is 1. In the case that SequenceData - // is a list, we check that the provided element is the right type below. + // Check that the length of the provided element is 1. In the case that SequenceData + // is a list, we check that the provided element is the right type below. if !self.is_list() { if let Value::Sequence(data) = &element { - let elem_length = data.len(); + let elem_length = data.len(); if elem_length != 1 { - return Err(RuntimeErrorType::BadTypeConstruction.into()) + return Err(RuntimeErrorType::BadTypeConstruction.into()); } } else { - return Err(RuntimeErrorType::BadTypeConstruction.into()) + return Err(RuntimeErrorType::BadTypeConstruction.into()); } } if index >= seq_length { - return Err(CheckErrors::ValueOutOfBounds.into()) + return Err(CheckErrors::ValueOutOfBounds.into()); } let new_seq_data = match (self, element) { @@ -309,21 +309,27 @@ impl SequenceData { (SequenceData::List(mut data), elem) => { let entry_type = data.type_signature.get_list_item_type(); if !entry_type.admits(&elem) { - return Err(CheckErrors::ListTypesMustMatch.into()) + return Err(CheckErrors::ListTypesMustMatch.into()); } data.data[index] = elem; SequenceData::List(data) } - (SequenceData::String(CharType::ASCII(mut data)), Value::Sequence(SequenceData::String(CharType::ASCII(elem)))) => { + ( + SequenceData::String(CharType::ASCII(mut data)), + Value::Sequence(SequenceData::String(CharType::ASCII(elem))), + ) => { data.data[index] = elem.data[0]; SequenceData::String(CharType::ASCII(data)) } - (SequenceData::String(CharType::UTF8(mut data)), Value::Sequence(SequenceData::String(CharType::UTF8(mut elem)))) => { + ( + SequenceData::String(CharType::UTF8(mut data)), + Value::Sequence(SequenceData::String(CharType::UTF8(mut elem))), + ) => { data.data[index] = elem.data.swap_remove(0); SequenceData::String(CharType::UTF8(data)) } - _ => return Err(CheckErrors::ListTypesMustMatch.into()) - }; + _ => return Err(CheckErrors::ListTypesMustMatch.into()), + }; Ok(Value::some(Value::Sequence(new_seq_data))?) } From 5d9d9a590c45b9c5a351eb5260e925f383c8c648 Mon Sep 17 00:00:00 2001 From: Alie Slade Date: Thu, 13 Oct 2022 19:01:12 -0400 Subject: [PATCH 11/15] Added ReplaceAt to ClarityCostFunction enum --- clarity/src/vm/costs/cost_functions.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clarity/src/vm/costs/cost_functions.rs b/clarity/src/vm/costs/cost_functions.rs index 9632fb883..e37be7c3d 100644 --- a/clarity/src/vm/costs/cost_functions.rs +++ b/clarity/src/vm/costs/cost_functions.rs @@ -130,5 +130,6 @@ define_named_enum!(ClarityCostFunction { NftOwner("cost_nft_owner"), NftBurn("cost_nft_burn"), PoisonMicroblock("poison_microblock"), + ReplaceAt("cost_replace_at"), Unimplemented("cost_unimplemented"), }); From 03be3e79bc5d36feda63ed492f52a8ece2783cf6 Mon Sep 17 00:00:00 2001 From: Pavitthra Pandurangan Date: Fri, 14 Oct 2022 12:05:05 +0530 Subject: [PATCH 12/15] fixed failing unit test --- clarity/src/vm/docs/mod.rs | 16 ++++++++-------- clarity/src/vm/functions/sequences.rs | 1 - src/clarity_vm/tests/costs.rs | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/clarity/src/vm/docs/mod.rs b/clarity/src/vm/docs/mod.rs index cd4ae117d..de2f8e870 100644 --- a/clarity/src/vm/docs/mod.rs +++ b/clarity/src/vm/docs/mod.rs @@ -2206,7 +2206,7 @@ to deserialize the type, the method returns `none`. const REPLACE_AT: SpecialAPI = SpecialAPI { input_type: "sequence_A, uint, A", - output_type: "(response sequence_A uint)", + output_type: "(optional sequence_A)", snippet: "replace-at ${1:sequence} ${2:index} ${3:element}", signature: "(replace-at sequence index element)", description: "The `replace-at` function takes in a sequence, an index, and an element, @@ -2214,15 +2214,15 @@ and returns a new sequence with the data at the index position replaced with the The given element's type must match the type of the sequence, and must correspond to a single index of the input sequence. The return type on success is the same type as the input sequence. -If the provided index is out of bounds, this functions returns `(err u1)`. +If the provided index is out of bounds, this functions returns `none`. ", example: r#" -(replace-at u"ab" u1 u"c") ;; Returns (ok u"ac") -(replace-at 0x00112233 u2 0x44) ;; Returns (ok 0x00114433) -(replace-at "abcd" u3 "e") ;; Returns (ok "abce") -(replace-at (list 1) u0 10) ;; Returns (ok (10)) -(replace-at (list (list 1) (list 2)) u0 (list 33)) ;; Returns (ok ((33) (2))) -(replace-at (list 1 2) u3 4) ;; Returns (err u1) +(replace-at u"ab" u1 u"c") ;; Returns (some u"ac") +(replace-at 0x00112233 u2 0x44) ;; Returns (some 0x00114433) +(replace-at "abcd" u3 "e") ;; Returns (some "abce") +(replace-at (list 1) u0 10) ;; Returns (some (10)) +(replace-at (list (list 1) (list 2)) u0 (list 33)) ;; Returns (some ((33) (2))) +(replace-at (list 1 2) u3 4) ;; Returns none "#, }; diff --git a/clarity/src/vm/functions/sequences.rs b/clarity/src/vm/functions/sequences.rs index c59abb951..dd567277f 100644 --- a/clarity/src/vm/functions/sequences.rs +++ b/clarity/src/vm/functions/sequences.rs @@ -391,7 +391,6 @@ pub fn special_replace_at( ) -> Result { check_argument_count(3, args)?; - // todo: update the ClarityCostFunction once the Clarity2 related cost functions are implemented. // Set the input to runtime_cost to 0, since replacing an element at an index is an O(1) operation. runtime_cost(ClarityCostFunction::Unimplemented, env, 0)?; diff --git a/src/clarity_vm/tests/costs.rs b/src/clarity_vm/tests/costs.rs index 612ec4166..bbd40e485 100644 --- a/src/clarity_vm/tests/costs.rs +++ b/src/clarity_vm/tests/costs.rs @@ -159,7 +159,7 @@ pub fn get_simple_test(function: &NativeFunctions) -> &'static str { Slice => "(slice str-foo u1 u1)", ToConsensusBuff => "(to-consensus-buff u1)", FromConsensusBuff => "(from-consensus-buff bool 0x03)", - ReplaceAt => "(replace-at list-foo 0 false)", + ReplaceAt => "(replace-at list-bar u0 5)", } } @@ -837,7 +837,7 @@ fn test_tracked_costs( (define-data-var var-foo int 0) (define-constant tuple-foo (tuple (a 1))) (define-constant list-foo (list true)) - (define-constant list-bar (list 1)) + (define-constant clarity/src/vm/docs/mod.rs (list 1)) (define-constant str-foo \"foobar\") (use-trait trait-1 .contract-trait.trait-1) (define-public (execute (contract )) (ok {}))", From a6bdac7916d6437ea9df4066a630aa531706f794 Mon Sep 17 00:00:00 2001 From: Pavitthra Pandurangan Date: Fri, 14 Oct 2022 12:05:51 +0530 Subject: [PATCH 13/15] remove clarity cost function; will be added in a different pr --- clarity/src/vm/costs/cost_functions.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/clarity/src/vm/costs/cost_functions.rs b/clarity/src/vm/costs/cost_functions.rs index e37be7c3d..9632fb883 100644 --- a/clarity/src/vm/costs/cost_functions.rs +++ b/clarity/src/vm/costs/cost_functions.rs @@ -130,6 +130,5 @@ define_named_enum!(ClarityCostFunction { NftOwner("cost_nft_owner"), NftBurn("cost_nft_burn"), PoisonMicroblock("poison_microblock"), - ReplaceAt("cost_replace_at"), Unimplemented("cost_unimplemented"), }); From 1b19aa08a684b0549ff6909dd982015cbe7fd516 Mon Sep 17 00:00:00 2001 From: Pavitthra Pandurangan Date: Fri, 14 Oct 2022 18:56:31 +0530 Subject: [PATCH 14/15] removed typo --- src/clarity_vm/tests/costs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clarity_vm/tests/costs.rs b/src/clarity_vm/tests/costs.rs index bbd40e485..dc0c73d8a 100644 --- a/src/clarity_vm/tests/costs.rs +++ b/src/clarity_vm/tests/costs.rs @@ -837,7 +837,7 @@ fn test_tracked_costs( (define-data-var var-foo int 0) (define-constant tuple-foo (tuple (a 1))) (define-constant list-foo (list true)) - (define-constant clarity/src/vm/docs/mod.rs (list 1)) + (define-constant list-bar (list 1)) (define-constant str-foo \"foobar\") (use-trait trait-1 .contract-trait.trait-1) (define-public (execute (contract )) (ok {}))", From 57a914aee5626652b5a6f951e6f31f37351f5643 Mon Sep 17 00:00:00 2001 From: Jude Nelson Date: Tue, 18 Oct 2022 10:29:44 -0400 Subject: [PATCH 15/15] fix: comment string --- src/burnchains/bitcoin/indexer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/burnchains/bitcoin/indexer.rs b/src/burnchains/bitcoin/indexer.rs index a284cff56..e954988da 100644 --- a/src/burnchains/bitcoin/indexer.rs +++ b/src/burnchains/bitcoin/indexer.rs @@ -495,7 +495,7 @@ impl BitcoinIndexer { canonical_spv_client.read_block_headers(1, start_block + 1)?; assert!( interval_headers.len() >= start_block as usize, - "BUG: missing headers for 0-{}", + "BUG: missing headers for 1-{}", start_block );