Skip to content

Commit 8d6248b

Browse files
committed
Merge branch 'merge-develop-to-aac-client-breaking' of github.com:jferrant/stacks-core into chore/merge-develop-to-aac-client-breaking
2 parents 2b74579 + 8f7df21 commit 8d6248b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+6435
-123
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
2626
- `current-contract`
2727
- `block-time`
2828
- `to-ascii?`
29+
- `restrict-assets?`
30+
- `as-contract?`
31+
- Special allowance expressions:
32+
- `with-stx`
33+
- `with-ft`
34+
- `with-nft`
35+
- `with-stacking`
36+
- `with-all-assets-unsafe`
2937
- Added `contract_cost_limit_percentage` to the miner config file — sets the percentage of a block’s execution cost at which, if a large non-boot contract call would cause a BlockTooBigError, the miner will stop adding further non-boot contract calls and only include STX transfers and boot contract calls for the remainder of the block.
3038
- Fixed a bug caused by a miner winning a sortition with a block commit that pointed to a previous tip, which would cause the miner to try and reorg itself. [#6481](https://github.com/stacks-network/stacks-core/issues/6481)
3139

clarity-types/src/errors/analysis.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,16 @@ pub enum CheckErrorKind {
482482
WriteAttemptedInReadOnly,
483483
/// `at-block` closure must be read-only but contains write operations.
484484
AtBlockClosureMustBeReadOnly,
485+
486+
// contract post-conditions
487+
ExpectedListOfAllowances(String, i32),
488+
AllowanceExprNotAllowed,
489+
ExpectedAllowanceExpr(String),
490+
WithAllAllowanceNotAllowed,
491+
WithAllAllowanceNotAlone,
492+
WithNftExpectedListOfIdentifiers,
493+
MaxIdentifierLengthExceeded(u32, u32),
494+
TooManyAllowances(usize, usize),
485495
}
486496

487497
#[derive(Debug, PartialEq)]
@@ -792,6 +802,14 @@ impl DiagnosableError for CheckErrorKind {
792802
CheckErrorKind::CostComputationFailed(s) => format!("contract cost computation failed: {s}"),
793803
CheckErrorKind::CouldNotDetermineSerializationType => "could not determine the input type for the serialization function".into(),
794804
CheckErrorKind::ExecutionTimeExpired => "execution time expired".into(),
805+
CheckErrorKind::ExpectedListOfAllowances(fn_name, arg_num) => format!("{fn_name} expects a list of asset allowances as argument {arg_num}"),
806+
CheckErrorKind::AllowanceExprNotAllowed => "allowance expressions are only allowed in the context of a `restrict-assets?` or `as-contract?`".into(),
807+
CheckErrorKind::ExpectedAllowanceExpr(got_name) => format!("expected an allowance expression, got: {got_name}"),
808+
CheckErrorKind::WithAllAllowanceNotAllowed => "with-all-assets-unsafe is not allowed here, only in the allowance list for `as-contract?`".into(),
809+
CheckErrorKind::WithAllAllowanceNotAlone => "with-all-assets-unsafe must not be used along with other allowances".into(),
810+
CheckErrorKind::WithNftExpectedListOfIdentifiers => "with-nft allowance must include a list of asset identifiers".into(),
811+
CheckErrorKind::MaxIdentifierLengthExceeded(max_len, len) => format!("with-nft allowance identifiers list must not exceed {max_len} elements, got {len}"),
812+
CheckErrorKind::TooManyAllowances(max_allowed, found) => format!("too many allowances specified, the maximum is {max_allowed}, found {found}"),
795813
}
796814
}
797815

clarity-types/src/errors/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub enum VmExecutionError {
6868
Internal(VmInternalError),
6969
/// Errors that occur during runtime execution of Clarity code, such as arithmetic errors or
7070
/// invalid operations, expected as part of contract evaluation.
71-
/// The `RuntimeErrorType` wraps the specific runtime error, and the `Option<StackTrace>` provides
71+
/// The `RuntimeError` wraps the specific runtime error, and the `Option<StackTrace>` provides
7272
/// an optional stack trace for debugging, if available.
7373
Runtime(RuntimeError, Option<StackTrace>),
7474
/// Errors triggered during Clarity contract evaluation that cause early termination with
@@ -192,6 +192,7 @@ pub enum RuntimeError {
192192
PoxAlreadyLocked,
193193
/// Block time unavailable during execution.
194194
BlockTimeNotAvailable,
195+
Unreachable,
195196
}
196197

197198
#[derive(Debug, PartialEq)]

clarity-types/src/types/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,16 @@ impl Value {
12351235
Err(VmInternalError::Expect("Expected response".into()).into())
12361236
}
12371237
}
1238+
1239+
pub fn expect_string_ascii(self) -> Result<String> {
1240+
if let Value::Sequence(SequenceData::String(CharType::ASCII(ASCIIData { data }))) = self {
1241+
Ok(String::from_utf8(data)
1242+
.map_err(|_| VmInternalError::Expect("Non UTF-8 data in string".into()))?)
1243+
} else {
1244+
error!("Value '{self:?}' is not an ASCII string");
1245+
Err(VmInternalError::Expect("Expected ASCII string".into()).into())
1246+
}
1247+
}
12381248
}
12391249

12401250
impl BuffData {

clarity-types/src/types/signatures.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,8 @@ impl TypeSignature {
860860
pub const STRING_ASCII_MAX: TypeSignature = Self::type_ascii_const(MAX_VALUE_SIZE);
861861
/// String ASCII type with length 40.
862862
pub const STRING_ASCII_40: TypeSignature = Self::type_ascii_const(40);
863+
/// String ASCII type with length 128.
864+
pub const STRING_ASCII_128: TypeSignature = Self::type_ascii_const(128);
863865

864866
/// String UTF8 type with minimum length (`1`).
865867
pub const STRING_UTF8_MIN: TypeSignature = Self::type_string_utf8(1);
@@ -913,7 +915,7 @@ impl TypeSignature {
913915

914916
/// Creates a string ASCII type with the specified length.
915917
/// It may panic if the provided length is invalid.
916-
#[cfg(test)]
918+
#[cfg(any(test, feature = "testing"))]
917919
pub const fn new_ascii_type_checked(len: u32) -> Self {
918920
Self::type_ascii_const(len)
919921
}

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,31 @@ impl ArithmeticOnlyChecker<'_> {
175175
| ContractCall | StxTransfer | StxTransferMemo | StxBurn | AtBlock | GetStxBalance
176176
| GetTokenSupply | BurnToken | FromConsensusBuff | ToConsensusBuff | BurnAsset
177177
| StxGetAccount => Err(Error::FunctionNotPermitted(function)),
178-
Append | Concat | AsMaxLen | ContractOf | PrincipalOf | ListCons | Print
179-
| AsContract | ElementAt | ElementAtAlias | IndexOf | IndexOfAlias | Map | Filter
180-
| Fold | Slice | ReplaceAt | ContractHash => Err(Error::FunctionNotPermitted(function)),
178+
Append
179+
| Concat
180+
| AsMaxLen
181+
| ContractOf
182+
| PrincipalOf
183+
| ListCons
184+
| Print
185+
| AsContract
186+
| ElementAt
187+
| ElementAtAlias
188+
| IndexOf
189+
| IndexOfAlias
190+
| Map
191+
| Filter
192+
| Fold
193+
| Slice
194+
| ReplaceAt
195+
| ContractHash
196+
| RestrictAssets
197+
| AsContractSafe
198+
| AllowanceWithStx
199+
| AllowanceWithFt
200+
| AllowanceWithNft
201+
| AllowanceWithStacking
202+
| AllowanceAll => Err(Error::FunctionNotPermitted(function)),
181203
BuffToIntLe | BuffToUIntLe | BuffToIntBe | BuffToUIntBe => {
182204
Err(Error::FunctionNotPermitted(function))
183205
}

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

Lines changed: 134 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -286,20 +286,101 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> {
286286
use crate::vm::functions::NativeFunctions::*;
287287

288288
match function {
289-
Add | Subtract | Divide | Multiply | CmpGeq | CmpLeq | CmpLess | CmpGreater
290-
| Modulo | Power | Sqrti | Log2 | BitwiseXor | And | Or | Not | Hash160 | Sha256
291-
| Keccak256 | Equals | If | Sha512 | Sha512Trunc256 | Secp256k1Recover
292-
| Secp256k1Verify | ConsSome | ConsOkay | ConsError | DefaultTo | UnwrapRet
293-
| UnwrapErrRet | IsOkay | IsNone | Asserts | Unwrap | UnwrapErr | Match | IsErr
294-
| IsSome | TryRet | ToUInt | ToInt | BuffToIntLe | BuffToUIntLe | BuffToIntBe
295-
| BuffToUIntBe | IntToAscii | IntToUtf8 | StringToInt | StringToUInt | IsStandard
296-
| ToConsensusBuff | PrincipalDestruct | PrincipalConstruct | Append | Concat
297-
| AsMaxLen | ContractOf | PrincipalOf | ListCons | GetBlockInfo | GetBurnBlockInfo
298-
| GetStacksBlockInfo | GetTenureInfo | TupleGet | TupleMerge | Len | Print
299-
| AsContract | Begin | FetchVar | GetStxBalance | StxGetAccount | GetTokenBalance
300-
| GetAssetOwner | GetTokenSupply | ElementAt | IndexOf | Slice | ReplaceAt
301-
| BitwiseAnd | BitwiseOr | BitwiseNot | BitwiseLShift | BitwiseRShift | BitwiseXor2
302-
| ElementAtAlias | IndexOfAlias | ContractHash | ToAscii => {
289+
Add
290+
| Subtract
291+
| Divide
292+
| Multiply
293+
| CmpGeq
294+
| CmpLeq
295+
| CmpLess
296+
| CmpGreater
297+
| Modulo
298+
| Power
299+
| Sqrti
300+
| Log2
301+
| BitwiseXor
302+
| And
303+
| Or
304+
| Not
305+
| Hash160
306+
| Sha256
307+
| Keccak256
308+
| Equals
309+
| If
310+
| Sha512
311+
| Sha512Trunc256
312+
| Secp256k1Recover
313+
| Secp256k1Verify
314+
| ConsSome
315+
| ConsOkay
316+
| ConsError
317+
| DefaultTo
318+
| UnwrapRet
319+
| UnwrapErrRet
320+
| IsOkay
321+
| IsNone
322+
| Asserts
323+
| Unwrap
324+
| UnwrapErr
325+
| Match
326+
| IsErr
327+
| IsSome
328+
| TryRet
329+
| ToUInt
330+
| ToInt
331+
| BuffToIntLe
332+
| BuffToUIntLe
333+
| BuffToIntBe
334+
| BuffToUIntBe
335+
| IntToAscii
336+
| IntToUtf8
337+
| StringToInt
338+
| StringToUInt
339+
| IsStandard
340+
| ToConsensusBuff
341+
| PrincipalDestruct
342+
| PrincipalConstruct
343+
| Append
344+
| Concat
345+
| AsMaxLen
346+
| ContractOf
347+
| PrincipalOf
348+
| ListCons
349+
| GetBlockInfo
350+
| GetBurnBlockInfo
351+
| GetStacksBlockInfo
352+
| GetTenureInfo
353+
| TupleGet
354+
| TupleMerge
355+
| Len
356+
| Print
357+
| AsContract
358+
| Begin
359+
| FetchVar
360+
| GetStxBalance
361+
| StxGetAccount
362+
| GetTokenBalance
363+
| GetAssetOwner
364+
| GetTokenSupply
365+
| ElementAt
366+
| IndexOf
367+
| Slice
368+
| ReplaceAt
369+
| BitwiseAnd
370+
| BitwiseOr
371+
| BitwiseNot
372+
| BitwiseLShift
373+
| BitwiseRShift
374+
| BitwiseXor2
375+
| ElementAtAlias
376+
| IndexOfAlias
377+
| ContractHash
378+
| ToAscii
379+
| AllowanceWithStx
380+
| AllowanceWithFt
381+
| AllowanceWithNft
382+
| AllowanceWithStacking
383+
| AllowanceAll => {
303384
// Check all arguments.
304385
self.check_each_expression_is_read_only(args)
305386
}
@@ -435,6 +516,45 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> {
435516
self.check_each_expression_is_read_only(&args[2..])
436517
.map(|args_read_only| args_read_only && is_function_read_only)
437518
}
519+
RestrictAssets => {
520+
check_arguments_at_least(3, args)?;
521+
522+
// Check the asset owner argument.
523+
let asset_owner_read_only = self.check_read_only(&args[0])?;
524+
525+
// Check the allowances argument.
526+
let allowances =
527+
args[1]
528+
.match_list()
529+
.ok_or(CheckErrorKind::ExpectedListOfAllowances(
530+
"restrict-assets?".into(),
531+
2,
532+
))?;
533+
let allowances_read_only = self.check_each_expression_is_read_only(allowances)?;
534+
535+
// Check the body expressions.
536+
let body_read_only = self.check_each_expression_is_read_only(&args[2..])?;
537+
538+
Ok(asset_owner_read_only && allowances_read_only && body_read_only)
539+
}
540+
AsContractSafe => {
541+
check_arguments_at_least(2, args)?;
542+
543+
// Check the allowances argument.
544+
let allowances =
545+
args[0]
546+
.match_list()
547+
.ok_or(CheckErrorKind::ExpectedListOfAllowances(
548+
"as-contract?".into(),
549+
1,
550+
))?;
551+
let allowances_read_only = self.check_each_expression_is_read_only(allowances)?;
552+
553+
// Check the body expressions.
554+
let body_read_only = self.check_each_expression_is_read_only(&args[1..])?;
555+
556+
Ok(allowances_read_only && body_read_only)
557+
}
438558
}
439559
}
440560

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

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -787,12 +787,43 @@ impl TypedNativeFunction {
787787
IsNone => Special(SpecialNativeFunction(&options::check_special_is_optional)),
788788
IsSome => Special(SpecialNativeFunction(&options::check_special_is_optional)),
789789
AtBlock => Special(SpecialNativeFunction(&check_special_at_block)),
790-
ElementAtAlias | IndexOfAlias | BuffToIntLe | BuffToUIntLe | BuffToIntBe
791-
| BuffToUIntBe | IsStandard | PrincipalDestruct | PrincipalConstruct | StringToInt
792-
| StringToUInt | IntToAscii | IntToUtf8 | GetBurnBlockInfo | StxTransferMemo
793-
| StxGetAccount | BitwiseAnd | BitwiseOr | BitwiseNot | BitwiseLShift
794-
| BitwiseRShift | BitwiseXor2 | Slice | ToConsensusBuff | FromConsensusBuff
795-
| ReplaceAt | GetStacksBlockInfo | GetTenureInfo | ContractHash | ToAscii => {
790+
ElementAtAlias
791+
| IndexOfAlias
792+
| BuffToIntLe
793+
| BuffToUIntLe
794+
| BuffToIntBe
795+
| BuffToUIntBe
796+
| IsStandard
797+
| PrincipalDestruct
798+
| PrincipalConstruct
799+
| StringToInt
800+
| StringToUInt
801+
| IntToAscii
802+
| IntToUtf8
803+
| GetBurnBlockInfo
804+
| StxTransferMemo
805+
| StxGetAccount
806+
| BitwiseAnd
807+
| BitwiseOr
808+
| BitwiseNot
809+
| BitwiseLShift
810+
| BitwiseRShift
811+
| BitwiseXor2
812+
| Slice
813+
| ToConsensusBuff
814+
| FromConsensusBuff
815+
| ReplaceAt
816+
| GetStacksBlockInfo
817+
| GetTenureInfo
818+
| ContractHash
819+
| ToAscii
820+
| RestrictAssets
821+
| AsContractSafe
822+
| AllowanceWithStx
823+
| AllowanceWithFt
824+
| AllowanceWithNft
825+
| AllowanceWithStacking
826+
| AllowanceAll => {
796827
return Err(CheckErrorKind::Expects(
797828
"Clarity 2+ keywords should not show up in 2.05".into(),
798829
));

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> {
11431143
Ok(())
11441144
}
11451145

1146-
// Type check an expression, with an expected_type that should _admit_ the expression.
1146+
/// Type check an expression, with an expected_type that should _admit_ the expression.
11471147
pub fn type_check_expects(
11481148
&mut self,
11491149
expr: &SymbolicExpression,
@@ -1165,7 +1165,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> {
11651165
}
11661166
}
11671167

1168-
// Type checks an expression, recursively type checking its subexpressions
1168+
/// Type checks an expression, recursively type checking its subexpressions
11691169
pub fn type_check(
11701170
&mut self,
11711171
expr: &SymbolicExpression,
@@ -1184,6 +1184,8 @@ impl<'a, 'b> TypeChecker<'a, 'b> {
11841184
result
11851185
}
11861186

1187+
/// Type checks a list of statements, ensuring that each statement is valid
1188+
/// and any responses before the last statement are handled.
11871189
fn type_check_consecutive_statements(
11881190
&mut self,
11891191
args: &[SymbolicExpression],

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ mod assets;
3939
mod conversions;
4040
mod maps;
4141
mod options;
42+
pub(crate) mod post_conditions;
4243
mod sequences;
4344

4445
#[allow(clippy::large_enum_variant)]
@@ -1225,6 +1226,15 @@ impl TypedNativeFunction {
12251226
)
12261227
})?,
12271228
))),
1229+
RestrictAssets => Special(SpecialNativeFunction(
1230+
&post_conditions::check_restrict_assets,
1231+
)),
1232+
AsContractSafe => Special(SpecialNativeFunction(&post_conditions::check_as_contract)),
1233+
AllowanceWithStx
1234+
| AllowanceWithFt
1235+
| AllowanceWithNft
1236+
| AllowanceWithStacking
1237+
| AllowanceAll => Special(SpecialNativeFunction(&post_conditions::check_allowance_err)),
12281238
};
12291239

12301240
Ok(out)

0 commit comments

Comments
 (0)