Flatten the types directory

We recently created a `types` subdirectory under `script` to keep all
the `Script` and `ScriptBuf` impls together. Turns out this additional
level of subdirectory is a bit annoying and we can achieve the same
grouping by just using `script/mod.rs`.

Move code from `types/mod.rs` to `script/mod.rs`, move the two
submodules up a level, remove the `types` directory.
This commit is contained in:
Tobin C. Harding 2023-02-14 06:45:37 +11:00
parent f71da4e91a
commit 272cdbcf7c
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
4 changed files with 517 additions and 530 deletions

View File

@ -48,20 +48,35 @@
//! At the time of writing there's only one operation using the cache - `push_verify`, so the cache
//! is minimal but we may extend it in the future if needed.
use alloc::rc::Rc;
use alloc::sync::Arc;
use core::cmp::Ordering;
use core::borrow::{Borrow, BorrowMut};
use core::fmt;
use core::ops::{Deref, DerefMut};
#[cfg(feature = "serde")]
use serde;
use crate::blockdata::opcodes::{self, all::*};
use crate::OutPoint;
use crate::consensus::{encode, Decodable, Encodable};
use crate::hash_types::{ScriptHash, WScriptHash};
use crate::hashes::hex;
use crate::{io, OutPoint};
use crate::prelude::*;
mod borrowed;
mod builder;
mod instruction;
mod types;
mod owned;
#[cfg(test)]
mod tests;
pub use self::borrowed::*;
pub use self::builder::*;
pub use self::instruction::*;
pub use self::types::*;
pub use self::owned::*;
/// Encodes an integer in script(minimal CScriptNum) format.
///
@ -213,6 +228,505 @@ fn opcode_to_verify(opcode: Option<opcodes::All>) -> Option<opcodes::All> {
})
}
// We keep all the `Script` and `ScriptBuf` impls together since its easier to see side-by-side.
impl From<ScriptBuf> for Box<Script> {
fn from(v: ScriptBuf) -> Self {
v.into_boxed_script()
}
}
impl From<ScriptBuf> for Cow<'_, Script> {
fn from(value: ScriptBuf) -> Self {
Cow::Owned(value)
}
}
impl<'a> From<Cow<'a, Script>> for ScriptBuf {
fn from(value: Cow<'a, Script>) -> Self {
match value {
Cow::Owned(owned) => owned,
Cow::Borrowed(borrwed) => borrwed.into(),
}
}
}
impl<'a> From<Cow<'a, Script>> for Box<Script> {
fn from(value: Cow<'a, Script>) -> Self {
match value {
Cow::Owned(owned) => owned.into(),
Cow::Borrowed(borrwed) => borrwed.into(),
}
}
}
impl<'a> From<&'a Script> for Box<Script> {
fn from(value: &'a Script) -> Self {
value.to_owned().into()
}
}
impl<'a> From<&'a Script> for ScriptBuf {
fn from(value: &'a Script) -> Self {
value.to_owned()
}
}
impl<'a> From<&'a Script> for Cow<'a, Script> {
fn from(value: &'a Script) -> Self {
Cow::Borrowed(value)
}
}
impl<'a> From<&'a Script> for Arc<Script> {
fn from(value: &'a Script) -> Self {
let rw: *const [u8] = Arc::into_raw(Arc::from(&value.0));
// SAFETY: copied from `std`
// The pointer was just created from an Arc without deallocating
// Casting a slice to a transparent struct wrapping that slice is sound (same
// layout).
unsafe { Arc::from_raw(rw as *const Script) }
}
}
impl<'a> From<&'a Script> for Rc<Script> {
fn from(value: &'a Script) -> Self {
let rw: *const [u8] = Rc::into_raw(Rc::from(&value.0));
// SAFETY: copied from `std`
// The pointer was just created from an Rc without deallocating
// Casting a slice to a transparent struct wrapping that slice is sound (same
// layout).
unsafe { Rc::from_raw(rw as *const Script) }
}
}
impl From<Vec<u8>> for ScriptBuf {
fn from(v: Vec<u8>) -> Self { ScriptBuf(v) }
}
impl From<ScriptBuf> for Vec<u8> {
fn from(v: ScriptBuf) -> Self { v.0 }
}
impl From<ScriptBuf> for ScriptHash {
fn from(script: ScriptBuf) -> ScriptHash {
script.script_hash()
}
}
impl From<&ScriptBuf> for ScriptHash {
fn from(script: &ScriptBuf) -> ScriptHash {
script.script_hash()
}
}
impl From<&Script> for ScriptHash {
fn from(script: &Script) -> ScriptHash {
script.script_hash()
}
}
impl From<ScriptBuf> for WScriptHash {
fn from(script: ScriptBuf) -> WScriptHash {
script.wscript_hash()
}
}
impl From<&ScriptBuf> for WScriptHash {
fn from(script: &ScriptBuf) -> WScriptHash {
script.wscript_hash()
}
}
impl From<&Script> for WScriptHash {
fn from(script: &Script) -> WScriptHash {
script.wscript_hash()
}
}
impl core::str::FromStr for ScriptBuf {
type Err = hex::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, hex::Error> {
ScriptBuf::from_hex(s)
}
}
impl AsRef<Script> for Script {
#[inline]
fn as_ref(&self) -> &Script {
self
}
}
impl AsRef<Script> for ScriptBuf {
fn as_ref(&self) -> &Script {
self
}
}
impl AsRef<[u8]> for Script {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<[u8]> for ScriptBuf {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsMut<Script> for Script {
fn as_mut(&mut self) -> &mut Script {
self
}
}
impl AsMut<Script> for ScriptBuf {
fn as_mut(&mut self) -> &mut Script {
self
}
}
impl AsMut<[u8]> for Script {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
self.as_mut_bytes()
}
}
impl AsMut<[u8]> for ScriptBuf {
fn as_mut(&mut self) -> &mut [u8] {
self.as_mut_bytes()
}
}
impl fmt::Debug for Script {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("Script(")?;
self.fmt_asm(f)?;
f.write_str(")")
}
}
impl fmt::Debug for ScriptBuf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.as_script(), f)
}
}
impl fmt::Display for Script {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.fmt_asm(f)
}
}
impl fmt::Display for ScriptBuf {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.as_script(), f)
}
}
impl fmt::LowerHex for Script {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
}
}
impl fmt::LowerHex for ScriptBuf {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(self.as_script(), f)
}
}
impl fmt::UpperHex for Script {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
}
}
impl fmt::UpperHex for ScriptBuf {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::UpperHex::fmt(self.as_script(), f)
}
}
impl Deref for ScriptBuf {
type Target = Script;
fn deref(&self) -> &Self::Target {
Script::from_bytes(&self.0)
}
}
impl DerefMut for ScriptBuf {
fn deref_mut(&mut self) -> &mut Self::Target {
Script::from_bytes_mut(&mut self.0)
}
}
impl Borrow<Script> for ScriptBuf {
fn borrow(&self) -> &Script {
self
}
}
impl BorrowMut<Script> for ScriptBuf {
fn borrow_mut(&mut self) -> &mut Script {
self
}
}
impl PartialEq<ScriptBuf> for Script {
fn eq(&self, other: &ScriptBuf) -> bool {
self.eq(other.as_script())
}
}
impl PartialEq<Script> for ScriptBuf {
fn eq(&self, other: &Script) -> bool {
self.as_script().eq(other)
}
}
impl PartialOrd<Script> for ScriptBuf {
fn partial_cmp(&self, other: &Script) -> Option<Ordering> {
self.as_script().partial_cmp(other)
}
}
impl PartialOrd<ScriptBuf> for Script {
fn partial_cmp(&self, other: &ScriptBuf) -> Option<Ordering> {
self.partial_cmp(other.as_script())
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl serde::Serialize for Script {
/// User-facing serialization for `Script`.
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
serializer.collect_str(&format_args!("{:x}", self))
} else {
serializer.serialize_bytes(self.as_bytes())
}
}
}
/// Can only deserialize borrowed bytes.
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de> serde::Deserialize<'de> for &'de Script {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
use crate::serde::de::Error;
return Err(D::Error::custom("deserialization of `&Script` from human-readable formats is not possible"));
}
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = &'de Script;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("borrowed bytes")
}
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Script::from_bytes(v))
}
}
deserializer.deserialize_bytes(Visitor)
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl serde::Serialize for ScriptBuf {
/// User-facing serialization for `Script`.
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(**self).serialize(serializer)
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de> serde::Deserialize<'de> for ScriptBuf {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use core::fmt::Formatter;
use crate::hashes::hex::FromHex;
if deserializer.is_human_readable() {
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = ScriptBuf;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a script hex")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let v = Vec::from_hex(v).map_err(E::custom)?;
Ok(ScriptBuf::from(v))
}
}
deserializer.deserialize_str(Visitor)
} else {
struct BytesVisitor;
impl<'de> serde::de::Visitor<'de> for BytesVisitor {
type Value = ScriptBuf;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a script Vec<u8>")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(ScriptBuf::from(v.to_vec()))
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(ScriptBuf::from(v))
}
}
deserializer.deserialize_byte_buf(BytesVisitor)
}
}
}
impl Encodable for Script {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
crate::consensus::encode::consensus_encode_with_size(&self.0, w)
}
}
impl Encodable for ScriptBuf {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
self.0.consensus_encode(w)
}
}
impl Decodable for ScriptBuf {
#[inline]
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?))
}
}
/// Writes the assembly decoding of the script bytes to the formatter.
pub(super) fn bytes_to_asm_fmt(script: &[u8], f: &mut dyn fmt::Write) -> fmt::Result {
// This has to be a macro because it needs to break the loop
macro_rules! read_push_data_len {
($iter:expr, $len:literal, $formatter:expr) => {
match read_uint_iter($iter, $len) {
Ok(n) => {
n
},
Err(UintError::EarlyEndOfScript) => {
$formatter.write_str("<unexpected end>")?;
break;
}
// We got the data in a slice which implies it being shorter than `usize::max_value()`
// So if we got overflow, we can confidently say the number is higher than length of
// the slice even though we don't know the exact number. This implies attempt to push
// past end.
Err(UintError::NumericOverflow) => {
$formatter.write_str("<push past end>")?;
break;
}
}
}
}
let mut iter = script.iter();
// Was at least one opcode emitted?
let mut at_least_one = false;
// `iter` needs to be borrowed in `read_push_data_len`, so we have to use `while let` instead
// of `for`.
while let Some(byte) = iter.next() {
let opcode = opcodes::All::from(*byte);
let data_len = if let opcodes::Class::PushBytes(n) = opcode.classify(opcodes::ClassifyContext::Legacy) {
n as usize
} else {
match opcode {
OP_PUSHDATA1 => {
// side effects: may write and break from the loop
read_push_data_len!(&mut iter, 1, f)
}
OP_PUSHDATA2 => {
// side effects: may write and break from the loop
read_push_data_len!(&mut iter, 2, f)
}
OP_PUSHDATA4 => {
// side effects: may write and break from the loop
read_push_data_len!(&mut iter, 4, f)
}
_ => 0
}
};
if at_least_one {
f.write_str(" ")?;
} else {
at_least_one = true;
}
// Write the opcode
if opcode == OP_PUSHBYTES_0 {
f.write_str("OP_0")?;
} else {
write!(f, "{:?}", opcode)?;
}
// Write any pushdata
if data_len > 0 {
f.write_str(" ")?;
if data_len <= iter.len() {
for ch in iter.by_ref().take(data_len) {
write!(f, "{:02x}", ch)?;
}
} else {
f.write_str("<push past end>")?;
break;
}
}
}
Ok(())
}
/// Ways that a script might fail. Not everything is split up as
/// much as it could be; patches welcome if more detailed errors
/// would help you.

View File

@ -1,527 +0,0 @@
// Written in 2014 by Andrew Poelstra <apoelstra@wpsoftware.net>
// SPDX-License-Identifier: CC0-1.0
//! Provides the two script types, one with owned inner data [`ScriptBuf`] and
//! one with borrowed inner data [`Script`].
use alloc::rc::Rc;
use alloc::sync::Arc;
use core::cmp::Ordering;
use core::borrow::{Borrow, BorrowMut};
use core::fmt;
use core::ops::{Deref, DerefMut};
#[cfg(feature = "serde")]
use serde;
use crate::blockdata::opcodes::{self, all::*};
use crate::blockdata::script::{read_uint_iter, UintError};
use crate::consensus::{encode, Decodable, Encodable};
use crate::hash_types::{ScriptHash, WScriptHash};
use crate::hashes::{hex};
use crate::io;
use crate::prelude::*;
mod borrowed;
mod owned;
pub use borrowed::*;
pub use owned::*;
impl From<ScriptBuf> for Box<Script> {
fn from(v: ScriptBuf) -> Self {
v.into_boxed_script()
}
}
impl From<ScriptBuf> for Cow<'_, Script> {
fn from(value: ScriptBuf) -> Self {
Cow::Owned(value)
}
}
impl<'a> From<Cow<'a, Script>> for ScriptBuf {
fn from(value: Cow<'a, Script>) -> Self {
match value {
Cow::Owned(owned) => owned,
Cow::Borrowed(borrwed) => borrwed.into(),
}
}
}
impl<'a> From<Cow<'a, Script>> for Box<Script> {
fn from(value: Cow<'a, Script>) -> Self {
match value {
Cow::Owned(owned) => owned.into(),
Cow::Borrowed(borrwed) => borrwed.into(),
}
}
}
impl<'a> From<&'a Script> for Box<Script> {
fn from(value: &'a Script) -> Self {
value.to_owned().into()
}
}
impl<'a> From<&'a Script> for ScriptBuf {
fn from(value: &'a Script) -> Self {
value.to_owned()
}
}
impl<'a> From<&'a Script> for Cow<'a, Script> {
fn from(value: &'a Script) -> Self {
Cow::Borrowed(value)
}
}
impl<'a> From<&'a Script> for Arc<Script> {
fn from(value: &'a Script) -> Self {
let rw: *const [u8] = Arc::into_raw(Arc::from(&value.0));
// SAFETY: copied from `std`
// The pointer was just created from an Arc without deallocating
// Casting a slice to a transparent struct wrapping that slice is sound (same
// layout).
unsafe { Arc::from_raw(rw as *const Script) }
}
}
impl<'a> From<&'a Script> for Rc<Script> {
fn from(value: &'a Script) -> Self {
let rw: *const [u8] = Rc::into_raw(Rc::from(&value.0));
// SAFETY: copied from `std`
// The pointer was just created from an Rc without deallocating
// Casting a slice to a transparent struct wrapping that slice is sound (same
// layout).
unsafe { Rc::from_raw(rw as *const Script) }
}
}
impl From<Vec<u8>> for ScriptBuf {
fn from(v: Vec<u8>) -> Self { ScriptBuf(v) }
}
impl From<ScriptBuf> for Vec<u8> {
fn from(v: ScriptBuf) -> Self { v.0 }
}
impl From<ScriptBuf> for ScriptHash {
fn from(script: ScriptBuf) -> ScriptHash {
script.script_hash()
}
}
impl From<&ScriptBuf> for ScriptHash {
fn from(script: &ScriptBuf) -> ScriptHash {
script.script_hash()
}
}
impl From<&Script> for ScriptHash {
fn from(script: &Script) -> ScriptHash {
script.script_hash()
}
}
impl From<ScriptBuf> for WScriptHash {
fn from(script: ScriptBuf) -> WScriptHash {
script.wscript_hash()
}
}
impl From<&ScriptBuf> for WScriptHash {
fn from(script: &ScriptBuf) -> WScriptHash {
script.wscript_hash()
}
}
impl From<&Script> for WScriptHash {
fn from(script: &Script) -> WScriptHash {
script.wscript_hash()
}
}
impl core::str::FromStr for ScriptBuf {
type Err = hex::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, hex::Error> {
ScriptBuf::from_hex(s)
}
}
impl AsRef<Script> for Script {
#[inline]
fn as_ref(&self) -> &Script {
self
}
}
impl AsRef<Script> for ScriptBuf {
fn as_ref(&self) -> &Script {
self
}
}
impl AsRef<[u8]> for Script {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<[u8]> for ScriptBuf {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsMut<Script> for Script {
fn as_mut(&mut self) -> &mut Script {
self
}
}
impl AsMut<Script> for ScriptBuf {
fn as_mut(&mut self) -> &mut Script {
self
}
}
impl AsMut<[u8]> for Script {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
self.as_mut_bytes()
}
}
impl AsMut<[u8]> for ScriptBuf {
fn as_mut(&mut self) -> &mut [u8] {
self.as_mut_bytes()
}
}
impl fmt::Debug for Script {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("Script(")?;
self.fmt_asm(f)?;
f.write_str(")")
}
}
impl fmt::Debug for ScriptBuf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.as_script(), f)
}
}
impl fmt::Display for Script {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.fmt_asm(f)
}
}
impl fmt::Display for ScriptBuf {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self.as_script(), f)
}
}
impl fmt::LowerHex for Script {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
}
}
impl fmt::LowerHex for ScriptBuf {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::LowerHex::fmt(self.as_script(), f)
}
}
impl fmt::UpperHex for Script {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
}
}
impl fmt::UpperHex for ScriptBuf {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::UpperHex::fmt(self.as_script(), f)
}
}
impl Deref for ScriptBuf {
type Target = Script;
fn deref(&self) -> &Self::Target {
Script::from_bytes(&self.0)
}
}
impl DerefMut for ScriptBuf {
fn deref_mut(&mut self) -> &mut Self::Target {
Script::from_bytes_mut(&mut self.0)
}
}
impl Borrow<Script> for ScriptBuf {
fn borrow(&self) -> &Script {
self
}
}
impl BorrowMut<Script> for ScriptBuf {
fn borrow_mut(&mut self) -> &mut Script {
self
}
}
impl PartialEq<ScriptBuf> for Script {
fn eq(&self, other: &ScriptBuf) -> bool {
self.eq(other.as_script())
}
}
impl PartialEq<Script> for ScriptBuf {
fn eq(&self, other: &Script) -> bool {
self.as_script().eq(other)
}
}
impl PartialOrd<Script> for ScriptBuf {
fn partial_cmp(&self, other: &Script) -> Option<Ordering> {
self.as_script().partial_cmp(other)
}
}
impl PartialOrd<ScriptBuf> for Script {
fn partial_cmp(&self, other: &ScriptBuf) -> Option<Ordering> {
self.partial_cmp(other.as_script())
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl serde::Serialize for Script {
/// User-facing serialization for `Script`.
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
serializer.collect_str(&format_args!("{:x}", self))
} else {
serializer.serialize_bytes(self.as_bytes())
}
}
}
/// Can only deserialize borrowed bytes.
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de> serde::Deserialize<'de> for &'de Script {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
use crate::serde::de::Error;
return Err(D::Error::custom("deserialization of `&Script` from human-readable formats is not possible"));
}
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = &'de Script;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("borrowed bytes")
}
fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Script::from_bytes(v))
}
}
deserializer.deserialize_bytes(Visitor)
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl serde::Serialize for ScriptBuf {
/// User-facing serialization for `Script`.
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(**self).serialize(serializer)
}
}
#[cfg(feature = "serde")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de> serde::Deserialize<'de> for ScriptBuf {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use core::fmt::Formatter;
use crate::hashes::hex::FromHex;
if deserializer.is_human_readable() {
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = ScriptBuf;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a script hex")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let v = Vec::from_hex(v).map_err(E::custom)?;
Ok(ScriptBuf::from(v))
}
}
deserializer.deserialize_str(Visitor)
} else {
struct BytesVisitor;
impl<'de> serde::de::Visitor<'de> for BytesVisitor {
type Value = ScriptBuf;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a script Vec<u8>")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(ScriptBuf::from(v.to_vec()))
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(ScriptBuf::from(v))
}
}
deserializer.deserialize_byte_buf(BytesVisitor)
}
}
}
impl Encodable for Script {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
crate::consensus::encode::consensus_encode_with_size(&self.0, w)
}
}
impl Encodable for ScriptBuf {
#[inline]
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
self.0.consensus_encode(w)
}
}
impl Decodable for ScriptBuf {
#[inline]
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?))
}
}
/// Writes the assembly decoding of the script bytes to the formatter.
pub(super) fn bytes_to_asm_fmt(script: &[u8], f: &mut dyn fmt::Write) -> fmt::Result {
// This has to be a macro because it needs to break the loop
macro_rules! read_push_data_len {
($iter:expr, $len:literal, $formatter:expr) => {
match read_uint_iter($iter, $len) {
Ok(n) => {
n
},
Err(UintError::EarlyEndOfScript) => {
$formatter.write_str("<unexpected end>")?;
break;
}
// We got the data in a slice which implies it being shorter than `usize::max_value()`
// So if we got overflow, we can confidently say the number is higher than length of
// the slice even though we don't know the exact number. This implies attempt to push
// past end.
Err(UintError::NumericOverflow) => {
$formatter.write_str("<push past end>")?;
break;
}
}
}
}
let mut iter = script.iter();
// Was at least one opcode emitted?
let mut at_least_one = false;
// `iter` needs to be borrowed in `read_push_data_len`, so we have to use `while let` instead
// of `for`.
while let Some(byte) = iter.next() {
let opcode = opcodes::All::from(*byte);
let data_len = if let opcodes::Class::PushBytes(n) = opcode.classify(opcodes::ClassifyContext::Legacy) {
n as usize
} else {
match opcode {
OP_PUSHDATA1 => {
// side effects: may write and break from the loop
read_push_data_len!(&mut iter, 1, f)
}
OP_PUSHDATA2 => {
// side effects: may write and break from the loop
read_push_data_len!(&mut iter, 2, f)
}
OP_PUSHDATA4 => {
// side effects: may write and break from the loop
read_push_data_len!(&mut iter, 4, f)
}
_ => 0
}
};
if at_least_one {
f.write_str(" ")?;
} else {
at_least_one = true;
}
// Write the opcode
if opcode == OP_PUSHBYTES_0 {
f.write_str("OP_0")?;
} else {
write!(f, "{:?}", opcode)?;
}
// Write any pushdata
if data_len > 0 {
f.write_str(" ")?;
if data_len <= iter.len() {
for ch in iter.by_ref().take(data_len) {
write!(f, "{:02x}", ch)?;
}
} else {
f.write_str("<push past end>")?;
break;
}
}
}
Ok(())
}