Skip to content

Commit da9953a

Browse files
committed
Add SoftFork error support, only leave ErgoTree unparsed if SoftFork error is encountered
1 parent 8142da2 commit da9953a

File tree

14 files changed

+181
-90
lines changed

14 files changed

+181
-90
lines changed

ergotree-interpreter/src/eval/deserialize_register.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ mod tests {
1414
use ergotree_ir::mir::global_vars::GlobalVars;
1515
use ergotree_ir::mir::value::Value;
1616
use ergotree_ir::serialization::SigmaSerializable;
17+
use ergotree_ir::soft_fork::SoftForkError;
1718
use ergotree_ir::types::stype::SType;
1819
use sigma_test_util::force_any_val;
1920

@@ -79,10 +80,9 @@ mod tests {
7980
assert!(matches!(
8081
try_eval_with_deserialize::<i32>(&expr, &ctx),
8182
Err(EvalError::SubstDeserializeError(
82-
ergotree_ir::mir::expr::SubstDeserializeError::ExprTpeError {
83-
expected: _,
84-
actual: _
85-
}
83+
ergotree_ir::mir::expr::SubstDeserializeError::SoftForkError(
84+
SoftForkError::DeserializedScriptError
85+
)
8686
))
8787
));
8888
// default provided
@@ -133,10 +133,9 @@ mod tests {
133133
assert!(matches!(
134134
try_eval_with_deserialize::<bool>(&expr, &ctx),
135135
Err(EvalError::SubstDeserializeError(
136-
ergotree_ir::mir::expr::SubstDeserializeError::ExprTpeError {
137-
expected: _,
138-
actual: _
139-
}
136+
ergotree_ir::mir::expr::SubstDeserializeError::SoftForkError(
137+
SoftForkError::DeserializedScriptError
138+
)
140139
))
141140
));
142141
}

ergotree-ir/src/ergo_tree.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use crate::serialization::{
1010
SigmaParsingError, SigmaSerializable,
1111
};
1212
use crate::sigma_protocol::sigma_boolean::ProveDlog;
13+
use crate::soft_fork::IsSoftForkable;
14+
use crate::soft_fork::SoftForkError;
1315
use crate::types::stype::SType;
1416

1517
use alloc::string::String;
@@ -107,9 +109,9 @@ pub enum ErgoTreeError {
107109
/// IO error
108110
#[error("IO error: {0:?}")]
109111
IoError(String),
110-
/// ErgoTree root error. ErgoTree root TPE should be SigmaProp
111-
#[error("Root Tpe error: expected SigmaProp, got {0}")]
112-
RootTpeError(SType),
112+
/// Soft-fork error condition
113+
#[error("Soft fork error: {0}")]
114+
SoftForkError(SoftForkError),
113115
}
114116

115117
/// The root of ErgoScript IR. Serialized instances of this class are self sufficient and can be passed around.
@@ -145,7 +147,7 @@ impl ErgoTree {
145147
fn sigma_parse_sized<R: SigmaByteRead>(
146148
r: &mut R,
147149
header: ErgoTreeHeader,
148-
) -> Result<ParsedErgoTree, ErgoTreeError> {
150+
) -> Result<ParsedErgoTree, SigmaParsingError> {
149151
let constants = if header.is_constant_segregation() {
150152
ErgoTree::sigma_parse_constants(r)?
151153
} else {
@@ -159,7 +161,7 @@ impl ErgoTree {
159161
let has_deserialize = r.was_deserialize();
160162
r.set_deserialize(was_deserialize);
161163
if root.tpe() != SType::SSigmaProp {
162-
return Err(ErgoTreeError::RootTpeError(root.tpe()));
164+
return Err(SoftForkError::InvalidRootType.into());
163165
}
164166
Ok(ParsedErgoTree {
165167
header,
@@ -390,16 +392,17 @@ impl SigmaSerializable for ErgoTree {
390392
ErgoTree::sigma_parse_sized(inner_r, header)
391393
}) {
392394
Ok(parsed_tree) => Ok(parsed_tree.into()),
393-
Err(error) => {
395+
Err(error) if error.is_soft_fork() => {
394396
let num_bytes = (body_pos - start_pos) + tree_size_bytes as u64;
395397
r.seek(io::SeekFrom::Start(start_pos))?;
396398
let mut bytes = vec![0; num_bytes as usize];
397399
r.read_exact(&mut bytes)?;
398400
Ok(ErgoTree::Unparsed {
399401
tree_bytes: bytes,
400-
error,
402+
error: error.into(),
401403
})
402404
}
405+
Err(error) => Err(error),
403406
}
404407
} else {
405408
let constants = if header.is_constant_segregation() {
@@ -503,6 +506,7 @@ mod tests {
503506
use crate::mir::constant::Literal;
504507
use crate::mir::deserialize_context::DeserializeContext;
505508
use crate::sigma_protocol::sigma_boolean::SigmaProp;
509+
use crate::soft_fork::SoftForkError;
506510
use proptest::prelude::*;
507511

508512
proptest! {
@@ -537,7 +541,9 @@ mod tests {
537541
];
538542
assert_eq!(
539543
ErgoTree::sigma_parse_bytes(&bytes),
540-
Err(SigmaParsingError::InvalidTypeCode(0))
544+
Err(SigmaParsingError::SoftForkError(
545+
SoftForkError::InvalidPrimitiveType(0)
546+
))
541547
);
542548
}
543549

@@ -696,7 +702,7 @@ mod tests {
696702
tree,
697703
ErgoTree::Unparsed {
698704
tree_bytes,
699-
error: ErgoTreeError::RootTpeError(SType::SByte)
705+
error: ErgoTreeError::SigmaParsingError(SoftForkError::InvalidRootType.into())
700706
}
701707
);
702708
}
@@ -725,7 +731,7 @@ mod tests {
725731
tree,
726732
ErgoTree::Unparsed {
727733
tree_bytes: bytes,
728-
error: ErgoTreeError::RootTpeError(SType::SShort)
734+
error: ErgoTreeError::SigmaParsingError(SoftForkError::InvalidRootType.into())
729735
}
730736
);
731737
}

ergotree-ir/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub mod sigma_protocol;
3838
pub mod source_span;
3939
#[macro_use]
4040
pub mod traversable;
41+
pub mod soft_fork;
4142
pub mod type_check;
4243
pub mod types;
4344
pub mod unsignedbigint256;

ergotree-ir/src/mir/expr.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::serialization::sigma_byte_reader;
1717
use crate::serialization::sigma_byte_reader::SigmaByteRead;
1818
use crate::serialization::SigmaParsingError;
1919
use crate::serialization::SigmaSerializable;
20+
use crate::soft_fork::SoftForkError;
2021
use crate::source_span::Spanned;
2122
use crate::traversable::Traversable;
2223
use crate::types::stype::LiftIntoSType;
@@ -450,10 +451,7 @@ impl Expr {
450451
_ => unreachable!(),
451452
};
452453
if parsed_expr.tpe() != *tpe {
453-
return Err(SubstDeserializeError::ExprTpeError {
454-
expected: tpe.clone(),
455-
actual: parsed_expr.tpe(),
456-
});
454+
return Err(SoftForkError::DeserializedScriptError.into());
457455
}
458456
*expr = parsed_expr;
459457
Ok(())
@@ -685,8 +683,8 @@ pub enum SubstDeserializeError {
685683
RegisterValueError(#[from] RegisterValueError),
686684
#[error("Error while parsing Expr from bytes: {0}")]
687685
ExprParsingError(#[from] SigmaParsingError),
688-
#[error("Expected tpe {expected}, found {actual}")]
689-
ExprTpeError { expected: SType, actual: SType },
686+
#[error("{0}")]
687+
SoftForkError(#[from] SoftForkError),
690688
}
691689

692690
impl<T: TryFrom<Expr>> TryExtractFrom<Expr> for T {

ergotree-ir/src/mir/sigma_prop_bytes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl OneArgOp for SigmaPropBytes {
3838

3939
impl OneArgOpTryBuild for SigmaPropBytes {
4040
fn try_build(input: Expr) -> Result<Self, InvalidArgumentError> {
41-
input.check_post_eval_tpe(&SType::SSigmaProp)?;
41+
// dbg!(&input).check_post_eval_tpe(&SType::SSigmaProp)?;
4242
Ok(SigmaPropBytes {
4343
input: input.into(),
4444
})

ergotree-ir/src/serialization/data.rs

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use ergo_chain_types::Header;
33
use sigma_ser::ScorexSerializable;
44

55
use alloc::string::String;
6-
use alloc::string::ToString;
76
use alloc::vec;
87
use alloc::vec::Vec;
98
use sigma_util::AsVecU8;
@@ -17,12 +16,12 @@ use crate::mir::constant::TryExtractFromError;
1716
use crate::mir::constant::TryExtractInto;
1817
use crate::mir::value::CollKind;
1918
use crate::mir::value::NativeColl;
20-
use crate::serialization::SigmaSerializationError;
2119
use crate::serialization::SigmaSerializeResult;
2220
use crate::serialization::{
2321
sigma_byte_reader::SigmaByteRead, SigmaParsingError, SigmaSerializable,
2422
};
2523
use crate::sigma_protocol::{sigma_boolean::SigmaBoolean, sigma_boolean::SigmaProp};
24+
use crate::soft_fork::SoftForkError;
2625
use crate::types::stuple;
2726
use crate::types::stype::SType;
2827
use crate::unsignedbigint256::UnsignedBigInt;
@@ -59,9 +58,10 @@ impl DataSerializer {
5958
v.sigma_serialize(w)?
6059
}
6160
Literal::UnsignedBigInt(_) => {
62-
return Err(SigmaSerializationError::NotSupported(
63-
"Can't serialize UnsignedBigInt with tree version < 3".into(),
64-
))
61+
return Err(SoftForkError::NotSerializable(
62+
"Can't serialize UnsignedBigInt with tree version < 3",
63+
)
64+
.into())
6565
}
6666
Literal::AvlTree(a) => a.sigma_serialize(w)?,
6767
Literal::CBox(b) => b.sigma_serialize(w)?,
@@ -101,14 +101,16 @@ impl DataSerializer {
101101
// unsupported, see
102102
// https://github.com/ScorexFoundation/sigmastate-interpreter/issues/659
103103
Literal::Opt(_) => {
104-
return Err(SigmaSerializationError::NotSupported(
105-
"Option serialization is not supported".to_string(),
106-
));
104+
return Err(SoftForkError::NotSerializable(
105+
"Option serialization is not supported",
106+
)
107+
.into());
107108
}
108109
Literal::Header(_) => {
109-
return Err(SigmaSerializationError::NotSupported(
110-
"Header serialization is not supported".to_string(),
111-
));
110+
return Err(SoftForkError::NotSerializable(
111+
"Header serialization is not supported",
112+
)
113+
.into());
112114
}
113115
})
114116
}
@@ -187,14 +189,14 @@ impl DataSerializer {
187189
SHeader if r.tree_version() >= ErgoTreeVersion::V3 => {
188190
Literal::Header(Box::new(Header::scorex_parse(r)?))
189191
}
190-
STypeVar(_) => return Err(SigmaParsingError::NotSupported("TypeVar data")),
191-
SAny => return Err(SigmaParsingError::NotSupported("SAny data")),
192-
SOption(_) => return Err(SigmaParsingError::NotSupported("SOption data")),
193-
SFunc(_) => return Err(SigmaParsingError::NotSupported("SFunc data")),
194-
SContext => return Err(SigmaParsingError::NotSupported("SContext data")),
195-
SHeader => return Err(SigmaParsingError::NotSupported("SHeader data")),
196-
SPreHeader => return Err(SigmaParsingError::NotSupported("SPreHeader data")),
197-
SGlobal => return Err(SigmaParsingError::NotSupported("SGlobal data")),
192+
STypeVar(_) => return Err(SoftForkError::NotSerializable("TypeVar data").into()),
193+
SAny => return Err(SoftForkError::NotSerializable("SAny data").into()),
194+
SOption(_) => return Err(SoftForkError::NotSerializable("SOption data").into()),
195+
SFunc(_) => return Err(SoftForkError::NotSerializable("SFunc data").into()),
196+
SContext => return Err(SoftForkError::NotSerializable("SContext data").into()),
197+
SHeader => return Err(SoftForkError::NotSerializable("SHeader data").into()),
198+
SPreHeader => return Err(SoftForkError::NotSerializable("SPreHeader data").into()),
199+
SGlobal => return Err(SoftForkError::NotSerializable("SGlobal data").into()),
198200
})
199201
}
200202
}

ergotree-ir/src/serialization/expr.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ use crate::serialization::{
7878
};
7979

8080
use crate::mir::xor_of::XorOf;
81+
use crate::soft_fork::SoftForkError;
8182
use crate::source_span::Spanned;
8283

8384
impl Expr {
@@ -192,11 +193,12 @@ impl Expr {
192193
XorOf::OP_CODE => Ok(XorOf::sigma_parse(r)?.into()),
193194
TreeLookup::OP_CODE => Ok(TreeLookup::sigma_parse(r)?.into()),
194195
CreateAvlTree::OP_CODE => Ok(CreateAvlTree::sigma_parse(r)?.into()),
195-
o => Err(SigmaParsingError::NotImplementedOpCode(format!(
196+
o => Err(SoftForkError::InvalidOpCode(format!(
196197
"{0}(shift {1})",
197198
o.value(),
198199
o.shift()
199-
))),
200+
))
201+
.into()),
200202
}
201203
};
202204
res

ergotree-ir/src/serialization/method_call.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use alloc::vec::Vec;
44

55
use crate::mir::expr::Expr;
66
use crate::mir::method_call::MethodCall;
7+
use crate::soft_fork::SoftForkError;
78
use crate::types::smethod::MethodId;
89
use crate::types::smethod::SMethod;
910
use crate::types::stype::SType;
@@ -38,10 +39,7 @@ impl SigmaSerializable for MethodCall {
3839
let arg_types = args.iter().map(|arg| arg.tpe()).collect();
3940
let method = SMethod::from_ids(type_id, method_id)?.specialize_for(obj.tpe(), arg_types)?;
4041
if r.tree_version() < method.method_raw.min_version {
41-
return Err(SigmaParsingError::UnknownMethodId(
42-
method_id,
43-
type_id.value(),
44-
));
42+
return Err(SoftForkError::UnknownMethodId(method_id, type_id.value()).into());
4543
}
4644
let explicit_type_args = method
4745
.method_raw

ergotree-ir/src/serialization/serializable.rs

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ use crate::chain::ergo_box::RegisterValueError;
33
use crate::ergo_tree::{ErgoTreeHeaderError, ErgoTreeVersion};
44
use crate::mir::val_def::ValId;
55
use crate::mir::{constant::TryExtractFromError, expr::InvalidArgumentError};
6+
use crate::soft_fork::SoftForkError;
67
use crate::types::type_unify::TypeUnificationError;
78

89
use super::{
910
constant_store::ConstantStore,
1011
sigma_byte_reader::{SigmaByteRead, SigmaByteReader},
1112
sigma_byte_writer::{SigmaByteWrite, SigmaByteWriter},
1213
};
13-
use crate::types::smethod::MethodId;
1414
use alloc::boxed::Box;
1515

1616
use alloc::string::{String, ToString};
@@ -41,6 +41,9 @@ pub enum SigmaSerializationError {
4141
/// Scorex serialization error
4242
#[error("Scorex serialization error: {0}")]
4343
ScorexSerializationError(#[from] ScorexSerializationError),
44+
/// Soft-fork error
45+
#[error("{0}")]
46+
SoftForkError(#[from] SoftForkError),
4447
}
4548

4649
impl From<io::Error> for SigmaSerializationError {
@@ -52,18 +55,6 @@ impl From<io::Error> for SigmaSerializationError {
5255
/// Ways parsing might fail
5356
#[derive(Error, Eq, PartialEq, Debug, Clone)]
5457
pub enum SigmaParsingError {
55-
/// Invalid op code
56-
#[error("invalid op code: {0}")]
57-
InvalidOpCode(u8),
58-
/// Lacking support for the op
59-
#[error("not implemented op error: {0}")]
60-
NotImplementedOpCode(String),
61-
/// Failed to parse type
62-
#[error("type parsing error, invalid type code: {0}({0:#04X})")]
63-
InvalidTypeCode(u8),
64-
/// V6 type error
65-
#[error("Can't use v6 types (UnsignedBigInt, Header, Option) in ContextExtension/Registers ")]
66-
V6TypeError,
6758
/// Failed to decode VLQ
6859
#[error("vlq encode error: {0}")]
6960
VlqEncode(#[from] vlq_encode::VlqEncodingError),
@@ -91,9 +82,6 @@ pub enum SigmaParsingError {
9182
/// Invalid argument on node creation
9283
#[error("Invalid argument: {0:?}")]
9384
InvalidArgument(#[from] InvalidArgumentError),
94-
/// Unknown method ID for given type code
95-
#[error("No method id {0:?} found in type companion with type id {1:?} ")]
96-
UnknownMethodId(MethodId, u8),
9785
/// Feature not supported
9886
#[error("parsing not supported: {0}")]
9987
NotSupported(&'static str),
@@ -112,6 +100,9 @@ pub enum SigmaParsingError {
112100
/// Invalid register value
113101
#[error("Invalid register value: {0}")]
114102
InvalidRegisterValue(#[from] RegisterValueError),
103+
/// Soft-forkable error
104+
#[error("{0}")]
105+
SoftForkError(#[from] SoftForkError),
115106
}
116107

117108
impl From<io::Error> for SigmaParsingError {

0 commit comments

Comments
 (0)