From 389f419676bb5090c696ba62a033500391e69cfd Mon Sep 17 00:00:00 2001 From: Brandon Kite Date: Thu, 31 Mar 2022 11:56:28 -0700 Subject: [PATCH] Receipt Error Improvements (#99) * make panic receipt more transparent, make script result handle reverts --- fuel-tx/src/lib.rs | 2 +- fuel-tx/src/receipt.rs | 15 +-- fuel-tx/src/receipt/receipt_std.rs | 5 +- fuel-tx/src/receipt/script_result.rs | 36 ++++++++ fuel-tx/tests/bytes.rs | 131 ++++++++++++++++++++------- 5 files changed, 149 insertions(+), 40 deletions(-) create mode 100644 fuel-tx/src/receipt/script_result.rs diff --git a/fuel-tx/src/lib.rs b/fuel-tx/src/lib.rs index 80323e6c8d..98b470a19e 100644 --- a/fuel-tx/src/lib.rs +++ b/fuel-tx/src/lib.rs @@ -28,7 +28,7 @@ mod transaction; pub use builder::TransactionBuilder; #[cfg(feature = "alloc")] -pub use receipt::Receipt; +pub use receipt::{Receipt, ScriptExecutionResult}; #[cfg(feature = "alloc")] pub use transaction::{ diff --git a/fuel-tx/src/receipt.rs b/fuel-tx/src/receipt.rs index c0abac35c7..e7b11c291d 100644 --- a/fuel-tx/src/receipt.rs +++ b/fuel-tx/src/receipt.rs @@ -8,9 +8,12 @@ use alloc::vec::Vec; mod receipt_std; mod receipt_repr; +mod script_result; use receipt_repr::ReceiptRepr; +pub use script_result::ScriptExecutionResult; + #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr( feature = "serde-types-minimal", @@ -48,7 +51,7 @@ pub enum Receipt { Panic { id: ContractId, - reason: Word, + reason: InstructionResult, pc: Word, is: Word, }, @@ -101,7 +104,7 @@ pub enum Receipt { }, ScriptResult { - result: InstructionResult, + result: ScriptExecutionResult, gas_used: Word, }, } @@ -156,7 +159,7 @@ impl Receipt { } } - pub const fn panic(id: ContractId, reason: Word, pc: Word, is: Word) -> Self { + pub const fn panic(id: ContractId, reason: InstructionResult, pc: Word, is: Word) -> Self { Self::Panic { id, reason, pc, is } } @@ -244,7 +247,7 @@ impl Receipt { } } - pub const fn script_result(result: InstructionResult, gas_used: Word) -> Self { + pub const fn script_result(result: ScriptExecutionResult, gas_used: Word) -> Self { Self::ScriptResult { result, gas_used } } @@ -394,7 +397,7 @@ impl Receipt { } } - pub const fn reason(&self) -> Option { + pub const fn reason(&self) -> Option { match self { Self::Panic { reason, .. } => Some(*reason), _ => None, @@ -432,7 +435,7 @@ impl Receipt { } } - pub const fn result(&self) -> Option<&InstructionResult> { + pub const fn result(&self) -> Option<&ScriptExecutionResult> { match self { Self::ScriptResult { result, .. } => Some(result), _ => None, diff --git a/fuel-tx/src/receipt/receipt_std.rs b/fuel-tx/src/receipt/receipt_std.rs index c2b99ced9b..43b3cf5d53 100644 --- a/fuel-tx/src/receipt/receipt_std.rs +++ b/fuel-tx/src/receipt/receipt_std.rs @@ -4,6 +4,7 @@ use fuel_asm::InstructionResult; use fuel_types::bytes::{self, SizedBytes, WORD_SIZE}; use fuel_types::Word; +use crate::receipt::script_result::ScriptExecutionResult; use std::io::{self, Write}; impl io::Read for Receipt { @@ -258,7 +259,7 @@ impl io::Write for Receipt { let id = id.into(); - *self = Self::panic(id, reason, pc, is); + *self = Self::panic(id, InstructionResult::from(reason), pc, is); } ReceiptRepr::Revert => { @@ -344,7 +345,7 @@ impl io::Write for Receipt { let (result, buf) = unsafe { bytes::restore_word_unchecked(buf) }; let (gas_used, _) = unsafe { bytes::restore_word_unchecked(buf) }; - let result = InstructionResult::from(result); + let result = ScriptExecutionResult::from(result); *self = Self::script_result(result, gas_used); } diff --git a/fuel-tx/src/receipt/script_result.rs b/fuel-tx/src/receipt/script_result.rs new file mode 100644 index 0000000000..e40f6ded7d --- /dev/null +++ b/fuel-tx/src/receipt/script_result.rs @@ -0,0 +1,36 @@ +use fuel_types::Word; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + feature = "serde-types-minimal", + derive(serde::Serialize, serde::Deserialize) +)] +pub enum ScriptExecutionResult { + Success, + Revert, + Panic, + // Generic failure case since any u64 is valid here + GenericFailure(u64), +} + +impl From for Word { + fn from(result: ScriptExecutionResult) -> Self { + match result { + ScriptExecutionResult::Success => 0x00, + ScriptExecutionResult::Revert => 0x01, + ScriptExecutionResult::Panic => 0x02, + ScriptExecutionResult::GenericFailure(value) => value, + } + } +} + +impl From for ScriptExecutionResult { + fn from(value: u64) -> Self { + match value { + 0x00 => Self::Success, + 0x01 => Self::Revert, + 0x02 => Self::Panic, + value => Self::GenericFailure(value), + } + } +} diff --git a/fuel-tx/tests/bytes.rs b/fuel-tx/tests/bytes.rs index 8a994fbe90..abeba30aa8 100644 --- a/fuel-tx/tests/bytes.rs +++ b/fuel-tx/tests/bytes.rs @@ -207,217 +207,286 @@ fn receipt() { rng.gen(), rng.gen(), ), - Receipt::script_result(InstructionResult::success(), rng.gen()), - Receipt::script_result( + Receipt::panic( + rng.gen(), + InstructionResult::success(), + rng.gen(), + rng.gen(), + ), + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::Revert, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::OutOfGas, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::TransactionValidity, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::MemoryOverflow, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ArithmeticOverflow, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ContractNotFound, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::MemoryOwnership, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::NotEnoughBalance, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ExpectedInternalContext, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::AssetIdNotFound, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::InputNotFound, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::OutputNotFound, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::WitnessNotFound, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::TransactionMaturity, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::InvalidMetadataIdentifier, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::MalformedCallStructure, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ReservedRegisterNotWritable, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ErrorFlag, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::InvalidImmediateValue, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ExpectedCoinInput, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::MaxMemoryAccess, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::MemoryWriteOverlap, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ContractNotInInputs, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::InternalBalanceOverflow, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ContractMaxSize, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ExpectedUnallocatedStack, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::MaxStaticContractsReached, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::TransferAmountCannotBeZero, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ExpectedOutputVariable, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), - Receipt::script_result( + Receipt::panic( + rng.gen(), InstructionResult::error( PanicReason::ExpectedParentInternalContext, Opcode::JI(rng.gen::() & 0xffffff).into(), ), rng.gen(), + rng.gen(), ), + Receipt::script_result(ScriptExecutionResult::Success, rng.gen()), + Receipt::script_result(ScriptExecutionResult::Panic, rng.gen()), + Receipt::script_result(ScriptExecutionResult::Revert, rng.gen()), + Receipt::script_result(ScriptExecutionResult::GenericFailure(rng.gen()), rng.gen()), ]); }