Skip to main content

TransactionPayloadBuilder

Struct TransactionPayloadBuilder 

Source
pub struct TransactionPayloadBuilder { /* private fields */ }
Expand description

Builder for payload to be used with TxHandler (primarily for SimpleWallet).

The number of outputs that the payload declares is given to Self::new(). Method calls, added with Self::with_method_call(), write these outputs and refer to them by output index, and the builder computes the capacity of every declared output from the method calls that write it.

Methods in the payload are decoded and called with TransactionPayloadCaller, and can be described without calling them with TransactionPayloadDecoder.

Implementations§

Source§

impl TransactionPayloadBuilder

Source

pub fn new( max_size: u32, num_outputs: u8, ) -> Result<Self, TransactionPayloadBuilderError<'static>>

Create a new instance for a payload of up to max_size bytes that declares num_outputs outputs.

Memory for the whole payload is allocated here and never reallocated, a method call that doesn’t fit returns TransactionPayloadBuilderError::PayloadTooLarge. The payload is padded to a multiple of [Alignment::MAX], so max_size is rounded down to a multiple of it.

#[output] arguments and return values of method calls write the declared outputs, and slots and inputs of later method calls can refer to what was written last, by output index from 0 to num_outputs - 1, see MethodCallReferences. The header of the payload has room for the capacity of every declared output, which starts at 0, and every method call that writes an output raises its capacity to what the method needs, so capacities don’t have to be known upfront. The memory of every declared output is aligned for every output type. SimpleWalletBase::execute() only calls the methods of a payload whose declared outputs fit into OUTPUT_BUFFER_SIZE together, see TransactionPayloadDecoder.

The header is written right away, so a payload without method calls is the header.

Returns an error if num_outputs is larger than MAX_OUTPUTS or the header doesn’t fit into max_size.

Source

pub fn with_method_call<Args>( &mut self, contract: &Address, external_args: &Args, method_context: TransactionMethodContext, references: MethodCallReferences<'_>, ) -> Result<(), TransactionPayloadBuilderError<'static>>
where Args: ExternalArgs,

Add method call to the payload.

The wallet will call this method in addition order.

references refer to outputs that the payload declares (see Self::new()): the output index for each #[slot] and #[input] that gets the value that an earlier method call wrote last into that output instead of the value in external_args, and the output index that each #[output] and the return value write. See TransactionInput for more details. The capacity of every output that the method call writes is raised to the recommended capacity of the #[output] or the size of the return value if it is smaller.

Every output index must be below MAX_OUTPUTS (TransactionPayloadBuilderError::InvalidOutputIndex). The method call is also checked against the rules of the payload format about outputs, mostly with the code that decoders use, so that TransactionPayloadDecoder accepts the payload, and a broken rule is returned as TransactionPayloadBuilderError::PayloadRule with the error that the decoder returns for it, in the order in which the decoder checks the rules:

The other rules about outputs hold by construction: the return value is the last output, and every output gets a capacity that is enough for every method call that writes it.

Outputs are given to the method empty, with size 0, whatever an earlier method call wrote into them, so methods called from transactions must accept empty outputs, like MaybeData and VariableElements. A method with an #[output] of a [TrivialType] can’t be called directly from a transaction, since its value has to be initialized first, for example by a separate method. Initializing values is domain-specific, so the payload format doesn’t do it. Executors that check arguments against the method’s metadata reject such calls, while the native executor trusts transactions, so with it such a call violates the requirements of the called method.

The return value is given the size of its type, since executors write the whole value, so later method calls can refer to it as an input or a slot. The state returned by an #[init] method is the exception: executors store it as the state of the contract instead of writing it to the caller, so it is encoded as an #[output] that needs no capacity, like the state in the last #[output] of #[init] without a return value, and later method calls referring to it get it empty.

On error, the builder is left unchanged, so other method calls can still be added.

Source

pub unsafe fn with_method_call_untyped<'a>( &mut self, contract: &Address, external_args: NonNull<*const c_void>, method_metadata: &'a [u8], method_fingerprint: &MethodFingerprint, method_context: TransactionMethodContext, references: MethodCallReferences<'_>, ) -> Result<(), TransactionPayloadBuilderError<'a>>

Other than unsafe API, this method is identical to Self::with_method_call().

§Safety

external_args must correspond to method_metadata and method_fingerprint. Outputs are never read from external_args. The pointers of slots and inputs that refer to declared outputs in references are never dereferenced, so they may dangle, but they must not be null, since external arguments hold every pointer as NonNull.

Source

pub fn into_aligned_bytes( self, ) -> Result<OwnedAlignedBuffer, TransactionPayloadBuilderError<'static>>

Returns 16-byte aligned bytes, padded to a multiple of u128 size.

The contents is a header with the declared outputs, followed by a concatenated sequence of method calls with their arguments. All data structures are correctly aligned in the returned byte buffer with 0 used as padding when necessary. [OwnedAlignedBuffer::as_u128_slice()] returns the whole payload as u128s. Every payload starts with the header, also without declared outputs and method calls.

The capacity of every declared output is the largest that a method call writing it needs: the recommended capacity of an #[output], the size of a return value, or 0 for the state returned by an #[init] method.

Returns TransactionPayloadBuilderError::UnusedOutput with the first declared output that no method call writes, since its memory would never be used, which most likely means that a method call refers to the wrong output index. TransactionPayloadDecoder and TransactionPayloadCaller accept such a payload.

The header:

  • Number of declared outputs: u8
  • For each declared output:
    • Its capacity as little-endian u32

Each method is serialized in the following way:

Trait Implementations§

Source§

impl Clone for TransactionPayloadBuilder

Source§

fn clone(&self) -> TransactionPayloadBuilder

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TransactionPayloadBuilder

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.