Skip to content

Commit 1ab6e7a

Browse files
committed
feat: add error handling to script encode and decode
1 parent 783671d commit 1ab6e7a

File tree

4 files changed

+72
-44
lines changed

4 files changed

+72
-44
lines changed

node/src/actors/chain_manager/handlers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,7 @@ impl Handler<BuildScriptTransaction> for ChainManager {
13071307
.into_actor(self)
13081308
.then(|s, _act, _ctx| match s {
13091309
Ok(_signatures) => {
1310-
let multi_sig_witness = witnet_stack::encode(vec![]);
1310+
let multi_sig_witness = witnet_stack::encode(vec![]).unwrap();
13111311
let num_inputs = vtt.inputs.len();
13121312
let transaction = Transaction::ValueTransfer(VTTransaction {
13131313
body: vtt,

src/cli/node/json_rpc_client.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ pub fn create_multisig_address(
737737
]);
738738

739739
let locking_script_hash =
740-
PublicKeyHash::from_script_bytes(&witnet_stack::encode(redeem_script));
740+
PublicKeyHash::from_script_bytes(&witnet_stack::encode(redeem_script)?);
741741

742742
println!(
743743
"Sending to {}-of-{} multisig address {} composed of {:?}",
@@ -778,7 +778,7 @@ pub fn create_opened_multisig(
778778
Item::Value(MyValue::Integer(i128::from(n))),
779779
Item::Operator(MyOperator::CheckMultiSig),
780780
]);
781-
let redeem_script_bytes = witnet_stack::encode(redeem_script);
781+
let redeem_script_bytes = witnet_stack::encode(redeem_script)?;
782782
let vt_outputs = vec![ValueTransferOutput {
783783
pkh: address,
784784
value,
@@ -854,13 +854,13 @@ pub fn sign_tx(addr: SocketAddr, hex: String, dry_run: bool) -> Result<(), failu
854854
match tx {
855855
Transaction::ValueTransfer(ref mut vtt) => {
856856
let signature_bytes = signature.to_pb_bytes()?;
857-
let mut script = witnet_stack::decode(&vtt.witness[0]);
857+
let mut script = witnet_stack::decode(&vtt.witness[0])?;
858858

859859
println!("Previous script:\n{:?}", script);
860860
script.push(Item::Value(MyValue::Signature(signature_bytes)));
861861

862862
println!("Post script:\n{:?}", script);
863-
let encoded_script = witnet_stack::encode(script);
863+
let encoded_script = witnet_stack::encode(script)?;
864864

865865
vtt.witness[0] = encoded_script;
866866

stack/src/lib.rs

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use scriptful::{
33
prelude::Stack,
44
};
55
use serde::{Deserialize, Serialize};
6+
use std::fmt::Formatter;
67
use std::marker::PhantomData;
78

89
use witnet_crypto::hash::{calculate_sha256, Sha256};
@@ -364,22 +365,41 @@ where
364365
}
365366
}
366367

367-
pub fn decode(a: &[u8]) -> Script<MyOperator, MyValue> {
368-
let x: Vec<Item2<MyOperator, MyValue>> = serde_json::from_slice(a).unwrap();
368+
pub fn decode(a: &[u8]) -> Result<Script<MyOperator, MyValue>, ScriptError> {
369+
let x: Vec<Item2<MyOperator, MyValue>> =
370+
serde_json::from_slice(a).map_err(ScriptError::Decode)?;
369371

370-
x.into_iter().map(Into::into).collect()
372+
Ok(x.into_iter().map(Into::into).collect())
371373
}
372374

373-
pub fn encode(a: Script<MyOperator, MyValue>) -> Vec<u8> {
375+
pub fn encode(a: Script<MyOperator, MyValue>) -> Result<Vec<u8>, ScriptError> {
374376
let x: Vec<Item2<MyOperator, MyValue>> = a.into_iter().map(Into::into).collect();
375-
serde_json::to_vec(&x).unwrap()
377+
378+
serde_json::to_vec(&x).map_err(ScriptError::Encode)
376379
}
377380

378381
#[derive(Default)]
379382
pub struct ScriptContext {
380383
pub block_timestamp: i64,
381384
}
382385

386+
#[derive(Debug)]
387+
pub enum ScriptError {
388+
Decode(serde_json::Error),
389+
Encode(serde_json::Error),
390+
}
391+
392+
impl std::fmt::Display for ScriptError {
393+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
394+
match self {
395+
ScriptError::Decode(e) => write!(f, "Decode script failed: {}", e),
396+
ScriptError::Encode(e) => write!(f, "Encode script failed: {}", e),
397+
}
398+
}
399+
}
400+
401+
impl std::error::Error for ScriptError {}
402+
383403
fn execute_script(script: Script<MyOperator, MyValue>, context: &ScriptContext) -> bool {
384404
// Instantiate the machine with a reference to your operator system.
385405
let mut machine = Machine2::new(|a, b, c| my_operator_system(a, b, c, context));
@@ -411,26 +431,26 @@ fn execute_redeem_script(
411431
witness_bytes: &[u8],
412432
redeem_bytes: &[u8],
413433
context: &ScriptContext,
414-
) -> bool {
434+
) -> Result<bool, ScriptError> {
415435
// Execute witness script concatenated with redeem script
416-
let mut witness_script = decode(witness_bytes);
417-
let redeem_script = decode(redeem_bytes);
436+
let mut witness_script = decode(witness_bytes)?;
437+
let redeem_script = decode(redeem_bytes)?;
418438
witness_script.extend(redeem_script);
419439

420440
// Execute the script
421-
execute_script(witness_script, context)
441+
Ok(execute_script(witness_script, context))
422442
}
423443

424444
pub fn execute_complete_script(
425445
witness_bytes: &[u8],
426446
redeem_bytes: &[u8],
427447
locking_bytes: &[u8; 20],
428448
context: &ScriptContext,
429-
) -> bool {
449+
) -> Result<bool, ScriptError> {
430450
// Execute locking script
431451
let result = execute_locking_script(redeem_bytes, locking_bytes, context);
432452
if !result {
433-
return false;
453+
return Ok(false);
434454
}
435455

436456
// Execute witness script concatenated with redeem script
@@ -531,15 +551,15 @@ mod tests {
531551
let redeem_script = vec![Item::Operator(MyOperator::Equal)];
532552
let locking_script = EQUAL_OPERATOR_HASH;
533553
assert!(execute_locking_script(
534-
&encode(redeem_script),
554+
&encode(redeem_script).unwrap(),
535555
&locking_script,
536556
&ScriptContext::default(),
537557
));
538558

539559
let redeem_script = vec![Item::Operator(MyOperator::Equal)];
540560
let locking_script = [1; 20];
541561
assert!(!execute_locking_script(
542-
&encode(redeem_script),
562+
&encode(redeem_script).unwrap(),
543563
&locking_script,
544564
&ScriptContext::default(),
545565
));
@@ -553,21 +573,23 @@ mod tests {
553573
];
554574
let redeem_script = vec![Item::Operator(MyOperator::Equal)];
555575
assert!(execute_redeem_script(
556-
&encode(witness),
557-
&encode(redeem_script),
576+
&encode(witness).unwrap(),
577+
&encode(redeem_script).unwrap(),
558578
&ScriptContext::default(),
559-
));
579+
)
580+
.unwrap());
560581

561582
let witness = vec![
562583
Item::Value(MyValue::String("patata".to_string())),
563584
Item::Value(MyValue::String("potato".to_string())),
564585
];
565586
let redeem_script = vec![Item::Operator(MyOperator::Equal)];
566587
assert!(!execute_redeem_script(
567-
&encode(witness),
568-
&encode(redeem_script),
588+
&encode(witness).unwrap(),
589+
&encode(redeem_script).unwrap(),
569590
&ScriptContext::default(),
570-
));
591+
)
592+
.unwrap());
571593
}
572594

573595
#[test]
@@ -579,11 +601,12 @@ mod tests {
579601
let redeem_script = vec![Item::Operator(MyOperator::Equal)];
580602
let locking_script = EQUAL_OPERATOR_HASH;
581603
assert!(execute_complete_script(
582-
&encode(witness),
583-
&encode(redeem_script),
604+
&encode(witness).unwrap(),
605+
&encode(redeem_script).unwrap(),
584606
&locking_script,
585607
&ScriptContext::default(),
586-
));
608+
)
609+
.unwrap());
587610

588611
let witness = vec![
589612
Item::Value(MyValue::String("patata".to_string())),
@@ -592,11 +615,12 @@ mod tests {
592615
let redeem_script = vec![Item::Operator(MyOperator::Equal)];
593616
let locking_script = EQUAL_OPERATOR_HASH;
594617
assert!(!execute_complete_script(
595-
&encode(witness),
596-
&encode(redeem_script),
618+
&encode(witness).unwrap(),
619+
&encode(redeem_script).unwrap(),
597620
&locking_script,
598621
&ScriptContext::default(),
599-
));
622+
)
623+
.unwrap());
600624

601625
let witness = vec![
602626
Item::Value(MyValue::String("patata".to_string())),
@@ -605,11 +629,12 @@ mod tests {
605629
let redeem_script = vec![Item::Operator(MyOperator::Equal)];
606630
let locking_script: [u8; 20] = [1; 20];
607631
assert!(!execute_complete_script(
608-
&encode(witness),
609-
&encode(redeem_script),
632+
&encode(witness).unwrap(),
633+
&encode(redeem_script).unwrap(),
610634
&locking_script,
611635
&ScriptContext::default(),
612-
));
636+
)
637+
.unwrap());
613638
}
614639

615640
fn ks_from_pk(pk: PublicKey) -> KeyedSignature {
@@ -641,10 +666,11 @@ mod tests {
641666
Item::Operator(MyOperator::CheckMultiSig),
642667
];
643668
assert!(execute_redeem_script(
644-
&encode(witness),
645-
&encode(redeem_script),
669+
&encode(witness).unwrap(),
670+
&encode(redeem_script).unwrap(),
646671
&ScriptContext::default(),
647-
));
672+
)
673+
.unwrap());
648674

649675
let other_valid_witness = vec![
650676
Item::Value(MyValue::Signature(ks_1.to_pb_bytes().unwrap())),
@@ -659,10 +685,11 @@ mod tests {
659685
Item::Operator(MyOperator::CheckMultiSig),
660686
];
661687
assert!(execute_redeem_script(
662-
&encode(other_valid_witness),
663-
&encode(redeem_script),
688+
&encode(other_valid_witness).unwrap(),
689+
&encode(redeem_script).unwrap(),
664690
&ScriptContext::default(),
665-
));
691+
)
692+
.unwrap());
666693

667694
let pk_4 = PublicKey::from_bytes([4; 33]);
668695
let ks_4 = ks_from_pk(pk_4);
@@ -679,10 +706,11 @@ mod tests {
679706
Item::Operator(MyOperator::CheckMultiSig),
680707
];
681708
assert!(!execute_redeem_script(
682-
&encode(invalid_witness),
683-
&encode(redeem_script),
709+
&encode(invalid_witness).unwrap(),
710+
&encode(redeem_script).unwrap(),
684711
&ScriptContext::default(),
685-
));
712+
)
713+
.unwrap());
686714
}
687715

688716
#[test]

validations/src/validations.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,7 +1273,7 @@ pub fn validate_transaction_signatures(
12731273
&input.redeem_script,
12741274
redeem_script_hash.bytes(),
12751275
&script_context,
1276-
);
1276+
)?;
12771277

12781278
if !res {
12791279
return Err(TransactionError::ScriptExecutionFailed {
@@ -1284,7 +1284,7 @@ pub fn validate_transaction_signatures(
12841284
.into());
12851285
}
12861286

1287-
let witness_script = witnet_stack::decode(witness);
1287+
let witness_script = witnet_stack::decode(witness)?;
12881288
let mut num_signatures = 0;
12891289
// The witness field must have at least one signature
12901290
for item in witness_script {

0 commit comments

Comments
 (0)