Skip to content

Commit

Permalink
Merge branch 'master' into chore/merge-master-to-next
Browse files Browse the repository at this point in the history
  • Loading branch information
jcnelson committed Dec 15, 2022
2 parents 0e615ec + a71871a commit 793f8ed
Show file tree
Hide file tree
Showing 49 changed files with 2,305 additions and 585 deletions.
7 changes: 6 additions & 1 deletion .cargo/config
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
[alias]
stacks-node = "run --package stacks-node --"
stacks-node = "run --package stacks-node --"

# Needed by perf to generate flamegraphs.
#[target.x86_64-unknown-linux-gnu]
#linker = "/usr/bin/clang"
#rustflags = ["-Clink-arg=-fuse-ld=lld", "-Clink-arg=-Wl,--no-rosegment"]
1 change: 1 addition & 0 deletions .github/workflows/bitcoin-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ jobs:
- tests::epoch_21::transition_adds_mining_from_segwit
- tests::epoch_21::transition_removes_pox_sunset
- tests::epoch_21::transition_empty_blocks
- tests::neon_integrations::bad_microblock_pubkey
steps:
- uses: actions/checkout@v2
- name: Download docker image
Expand Down
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@ This release will contain consensus-breaking changes.
stacks-node uses for logging.
Example: `STACKS_LOG_FORMAT_TIME="%Y-%m-%d %H:%M:%S" cargo stacks-node`

## [2.05.0.6.0]

### Changed

- The `/v2/neighbors` endpoint now reports a node's bootstrap peers, so other
nodes can find high-quality nodes to boot from (#3401)
- If there are two or more Stacks chain tips that are tied for the canonical
tip, the node deterministically chooses one _independent_ of the arrival order
(#3419).
- If Stacks blocks for a different fork arrive out-of-order and, in doing so,
constitute a better fork than the fork the node considers canonical, the node
will update the canonical Stacks tip pointer in the sortition DB before
processing the next sortition (#3419).

### Fixed

- The node keychain no longer maintains any internal state, but instead derives
keys based on the chain tip the miner is building off of. This prevents the
node from accidentally producing an invalid block that reuses a microblock
public key hash (#3387).
- If a node mines an invalid block for some reason, it will no longer stall
forever. Instead, it will detect that its last-mined block is not the chain
tip, and resume mining (#3406).

## [2.05.0.5.0]

### Changed
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ stacks_common = { package = "stacks-common", features = ["default", "testing"],

[features]
default = ["developer-mode"]
profile-sqlite = []
disable-costs = []
developer-mode = []
monitoring_prom = ["prometheus"]
slog_json = ["slog-json", "stacks_common/slog_json", "clarity/slog_json"]
Expand Down
4 changes: 3 additions & 1 deletion clarity/src/vm/analysis/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub enum CheckErrors {
UncheckedIntermediaryResponses,

CouldNotDetermineMatchTypes,
CouldNotDetermineType,

// Checker runtime failures
TypeAlreadyAnnotatedFailure,
Expand Down Expand Up @@ -357,6 +358,7 @@ impl DiagnosableError for CheckErrors {
CheckErrors::CouldNotDetermineResponseOkType => format!("attempted to obtain 'ok' value from response, but 'ok' type is indeterminate"),
CheckErrors::CouldNotDetermineResponseErrType => format!("attempted to obtain 'err' value from response, but 'err' type is indeterminate"),
CheckErrors::CouldNotDetermineMatchTypes => format!("attempted to match on an (optional) or (response) type where either the some, ok, or err type is indeterminate. you may wish to use unwrap-panic or unwrap-err-panic instead."),
CheckErrors::CouldNotDetermineType => format!("type of expression cannot be determined"),
CheckErrors::BadTupleFieldName => format!("invalid tuple field name"),
CheckErrors::ExpectedTuple(type_signature) => format!("expecting tuple, found '{}'", type_signature),
CheckErrors::NoSuchTupleField(field_name, tuple_signature) => format!("cannot find field '{}' in tuple '{}'", field_name, tuple_signature),
Expand Down Expand Up @@ -430,7 +432,7 @@ impl DiagnosableError for CheckErrors {
CheckErrors::InvalidUTF8Encoding => format!("invalid UTF8 encoding"),
CheckErrors::InvalidSecp65k1Signature => format!("invalid seckp256k1 signature"),
CheckErrors::TypeAlreadyAnnotatedFailure | CheckErrors::CheckerImplementationFailure => {
format!("internal error - please file an issue on github.com/blockstack/blockstack-core")
format!("internal error - please file an issue on https://github.com/stacks-network/stacks-blockchain")
},
CheckErrors::UncheckedIntermediaryResponses => format!("intermediary responses in consecutive statements must be checked"),
CheckErrors::CostComputationFailed(s) => format!("contract cost computation failed: {}", s),
Expand Down
16 changes: 8 additions & 8 deletions clarity/src/vm/analysis/type_checker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ impl FunctionType {
check_arguments_at_least(1, args)?;
for found_type in args.iter() {
analysis_typecheck_cost(accounting, expected_type, found_type)?;
if !expected_type.admits_type(found_type) {
if !expected_type.admits_type(found_type)? {
return Err(CheckErrors::TypeError(
expected_type.clone(),
found_type.clone(),
Expand All @@ -178,7 +178,7 @@ impl FunctionType {
for (expected_type, found_type) in arg_types.iter().map(|x| &x.signature).zip(args)
{
analysis_typecheck_cost(accounting, expected_type, found_type)?;
if !expected_type.admits_type(found_type) {
if !expected_type.admits_type(found_type)? {
return Err(CheckErrors::TypeError(
expected_type.clone(),
found_type.clone(),
Expand All @@ -193,7 +193,7 @@ impl FunctionType {
let found_type = &args[0];
for expected_type in arg_types.iter() {
analysis_typecheck_cost(accounting, expected_type, found_type)?;
if expected_type.admits_type(found_type) {
if expected_type.admits_type(found_type)? {
return Ok(return_type.clone());
}
}
Expand Down Expand Up @@ -438,7 +438,7 @@ impl FunctionType {
contract_to_check.check_trait_compliance(trait_id, &trait_definition)?;
}
(expected_type, value) => {
if !expected_type.admits(&value) {
if !expected_type.admits(&value)? {
let actual_type = TypeSignature::type_of(&value);
return Err(
CheckErrors::TypeError(expected_type.clone(), actual_type).into()
Expand Down Expand Up @@ -476,7 +476,7 @@ fn check_function_arg_signature<T: CostTracker>(
match expected_sig {
FunctionArgSignature::Single(expected_type) => {
analysis_typecheck_cost(cost_tracker, expected_type, actual_type)?;
if !expected_type.admits_type(actual_type) {
if !expected_type.admits_type(actual_type)? {
return Err(
CheckErrors::TypeError(expected_type.clone(), actual_type.clone()).into(),
);
Expand All @@ -486,7 +486,7 @@ fn check_function_arg_signature<T: CostTracker>(
let mut admitted = false;
for expected_type in expected_types.iter() {
analysis_typecheck_cost(cost_tracker, expected_type, actual_type)?;
if expected_type.admits_type(actual_type) {
if expected_type.admits_type(actual_type)? {
admitted = true;
break;
}
Expand Down Expand Up @@ -751,7 +751,7 @@ fn clarity2_inner_type_check_type<T: CostTracker>(
}
(TypeSignature::NoType, _) => (),
(_, _) => {
if !expected_type.admits_type(&actual_type) {
if !expected_type.admits_type(&actual_type)? {
return Err(
CheckErrors::TypeError(expected_type.clone(), actual_type.clone()).into(),
);
Expand Down Expand Up @@ -1235,7 +1235,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> {
let actual_type = self.type_check(expr, context)?;
analysis_typecheck_cost(self, expected_type, &actual_type)?;

if !expected_type.admits_type(&actual_type) {
if !expected_type.admits_type(&actual_type)? {
let mut err: CheckError =
CheckErrors::TypeError(expected_type.clone(), actual_type).into();
err.set_expression(expr);
Expand Down
8 changes: 4 additions & 4 deletions clarity/src/vm/analysis/type_checker/natives/maps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn check_special_fetch_entry(

let option_type = TypeSignature::new_option(value_type.clone())?;

if !expected_key_type.admits_type(&key_type) {
if !expected_key_type.admits_type(&key_type)? {
return Err(CheckError::new(CheckErrors::TypeError(
expected_key_type.clone(),
key_type,
Expand Down Expand Up @@ -91,7 +91,7 @@ pub fn check_special_delete_entry(
)?;
analysis_typecheck_cost(&mut checker.cost_track, expected_key_type, &key_type)?;

if !expected_key_type.admits_type(&key_type) {
if !expected_key_type.admits_type(&key_type)? {
return Err(CheckError::new(CheckErrors::TypeError(
expected_key_type.clone(),
key_type,
Expand Down Expand Up @@ -132,12 +132,12 @@ fn check_set_or_insert_entry(
analysis_typecheck_cost(&mut checker.cost_track, expected_key_type, &key_type)?;
analysis_typecheck_cost(&mut checker.cost_track, expected_value_type, &value_type)?;

if !expected_key_type.admits_type(&key_type) {
if !expected_key_type.admits_type(&key_type)? {
return Err(CheckError::new(CheckErrors::TypeError(
expected_key_type.clone(),
key_type,
)));
} else if !expected_value_type.admits_type(&value_type) {
} else if !expected_value_type.admits_type(&value_type)? {
return Err(CheckError::new(CheckErrors::TypeError(
expected_value_type.clone(),
value_type,
Expand Down
2 changes: 1 addition & 1 deletion clarity/src/vm/analysis/type_checker/natives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ fn check_special_set_var(
)?;
analysis_typecheck_cost(&mut checker.cost_track, &value_type, &expected_value_type)?;

if !expected_value_type.admits_type(&value_type) {
if !expected_value_type.admits_type(&value_type)? {
return Err(CheckError::new(CheckErrors::TypeError(
expected_value_type.clone(),
value_type,
Expand Down
6 changes: 3 additions & 3 deletions clarity/src/vm/analysis/type_checker/natives/sequences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,16 +310,16 @@ pub fn check_special_as_max_len(
)))
}
TypeSignature::SequenceType(BufferType(_)) => Ok(TypeSignature::OptionalType(Box::new(
TypeSignature::SequenceType(BufferType(BufferLength::try_from(expected_len).unwrap())),
TypeSignature::SequenceType(BufferType(BufferLength::try_from(expected_len)?)),
))),
TypeSignature::SequenceType(StringType(ASCII(_))) => Ok(TypeSignature::OptionalType(
Box::new(TypeSignature::SequenceType(StringType(ASCII(
BufferLength::try_from(expected_len).unwrap(),
BufferLength::try_from(expected_len)?,
)))),
)),
TypeSignature::SequenceType(StringType(UTF8(_))) => Ok(TypeSignature::OptionalType(
Box::new(TypeSignature::SequenceType(StringType(UTF8(
StringUTF8Length::try_from(expected_len).unwrap(),
StringUTF8Length::try_from(expected_len)?,
)))),
)),
_ => Err(CheckErrors::ExpectedSequence(sequence).into()),
Expand Down
28 changes: 26 additions & 2 deletions clarity/src/vm/analysis/type_checker/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ fn test_from_consensus_buff() {
assert_eq!(expected, &type_result.to_string());

assert!(
type_result.admits(&execute_v2(good_test).unwrap().unwrap()),
type_result
.admits(&execute_v2(good_test).unwrap().unwrap())
.unwrap(),
"The analyzed type must admit the evaluated type"
);
}
Expand Down Expand Up @@ -220,7 +222,9 @@ fn test_to_consensus_buff() {
assert_eq!(expected, &type_result.to_string());

assert!(
type_result.admits(&execute_v2(good_test).unwrap().unwrap()),
type_result
.admits(&execute_v2(good_test).unwrap().unwrap())
.unwrap(),
"The analyzed type must admit the evaluated type"
);
}
Expand Down Expand Up @@ -1039,6 +1043,9 @@ fn test_index_of() {
"(index-of? 0xfedb \"a\")",
"(index-of? u\"a\" \"a\")",
"(index-of? \"a\" u\"a\")",
"(index-of (list) none)", // cannot determine type of list element
"(index-of (list) (ok u1))", // cannot determine complete type of list element
"(index-of (list) (err none))", // cannot determine complete type of list element
];

let bad_expected = [
Expand Down Expand Up @@ -1074,6 +1081,9 @@ fn test_index_of() {
TypeSignature::min_string_ascii(),
TypeSignature::min_string_utf8(),
),
CheckErrors::CouldNotDetermineType,
CheckErrors::CouldNotDetermineType,
CheckErrors::CouldNotDetermineType,
];

for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) {
Expand Down Expand Up @@ -1385,6 +1395,20 @@ fn test_native_as_max_len() {
&format!("{}", type_check_helper(&good_test).unwrap())
);
}

let bad = [
"(as-max-len? \"\" u1048577)",
"(as-max-len? u\"\" u1048577)",
"(as-max-len? 0x01 u1048577)",
];
let bad_expected = [
CheckErrors::ValueTooLarge,
CheckErrors::ValueTooLarge,
CheckErrors::ValueTooLarge,
];
for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) {
assert_eq!(expected, &type_check_helper(&bad_test).unwrap_err().err);
}
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions clarity/src/vm/analysis/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,15 @@ impl ContractAnalysis {
(Some(FunctionType::Fixed(func)), None)
| (None, Some(FunctionType::Fixed(func))) => {
let args_sig = func.args.iter().map(|a| a.signature.clone()).collect();
if !expected_sig.check_args_trait_compliance(args_sig) {
if !expected_sig.check_args_trait_compliance(args_sig)? {
return Err(CheckErrors::BadTraitImplementation(
trait_name,
func_name.to_string(),
)
.into());
}

if !expected_sig.returns.admits_type(&func.returns) {
if !expected_sig.returns.admits_type(&func.returns)? {
return Err(CheckErrors::BadTraitImplementation(
trait_name,
func_name.to_string(),
Expand Down
6 changes: 3 additions & 3 deletions clarity/src/vm/callables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ impl DefinedFunction {
);
}
_ => {
if !type_sig.admits(value) {
if !type_sig.admits(value)? {
return Err(CheckErrors::TypeValueError(
type_sig.clone(),
value.clone(),
Expand Down Expand Up @@ -232,7 +232,7 @@ impl DefinedFunction {
);
}
_ => {
if !type_sig.admits(&cast_value) {
if !type_sig.admits(&cast_value)? {
return Err(
CheckErrors::TypeValueError(type_sig.clone(), cast_value).into()
);
Expand Down Expand Up @@ -277,7 +277,7 @@ impl DefinedFunction {
))?;

let args = self.arg_types.iter().map(|a| a.clone()).collect();
if !expected_sig.check_args_trait_compliance(args) {
if !expected_sig.check_args_trait_compliance(args)? {
return Err(
CheckErrors::BadTraitImplementation(trait_name, self.name.to_string()).into(),
);
Expand Down
4 changes: 4 additions & 0 deletions clarity/src/vm/costs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,10 @@ fn compute_cost(

fn add_cost(s: &mut TrackerData, cost: ExecutionCost) -> std::result::Result<(), CostErrors> {
s.total.add(&cost)?;
if cfg!(feature = "disable-costs") {
// Disable check for exceeding the cost limit to allow mining large blocks for profiling purposes.
return Ok(());
}
if s.total.exceeds(&s.limit) {
Err(CostErrors::CostBalanceExceeded(
s.total.clone(),
Expand Down
Loading

0 comments on commit 793f8ed

Please sign in to comment.