Skip to content

Commit c33cf38

Browse files
committed
Merge branch 'pox-wf-integration' into feat/wf-signer-set
2 parents 68e4f84 + 9791d29 commit c33cf38

235 files changed

Lines changed: 5567 additions & 2699 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Adds two new Clarity 6 native functions: `verify-merkle-proof`, which checks a Bitcoin-style merkle inclusion proof against a known root using double-SHA-256, and `get-bitcoin-tx-output?`, which parses a serialized Bitcoin transaction (with or without SegWit witness data) and returns the output at a given index along with the canonical, witness-stripped txid in internal byte order

clarity-types/src/types/signatures.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,8 @@ impl TypeSignature {
830830
pub const BUFFER_64: TypeSignature = Self::type_buffer_const(64);
831831
/// Buffer type with length 65.
832832
pub const BUFFER_65: TypeSignature = Self::type_buffer_const(65);
833+
/// Buffer type with length 1024.
834+
pub const BUFFER_1024: TypeSignature = Self::type_buffer_const(1024);
833835

834836
/// String ASCII type with minimum length (`1`).
835837
pub const STRING_ASCII_MIN: TypeSignature = Self::type_ascii_const(1);

clarity/src/vm/analysis/arithmetic_checker/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,9 @@ impl ArithmeticOnlyChecker<'_> {
210210
Err(Error::FunctionNotPermitted(function))
211211
}
212212
Sha512 | Sha512Trunc256 | Secp256k1Recover | Secp256k1Verify | Secp256r1Verify
213-
| Hash160 | Sha256 | Keccak256 => Err(Error::FunctionNotPermitted(function)),
213+
| Hash160 | Sha256 | Keccak256 | VerifyMerkleProof | GetBitcoinTxOutput => {
214+
Err(Error::FunctionNotPermitted(function))
215+
}
214216
Add | Subtract | Divide | Multiply | CmpGeq | CmpLeq | CmpLess | CmpGreater
215217
| Modulo | Power | Sqrti | Log2 | BitwiseXor | And | Or | Not | Equals | If
216218
| ConsSome | ConsOkay | ConsError | DefaultTo | UnwrapRet | UnwrapErrRet | IsOkay

clarity/src/vm/analysis/errors.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,23 @@ pub fn check_arguments_at_most<T>(expected: usize, args: &[T]) -> Result<(), Com
11081108
}
11091109
}
11101110

1111+
/// Check if the supplied arguments are exactly N in length, and if so, return
1112+
/// a fixed array with pointers to the arguments. Otherwise, return an IncorrectArgumentCount
1113+
pub fn get_arguments_exact<T, const N: usize>(args: &[T]) -> Result<&[T; N], CommonCheckErrorKind> {
1114+
args.try_into()
1115+
.map_err(|_| CommonCheckErrorKind::IncorrectArgumentCount(N, args.len()))
1116+
}
1117+
1118+
/// Check if the supplied arguments are at least N in length, and if so, return
1119+
/// a fixed array of size N with pointers to the arguments and a slice with the excess.
1120+
/// Otherwise, return an IncorrectArgumentCount
1121+
pub fn get_arguments_at_least<T, const N: usize>(
1122+
args: &[T],
1123+
) -> Result<(&[T; N], &[T]), CommonCheckErrorKind> {
1124+
args.split_first_chunk::<N>()
1125+
.ok_or_else(|| CommonCheckErrorKind::RequiresAtLeastArguments(N, args.len()))
1126+
}
1127+
11111128
fn formatted_expected_types(expected_types: &[TypeSignature]) -> String {
11121129
let mut expected_types_joined = format!("'{}'", expected_types[0]);
11131130

clarity/src/vm/analysis/read_only_checker/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,9 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> {
381381
| AllowanceWithFt
382382
| AllowanceWithNft
383383
| AllowanceWithStacking
384-
| AllowanceAll => {
384+
| AllowanceAll
385+
| VerifyMerkleProof
386+
| GetBitcoinTxOutput => {
385387
// Check all arguments.
386388
self.check_each_expression_is_read_only(args)
387389
}

clarity/src/vm/analysis/type_checker/v2_05/natives/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,9 @@ impl TypedNativeFunction {
839839
| AllowanceWithNft
840840
| AllowanceWithStacking
841841
| AllowanceAll
842-
| Secp256r1Verify => {
842+
| Secp256r1Verify
843+
| VerifyMerkleProof
844+
| GetBitcoinTxOutput => {
843845
return Err(StaticCheckErrorKind::Unreachable(
844846
"Clarity 2+ keywords should not show up in 2.05".into(),
845847
));

clarity/src/vm/analysis/type_checker/v2_1/natives/mod.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ use super::{
2020
TypeChecker, TypingContext, check_argument_count, check_arguments_at_least,
2121
check_arguments_at_most, compute_typecheck_cost, no_type,
2222
};
23-
use crate::vm::analysis::errors::{StaticCheckError, StaticCheckErrorKind, SyntaxBindingErrorType};
23+
use crate::vm::analysis::errors::{
24+
StaticCheckError, StaticCheckErrorKind, SyntaxBindingErrorType, get_arguments_exact,
25+
};
2426
use crate::vm::costs::cost_functions::ClarityCostFunction;
2527
use crate::vm::costs::{CostErrors, CostTracker, analysis_typecheck_cost, runtime_cost};
2628
use crate::vm::diagnostic::DiagnosableError;
29+
use crate::vm::functions::bitcoin::VERIFY_MERKLE_PROOF_MAX_DEPTH;
2730
use crate::vm::functions::{NativeFunctions, handle_binding_list};
2831
use crate::vm::types::signatures::{
2932
CallableSubtype, FunctionArgSignature, FunctionReturnsSignature, SequenceSubtype,
@@ -868,6 +871,63 @@ fn check_get_tenure_info(
868871
Ok(TypeSignature::new_option(block_info_prop.type_result())?)
869872
}
870873

874+
fn check_verify_merkle_proof(
875+
checker: &mut TypeChecker,
876+
args: &[SymbolicExpression],
877+
context: &TypingContext,
878+
) -> Result<TypeSignature, StaticCheckError> {
879+
let [leaf_hash, root_hash, tx_index, tx_count, sibling_hashes] =
880+
get_arguments_exact::<_, 5>(args)?;
881+
882+
check_argument_count(5, args)?;
883+
checker.type_check_expects(leaf_hash, context, &TypeSignature::BUFFER_32)?;
884+
checker.type_check_expects(root_hash, context, &TypeSignature::BUFFER_32)?;
885+
checker.type_check_expects(tx_index, context, &TypeSignature::UIntType)?;
886+
checker.type_check_expects(tx_count, context, &TypeSignature::UIntType)?;
887+
let siblings_type = TypeSignature::list_of(
888+
TypeSignature::BUFFER_32,
889+
VERIFY_MERKLE_PROOF_MAX_DEPTH,
890+
)
891+
.map_err(|_| {
892+
StaticCheckErrorKind::Unreachable("FATAL: failed to build (list 24 (buff 32)) type".into())
893+
})?;
894+
checker.type_check_expects(sibling_hashes, context, &siblings_type)?;
895+
Ok(TypeSignature::BoolType)
896+
}
897+
898+
fn check_get_bitcoin_tx_output(
899+
checker: &mut TypeChecker,
900+
args: &[SymbolicExpression],
901+
context: &TypingContext,
902+
) -> Result<TypeSignature, StaticCheckError> {
903+
let [tx_bytes, vout_index] = get_arguments_exact::<_, 2>(args)?;
904+
905+
checker.type_check_expects(tx_bytes, context, &TypeSignature::BUFFER_MAX)?;
906+
checker.type_check_expects(vout_index, context, &TypeSignature::UIntType)?;
907+
908+
let ok_type: TypeSignature = TupleTypeSignature::try_from(vec![
909+
(
910+
ClarityName::from_literal("script"),
911+
TypeSignature::BUFFER_1024,
912+
),
913+
(ClarityName::from_literal("amount"), TypeSignature::UIntType),
914+
(ClarityName::from_literal("txid"), TypeSignature::BUFFER_32),
915+
])
916+
.map_err(|_| {
917+
StaticCheckErrorKind::Unreachable(
918+
"FATAL: failed to build get-bitcoin-tx-output? ok-tuple type".into(),
919+
)
920+
})?
921+
.into();
922+
923+
TypeSignature::new_response(ok_type, TypeSignature::UIntType).map_err(|_| {
924+
StaticCheckErrorKind::Unreachable(
925+
"FATAL: failed to build get-bitcoin-tx-output? response type".into(),
926+
)
927+
.into()
928+
})
929+
}
930+
871931
impl TypedNativeFunction {
872932
pub fn type_check_application(
873933
&self,
@@ -1272,6 +1332,8 @@ impl TypedNativeFunction {
12721332
| AllowanceWithStacking
12731333
| AllowanceAll => Special(SpecialNativeFunction(&post_conditions::check_allowance_err)),
12741334
Secp256r1Verify => Special(SpecialNativeFunction(&check_secp256r1_verify)),
1335+
VerifyMerkleProof => Special(SpecialNativeFunction(&check_verify_merkle_proof)),
1336+
GetBitcoinTxOutput => Special(SpecialNativeFunction(&check_get_bitcoin_tx_output)),
12751337
};
12761338

12771339
Ok(out)

clarity/src/vm/callables.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,33 @@ use crate::vm::{LocalContext, Value, eval};
3737

3838
#[allow(clippy::type_complexity, clippy::large_enum_variant)]
3939
pub enum CallableType {
40+
/// A function defined in a Clarity contract via `define-public`,
41+
/// `define-read-only`, or `define-private`. Arguments are evaluated by
42+
/// the caller and then bound into a fresh `LocalContext` before the
43+
/// body is interpreted.
4044
UserFunction(DefinedFunction),
45+
/// A built-in function implemented in Rust. The string is the function's
46+
/// Clarity name (used for identifier construction and diagnostics), the
47+
/// [`NativeHandle`] dispatches on arity, and the [`ClarityCostFunction`]
48+
/// is charged with the argument count as its input size.
4149
NativeFunction(&'static str, NativeHandle, ClarityCostFunction),
42-
/// These native functions have a new method for calculating input size in 2.05
43-
/// If the global context's epoch is >= 2.05, the fn field is applied to obtain
44-
/// the input to the cost function.
50+
/// A built-in function whose runtime-cost input size is computed from
51+
/// the actual argument values rather than just their count. Introduced
52+
/// in epoch 2.05: when the current epoch is >= 2.05, the trailing
53+
/// closure is applied to the evaluated arguments to obtain the input
54+
/// passed to the cost function. In earlier epochs this variant behaves
55+
/// like [`Self::NativeFunction`].
4556
NativeFunction205(
4657
&'static str,
4758
NativeHandle,
4859
ClarityCostFunction,
4960
&'static dyn Fn(&[Value]) -> Result<u64, VmExecutionError>,
5061
),
62+
/// A built-in form that needs control over how (or whether) its
63+
/// arguments are evaluated — e.g. `if`, `let`, `match`, `contract-call?`.
64+
/// The closure receives the raw [`SymbolicExpression`]s along with the
65+
/// execution and local contexts, and is responsible for cost tracking,
66+
/// arity checking, and argument evaluation itself.
5167
SpecialFunction(
5268
&'static str,
5369
&'static dyn Fn(

clarity/src/vm/costs/cost_functions.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ define_named_enum!(ClarityCostFunction {
161161
RestrictAssets("cost_restrict_assets"),
162162
AsContractSafe("cost_as_contract_safe"),
163163
Secp256r1verify("cost_secp256r1verify"),
164+
VerifyMerkleProof("cost_verify_merkle_proof"),
165+
GetBitcoinTxOutput("cost_get_bitcoin_tx_output"),
164166
Unimplemented("cost_unimplemented"),
165167
});
166168

@@ -339,6 +341,8 @@ pub trait CostValues {
339341
fn cost_restrict_assets(n: u64) -> Result<ExecutionCost, VmExecutionError>;
340342
fn cost_as_contract_safe(n: u64) -> Result<ExecutionCost, VmExecutionError>;
341343
fn cost_secp256r1verify(n: u64) -> Result<ExecutionCost, VmExecutionError>;
344+
fn cost_verify_merkle_proof(n: u64) -> Result<ExecutionCost, VmExecutionError>;
345+
fn cost_get_bitcoin_tx_output(n: u64) -> Result<ExecutionCost, VmExecutionError>;
342346
}
343347

344348
impl ClarityCostFunction {
@@ -496,6 +500,8 @@ impl ClarityCostFunction {
496500
ClarityCostFunction::RestrictAssets => C::cost_restrict_assets(n),
497501
ClarityCostFunction::AsContractSafe => C::cost_as_contract_safe(n),
498502
ClarityCostFunction::Secp256r1verify => C::cost_secp256r1verify(n),
503+
ClarityCostFunction::VerifyMerkleProof => C::cost_verify_merkle_proof(n),
504+
ClarityCostFunction::GetBitcoinTxOutput => C::cost_get_bitcoin_tx_output(n),
499505
ClarityCostFunction::Unimplemented => Err(RuntimeError::NotImplemented.into()),
500506
}
501507
}

clarity/src/vm/costs/costs_1.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,4 +765,12 @@ impl CostValues for Costs1 {
765765
fn cost_secp256r1verify(n: u64) -> Result<ExecutionCost, VmExecutionError> {
766766
Err(RuntimeError::NotImplemented.into())
767767
}
768+
769+
fn cost_verify_merkle_proof(_n: u64) -> Result<ExecutionCost, VmExecutionError> {
770+
Err(RuntimeError::NotImplemented.into())
771+
}
772+
773+
fn cost_get_bitcoin_tx_output(_n: u64) -> Result<ExecutionCost, VmExecutionError> {
774+
Err(RuntimeError::NotImplemented.into())
775+
}
768776
}

0 commit comments

Comments
 (0)