Skip to content

Commit 504c115

Browse files
committed
feat: initial implementation for restric-assets?
This just adds the basic support for the syntax and some setup for the full implementation.
1 parent 307d088 commit 504c115

File tree

17 files changed

+302
-64
lines changed

17 files changed

+302
-64
lines changed

clarity-types/src/errors/analysis.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,9 @@ pub enum CheckErrors {
307307

308308
// time checker errors
309309
ExecutionTimeExpired,
310+
311+
// contract post-conditions
312+
RestrictAssetsExpectedListOfAllowances,
310313
}
311314

312315
#[derive(Debug, PartialEq)]
@@ -605,6 +608,7 @@ impl DiagnosableError for CheckErrors {
605608
CheckErrors::CostComputationFailed(s) => format!("contract cost computation failed: {s}"),
606609
CheckErrors::CouldNotDetermineSerializationType => "could not determine the input type for the serialization function".into(),
607610
CheckErrors::ExecutionTimeExpired => "execution time expired".into(),
611+
CheckErrors::RestrictAssetsExpectedListOfAllowances => "restrict-assets? expects a list of asset allowances as its second argument".into(),
608612
}
609613
}
610614

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,9 @@ impl ArithmeticOnlyChecker<'_> {
175175
| StxGetAccount => Err(Error::FunctionNotPermitted(function)),
176176
Append | Concat | AsMaxLen | ContractOf | PrincipalOf | ListCons | Print
177177
| AsContract | ElementAt | ElementAtAlias | IndexOf | IndexOfAlias | Map | Filter
178-
| Fold | Slice | ReplaceAt | ContractHash => Err(Error::FunctionNotPermitted(function)),
178+
| Fold | Slice | ReplaceAt | ContractHash | RestrictAssets => {
179+
Err(Error::FunctionNotPermitted(function))
180+
}
179181
BuffToIntLe | BuffToUIntLe | BuffToIntBe | BuffToUIntBe => {
180182
Err(Error::FunctionNotPermitted(function))
181183
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,23 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> {
427427
self.check_each_expression_is_read_only(&args[2..])
428428
.map(|args_read_only| args_read_only && is_function_read_only)
429429
}
430+
RestrictAssets => {
431+
check_arguments_at_least(3, args)?;
432+
433+
// Check the asset owner argument.
434+
let asset_owner_read_only = self.check_read_only(&args[0])?;
435+
436+
// Check the allowances argument.
437+
let allowances = args[1]
438+
.match_list()
439+
.ok_or(CheckErrors::RestrictAssetsExpectedListOfAllowances)?;
440+
let allowances_read_only = self.check_each_expression_is_read_only(allowances)?;
441+
442+
// Check the body expressions.
443+
let body_read_only = self.check_each_expression_is_read_only(&args[2..])?;
444+
445+
Ok(asset_owner_read_only && allowances_read_only && body_read_only)
446+
}
430447
}
431448
}
432449

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616

1717
use stacks_common::types::StacksEpochId;
1818

19-
use super::{check_argument_count, check_arguments_at_least, no_type, TypeChecker, TypingContext};
19+
use super::{TypeChecker, TypingContext, check_argument_count, check_arguments_at_least, no_type};
2020
use crate::vm::analysis::errors::{CheckError, CheckErrors, SyntaxBindingErrorType};
2121
use crate::vm::costs::cost_functions::ClarityCostFunction;
2222
use crate::vm::costs::{analysis_typecheck_cost, runtime_cost};
2323
use crate::vm::diagnostic::DiagnosableError;
24-
use crate::vm::functions::{handle_binding_list, NativeFunctions};
24+
use crate::vm::functions::{NativeFunctions, handle_binding_list};
2525
use crate::vm::types::{
26-
BlockInfoProperty, FixedFunction, FunctionArg, FunctionSignature, FunctionType, PrincipalData,
27-
TupleTypeSignature, TypeSignature, Value, BUFF_20, BUFF_32, BUFF_33, BUFF_64, BUFF_65,
26+
BUFF_20, BUFF_32, BUFF_33, BUFF_64, BUFF_65, BlockInfoProperty, FixedFunction, FunctionArg,
27+
FunctionSignature, FunctionType, PrincipalData, TupleTypeSignature, TypeSignature, Value,
2828
};
2929
use crate::vm::{ClarityName, ClarityVersion, SymbolicExpression, SymbolicExpressionType};
3030

@@ -782,7 +782,8 @@ impl TypedNativeFunction {
782782
| StringToUInt | IntToAscii | IntToUtf8 | GetBurnBlockInfo | StxTransferMemo
783783
| StxGetAccount | BitwiseAnd | BitwiseOr | BitwiseNot | BitwiseLShift
784784
| BitwiseRShift | BitwiseXor2 | Slice | ToConsensusBuff | FromConsensusBuff
785-
| ReplaceAt | GetStacksBlockInfo | GetTenureInfo | ContractHash | ToAscii => {
785+
| ReplaceAt | GetStacksBlockInfo | GetTenureInfo | ContractHash | ToAscii
786+
| RestrictAssets => {
786787
return Err(CheckErrors::Expects(
787788
"Clarity 2+ keywords should not show up in 2.05".into(),
788789
));

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,7 +1134,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> {
11341134
Ok(())
11351135
}
11361136

1137-
// Type check an expression, with an expected_type that should _admit_ the expression.
1137+
/// Type check an expression, with an expected_type that should _admit_ the expression.
11381138
pub fn type_check_expects(
11391139
&mut self,
11401140
expr: &SymbolicExpression,
@@ -1156,7 +1156,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> {
11561156
}
11571157
}
11581158

1159-
// Type checks an expression, recursively type checking its subexpressions
1159+
/// Type checks an expression, recursively type checking its subexpressions
11601160
pub fn type_check(
11611161
&mut self,
11621162
expr: &SymbolicExpression,
@@ -1175,6 +1175,8 @@ impl<'a, 'b> TypeChecker<'a, 'b> {
11751175
result
11761176
}
11771177

1178+
/// Type checks a list of statements, ensuring that each statement is valid
1179+
/// and any responses before the last statement are handled.
11781180
fn type_check_consecutive_statements(
11791181
&mut self,
11801182
args: &[SymbolicExpression],

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

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,23 @@
1717
use stacks_common::types::StacksEpochId;
1818

1919
use super::{
20-
check_argument_count, check_arguments_at_least, check_arguments_at_most,
21-
compute_typecheck_cost, no_type, TypeChecker, TypingContext,
20+
TypeChecker, TypingContext, check_argument_count, check_arguments_at_least,
21+
check_arguments_at_most, compute_typecheck_cost, no_type,
2222
};
2323
use crate::vm::analysis::errors::{CheckError, CheckErrors, SyntaxBindingErrorType};
2424
use crate::vm::costs::cost_functions::ClarityCostFunction;
25-
use crate::vm::costs::{analysis_typecheck_cost, runtime_cost, CostErrors, CostTracker};
25+
use crate::vm::costs::{CostErrors, CostTracker, analysis_typecheck_cost, runtime_cost};
2626
use crate::vm::diagnostic::DiagnosableError;
27-
use crate::vm::functions::{handle_binding_list, NativeFunctions};
27+
use crate::vm::functions::{NativeFunctions, handle_binding_list};
2828
use crate::vm::types::signatures::{
29-
CallableSubtype, FunctionArgSignature, FunctionReturnsSignature, SequenceSubtype, ASCII_40,
29+
ASCII_40, CallableSubtype, FunctionArgSignature, FunctionReturnsSignature, SequenceSubtype,
3030
TO_ASCII_MAX_BUFF, TO_ASCII_RESPONSE_STRING, UTF8_40,
3131
};
3232
use crate::vm::types::{
33-
BlockInfoProperty, BufferLength, BurnBlockInfoProperty, FixedFunction, FunctionArg,
34-
FunctionSignature, FunctionType, PrincipalData, StacksBlockInfoProperty, TenureInfoProperty,
35-
TupleTypeSignature, TypeSignature, Value, BUFF_1, BUFF_20, BUFF_32, BUFF_33, BUFF_64, BUFF_65,
36-
MAX_VALUE_SIZE,
33+
BUFF_1, BUFF_20, BUFF_32, BUFF_33, BUFF_64, BUFF_65, BlockInfoProperty, BufferLength,
34+
BurnBlockInfoProperty, FixedFunction, FunctionArg, FunctionSignature, FunctionType,
35+
MAX_VALUE_SIZE, PrincipalData, StacksBlockInfoProperty, TenureInfoProperty, TupleTypeSignature,
36+
TypeSignature, Value,
3737
};
3838
use crate::vm::{ClarityName, ClarityVersion, SymbolicExpression, SymbolicExpressionType};
3939

@@ -819,6 +819,42 @@ fn check_get_tenure_info(
819819
Ok(TypeSignature::new_option(block_info_prop.type_result())?)
820820
}
821821

822+
fn check_restrict_assets(
823+
checker: &mut TypeChecker,
824+
args: &[SymbolicExpression],
825+
context: &TypingContext,
826+
) -> Result<TypeSignature, CheckError> {
827+
check_arguments_at_least(3, args)?;
828+
829+
let asset_owner = &args[0];
830+
let allowance_list = args[1].match_list().ok_or(CheckError::new(
831+
CheckErrors::RestrictAssetsExpectedListOfAllowances,
832+
))?;
833+
let body_exprs = &args[2..];
834+
835+
runtime_cost(
836+
ClarityCostFunction::AnalysisListItemsCheck,
837+
checker,
838+
allowance_list.len() + body_exprs.len(),
839+
)?;
840+
841+
checker.type_check_expects(asset_owner, context, &TypeSignature::PrincipalType)?;
842+
843+
// TODO: type-check the allowances
844+
845+
// Check the body expressions, ensuring any intermediate responses are handled
846+
let mut last_return = None;
847+
for expr in body_exprs {
848+
let type_return = checker.type_check(expr, context)?;
849+
if type_return.is_response_type() {
850+
return Err(CheckErrors::UncheckedIntermediaryResponses.into());
851+
}
852+
last_return = Some(type_return);
853+
}
854+
855+
last_return.ok_or_else(|| CheckError::new(CheckErrors::CheckerImplementationFailure))
856+
}
857+
822858
impl TypedNativeFunction {
823859
pub fn type_check_application(
824860
&self,
@@ -1209,6 +1245,7 @@ impl TypedNativeFunction {
12091245
CheckErrors::Expects("FATAL: Legal Clarity response type marked invalid".into())
12101246
})?,
12111247
))),
1248+
RestrictAssets => Special(SpecialNativeFunction(&check_restrict_assets)),
12121249
};
12131250

12141251
Ok(out)

clarity/src/vm/costs/cost_functions.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ define_named_enum!(ClarityCostFunction {
159159
BitwiseRShift("cost_bitwise_right_shift"),
160160
ContractHash("cost_contract_hash"),
161161
ToAscii("cost_to_ascii"),
162+
RestrictAssets("cost_restrict_assets"),
162163
Unimplemented("cost_unimplemented"),
163164
});
164165

@@ -330,6 +331,7 @@ pub trait CostValues {
330331
fn cost_bitwise_right_shift(n: u64) -> InterpreterResult<ExecutionCost>;
331332
fn cost_contract_hash(n: u64) -> InterpreterResult<ExecutionCost>;
332333
fn cost_to_ascii(n: u64) -> InterpreterResult<ExecutionCost>;
334+
fn cost_restrict_assets(n: u64) -> InterpreterResult<ExecutionCost>;
333335
}
334336

335337
impl ClarityCostFunction {
@@ -484,6 +486,7 @@ impl ClarityCostFunction {
484486
ClarityCostFunction::BitwiseRShift => C::cost_bitwise_right_shift(n),
485487
ClarityCostFunction::ContractHash => C::cost_contract_hash(n),
486488
ClarityCostFunction::ToAscii => C::cost_to_ascii(n),
489+
ClarityCostFunction::RestrictAssets => C::cost_restrict_assets(n),
487490
ClarityCostFunction::Unimplemented => Err(RuntimeErrorType::NotImplemented.into()),
488491
}
489492
}

clarity/src/vm/costs/costs_1.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
// You should have received a copy of the GNU General Public License
1414
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

16-
/// This file implements the cost functions from costs.clar in Rust.
17-
use super::cost_functions::{linear, logn, nlogn, CostValues};
1816
use super::ExecutionCost;
17+
/// This file implements the cost functions from costs.clar in Rust.
18+
use super::cost_functions::{CostValues, linear, logn, nlogn};
1919
use crate::vm::errors::{InterpreterResult, RuntimeErrorType};
2020

2121
pub struct Costs1;
@@ -753,4 +753,8 @@ impl CostValues for Costs1 {
753753
fn cost_to_ascii(n: u64) -> InterpreterResult<ExecutionCost> {
754754
Err(RuntimeErrorType::NotImplemented.into())
755755
}
756+
757+
fn cost_restrict_assets(n: u64) -> InterpreterResult<ExecutionCost> {
758+
Err(RuntimeErrorType::NotImplemented.into())
759+
}
756760
}

clarity/src/vm/costs/costs_2.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
// You should have received a copy of the GNU General Public License
1414
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

16-
/// This file implements the cost functions from costs-2.clar in Rust.
17-
use super::cost_functions::{linear, logn, nlogn, CostValues};
1816
use super::ExecutionCost;
17+
/// This file implements the cost functions from costs-2.clar in Rust.
18+
use super::cost_functions::{CostValues, linear, logn, nlogn};
1919
use crate::vm::errors::{InterpreterResult, RuntimeErrorType};
2020

2121
pub struct Costs2;
@@ -753,4 +753,8 @@ impl CostValues for Costs2 {
753753
fn cost_to_ascii(n: u64) -> InterpreterResult<ExecutionCost> {
754754
Err(RuntimeErrorType::NotImplemented.into())
755755
}
756+
757+
fn cost_restrict_assets(n: u64) -> InterpreterResult<ExecutionCost> {
758+
Err(RuntimeErrorType::NotImplemented.into())
759+
}
756760
}

clarity/src/vm/costs/costs_2_testnet.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
// You should have received a copy of the GNU General Public License
1414
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

16-
/// This file implements the cost functions from costs-2-testnet.clar in Rust.
17-
use super::cost_functions::{linear, logn, nlogn, CostValues};
1816
use super::ExecutionCost;
17+
/// This file implements the cost functions from costs-2-testnet.clar in Rust.
18+
use super::cost_functions::{CostValues, linear, logn, nlogn};
1919
use crate::vm::errors::{InterpreterResult, RuntimeErrorType};
2020

2121
pub struct Costs2Testnet;
@@ -753,4 +753,8 @@ impl CostValues for Costs2Testnet {
753753
fn cost_to_ascii(n: u64) -> InterpreterResult<ExecutionCost> {
754754
Err(RuntimeErrorType::NotImplemented.into())
755755
}
756+
757+
fn cost_restrict_assets(n: u64) -> InterpreterResult<ExecutionCost> {
758+
Err(RuntimeErrorType::NotImplemented.into())
759+
}
756760
}

0 commit comments

Comments
 (0)