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
impl TransactionPayloadBuilder
Sourcepub fn new(
max_size: u32,
num_outputs: u8,
) -> Result<Self, TransactionPayloadBuilderError<'static>>
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.
Sourcepub fn with_method_call<Args>(
&mut self,
contract: &Address,
external_args: &Args,
method_context: TransactionMethodContext,
references: MethodCallReferences<'_>,
) -> Result<(), TransactionPayloadBuilderError<'static>>where
Args: ExternalArgs,
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:
- a slot or an input only refers to a declared output that an earlier method call wrote
(
TransactionPayloadDecoderError::OutputIndexNotFound) and that this method call doesn’t write (TransactionPayloadDecoderError::OutputReferencedBySameMethod) - a slot only refers to a return value with the size of an address
(
TransactionPayloadDecoderError::InvalidSlotOutputIndexSize); an#[output]used as a slot gets its size when its method is called, soTransactionPayloadCallerchecks it - the method call only writes declared outputs
(
TransactionPayloadDecoderError::OutputIndexNotFound), each at most once (TransactionPayloadDecoderError::OutputUsedTwice)
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.
Sourcepub 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>>
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.
Sourcepub fn into_aligned_bytes(
self,
) -> Result<OwnedAlignedBuffer, TransactionPayloadBuilderError<'static>>
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
- Its capacity as little-endian
Each method is serialized in the following way:
- Contract to call: [
Address] - Fingerprint of the method to call: [
MethodFingerprint] - Method context:
TransactionMethodContext - Number of
#[slot]arguments:u8 - For each
#[slot]argument:TransactionSlotasu8
- Number of
#[input]arguments:u8 - For each
#[input]argument:TransactionInputasu8
- Number of
#[output]arguments, including the return value:u8 - For each
#[output]argument, followed by the return value if there is one:TransactionOutputasu8
- For each
TransactionSlot, whose type isTransactionSlotType::Address:- [
Address]
- [
- For each
TransactionInput, whose type isTransactionInputType::Value:- Input size as little-endian
u32followed by the input itself
- Input size as little-endian
- If the last
TransactionOutputis a return value:- Its size as little-endian
u32
- Its size as little-endian
Trait Implementations§
Source§impl Clone for TransactionPayloadBuilder
impl Clone for TransactionPayloadBuilder
Source§fn clone(&self) -> TransactionPayloadBuilder
fn clone(&self) -> TransactionPayloadBuilder
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for TransactionPayloadBuilder
impl RefUnwindSafe for TransactionPayloadBuilder
impl Send for TransactionPayloadBuilder
impl Sync for TransactionPayloadBuilder
impl Unpin for TransactionPayloadBuilder
impl UnsafeUnpin for TransactionPayloadBuilder
impl UnwindSafe for TransactionPayloadBuilder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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