Skip to content

Commit 5b8c709

Browse files
committed
Add SoftFork error support, only leave ErgoTree unparsed if SoftFork error is encountered
1 parent 6f12ef8 commit 5b8c709

File tree

16 files changed

+199
-96
lines changed

16 files changed

+199
-96
lines changed

bindings/ergo-lib-c-core/src/error_conversion.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use ergo_lib::ergotree_ir::chain::address::AddressError;
1616
use ergo_lib::ergotree_ir::chain::ergo_box::box_value::BoxValueError;
1717
use ergo_lib::ergotree_ir::chain::ergo_box::RegisterValueError;
1818
use ergo_lib::ergotree_ir::chain::token::TokenAmountError;
19+
use ergo_lib::ergotree_ir::soft_fork::SoftForkError;
1920
use ergo_lib::wallet::derivation_path::ChildIndexError;
2021
use ergo_lib::wallet::signing::TxSigningError;
2122
use ergo_lib::wallet::tx_context::TransactionContextError;
@@ -58,6 +59,7 @@ convert_error!(WalletError);
5859
convert_error!(DecodeError);
5960
convert_error!(TryFromSliceError);
6061
convert_error!(TransactionContextError);
62+
convert_error!(SoftForkError);
6163

6264
macro_rules! convert_error_via_debug {
6365
($t:ident) => {

bindings/ergo-lib-wasm/src/error_conversion.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use ergo_lib::ergotree_ir::chain::address::AddressError;
1818
use ergo_lib::ergotree_ir::chain::ergo_box::box_value::BoxValueError;
1919
use ergo_lib::ergotree_ir::chain::ergo_box::RegisterValueError;
2020
use ergo_lib::ergotree_ir::chain::token::TokenAmountError;
21+
use ergo_lib::ergotree_ir::soft_fork::SoftForkError;
2122
use ergo_lib::wallet::derivation_path::ChildIndexError;
2223
use ergo_lib::wallet::derivation_path::DerivationPathError;
2324
use ergo_lib::wallet::ext_pub_key::ExtPubKeyError;
@@ -99,6 +100,7 @@ from_error_to_wrap!(TransactionContextError);
99100
from_error_to_wrap!(TxValidationError);
100101
from_error_to_wrap!(RegisterValueError);
101102
from_error_to_wrap!(String);
103+
from_error_to_wrap!(SoftForkError);
102104

103105
macro_rules! from_error_to_wrap_via_debug {
104106
($t:ident) => {

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: 23 additions & 16 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.
@@ -120,14 +122,14 @@ pub enum ErgoTree {
120122
/// Original tree bytes
121123
tree_bytes: Vec<u8>,
122124
/// Parsing error
123-
error: ErgoTreeError,
125+
error: SoftForkError,
124126
},
125127
/// Parsed tree
126128
Parsed(ParsedErgoTree),
127129
}
128130

129131
impl ErgoTree {
130-
fn parsed_tree(&self) -> Result<&ParsedErgoTree, ErgoTreeError> {
132+
fn parsed_tree(&self) -> Result<&ParsedErgoTree, SoftForkError> {
131133
match self {
132134
ErgoTree::Unparsed {
133135
tree_bytes: _,
@@ -138,14 +140,14 @@ impl ErgoTree {
138140
}
139141

140142
/// Return ErgoTreeHeader. Errors if deserializing ergotree failed
141-
pub fn header(&self) -> Result<ErgoTreeHeader, ErgoTreeError> {
143+
pub fn header(&self) -> Result<ErgoTreeHeader, SoftForkError> {
142144
self.parsed_tree().map(|parsed| parsed.header.clone())
143145
}
144146

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,
@@ -273,21 +275,21 @@ impl ErgoTree {
273275

274276
/// Returns constants number as stored in serialized ErgoTree or error if the parsing of
275277
/// constants is failed
276-
pub fn constants_len(&self) -> Result<usize, ErgoTreeError> {
278+
pub fn constants_len(&self) -> Result<usize, SoftForkError> {
277279
self.parsed_tree().map(|tree| tree.constants.len())
278280
}
279281

280282
/// Returns constant with given index (as stored in serialized ErgoTree)
281283
/// or None if index is out of bounds
282284
/// or error if constants parsing were failed
283-
pub fn get_constant(&self, index: usize) -> Result<Option<Constant>, ErgoTreeError> {
285+
pub fn get_constant(&self, index: usize) -> Result<Option<Constant>, SoftForkError> {
284286
self.parsed_tree()
285287
.map(|tree| tree.constants.get(index).cloned())
286288
}
287289

288290
/// Returns all constants (as stored in serialized ErgoTree)
289291
/// or error if constants parsing were failed
290-
pub fn get_constants(&self) -> Result<Vec<Constant>, ErgoTreeError> {
292+
pub fn get_constants(&self) -> Result<Vec<Constant>, SoftForkError> {
291293
self.parsed_tree().map(|tree| tree.constants.clone())
292294
}
293295

@@ -390,16 +392,18 @@ 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+
#[allow(clippy::unwrap_used)] // Error is checked to be soft fork condition above
403+
error: error.to_soft_fork().unwrap().clone(),
401404
})
402405
}
406+
Err(error) => Err(error),
403407
}
404408
} else {
405409
let constants = if header.is_constant_segregation() {
@@ -503,6 +507,7 @@ mod tests {
503507
use crate::mir::constant::Literal;
504508
use crate::mir::deserialize_context::DeserializeContext;
505509
use crate::sigma_protocol::sigma_boolean::SigmaProp;
510+
use crate::soft_fork::SoftForkError;
506511
use proptest::prelude::*;
507512

508513
proptest! {
@@ -537,7 +542,9 @@ mod tests {
537542
];
538543
assert_eq!(
539544
ErgoTree::sigma_parse_bytes(&bytes),
540-
Err(SigmaParsingError::InvalidTypeCode(0))
545+
Err(SigmaParsingError::SoftForkError(
546+
SoftForkError::InvalidPrimitiveType(0)
547+
))
541548
);
542549
}
543550

@@ -696,7 +703,7 @@ mod tests {
696703
tree,
697704
ErgoTree::Unparsed {
698705
tree_bytes,
699-
error: ErgoTreeError::RootTpeError(SType::SByte)
706+
error: SoftForkError::InvalidRootType
700707
}
701708
);
702709
}
@@ -725,7 +732,7 @@ mod tests {
725732
tree,
726733
ErgoTree::Unparsed {
727734
tree_bytes: bytes,
728-
error: ErgoTreeError::RootTpeError(SType::SShort)
735+
error: SoftForkError::InvalidRootType
729736
}
730737
);
731738
}

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

0 commit comments

Comments
 (0)