spacemeshos / SMIPS

Spacemesh Improvement Proposals
https://spacemesh.io
Creative Commons Zero v1.0 Universal
7 stars 1 forks source link

Transaction Syntax (WIP) #76

Closed lrettig closed 1 year ago

lrettig commented 2 years ago

Overview

Like other blockchains and smart contract platforms, Spacemesh implements a deterministic state machine with transactions that advance state. System users generate, sign, and broadcast transactions, which have effects including deploying new smart contact templates, spawning new smart contracts from templates, and interacting with spawned smart contracts. These transactions are collected and held by miners in a mempool (a.k.a. txpool) and mined into blocks, which miners broadcast to the network for verification and inclusion into the canonical mesh.

Unlike previous smart contract platforms like Ethereum, Spacemesh implements only a single account type (see #49). All accounts may contain a coin balance and code, and may act as a principal account, i.e., as the source of gas and funds for a transaction.

This proposal introduces the final proposed Spacemesh transaction format.

Goals and motivation

High-level design

From the perspective of the node, Spacemesh transactions are mostly treated as opaque byte arrays which are interpreted at a higher level (inside the VM) (see #77). A transaction is contained in an envelope with a transaction type and an opaque transaction payload. The interpretation of the payload depends on the transaction type.

Prior art

Ethereum

Prior to this year's Berlin upgrade, Ethereum implemented a single, monolithic transaction format:

RLP([nonce, gasPrice, gasLimit, to, value, data, v, r, s])

Fields in this data structure could be overridden to specify different semantic transaction types: e.g., if the to field is empty, the transaction is interpreted as a contract deployment transaction, and the data field is interpreted to contain the contract code; after EIP-155: Simple replay attack protection, the signature v value could contain the chain ID.

EIP-2718: Typed Transaction Envelope, included in the Berlin upgrade, added a "transaction envelope" so that:

Transaction is either TransactionType || TransactionPayload or LegacyTransaction

For more information, see New Transaction Types on Ethereum.

Ethereum also intends to implement a form of account unification in EIP-2938: Account Abstraction. This involves introducing a new EIP-2718 transaction type whose payload should be interpreted as rlp([nonce, target, data]). Hence, handling of all transaction data fields except nonce and target are abstracted into the VM. Nonces are exposed to the VM and will become malleable by miners to support a multi-tenant use case.

Specification

A Spacemesh transaction is contained in an envelope as follows:

TransactionEnvelope := TransactionType || TransactionPayload

TransactionType is one byte.

TransactionPayload is an opaque byte array whose interpretation depends on the TransactionType.

Genesis type

Initially, Spacemesh will support only a single TransactionType: the "genesis" type (0x0). Transactions of any other type (and any data structures that contain them) should be considered invalid. The TransactionPayload of a genesis type transaction is passed directly into the VM, which handles all further verification and execution. The payload is opaque to the client (consensus, P2P layer) and can be read and written using one or more VM codecs via the VM connector API (see #80).

See #77 for more on higher-level interpretation and handling of transactions.

Signing

The Spacemesh node is never directly responsible for generating and signing a transaction. This is done by downstream clients. See #81 for more on this process.

Implementation plan

tbd

Questions

tbd

Dependencies and interactions

Stakeholders and reviewers

Testing and performance

tbd

tal-m commented 2 years ago

Some comments:

  1. The signed data can't include the signature itself. So you can't sign a hash of the envelope (or even the payload), as defined above.
  2. Given (1), the simplest version is to sign the entire envelope except for the signature(s). To make this simpler, the signature should be either at the beginning or the end. This allows the signature to be of a contiguous range of bytes in the transaction, and means we don't have to use the streaming hash API for signing in the simple case.
  3. I don't understand the compare method --- as far as I remember, contracts can't define arbitrary ordering of transactions, for good reasons. If we use the generalized nonce scheme I proposed, ordering must be according to the scheme (if not --- meaning we're using the TTL with subnonces scheme --- it must be consistent with that scheme).
  4. As I understand it, SVM doesn't do any unpacking. The unpacking (if necessary) happens inside the contract code. Thus, for example, verify can avoid almost all unpacking before checking the signature.
  5. The client API should be very clearly separated from the node API. Nodes only perform verification, so don't require any signing API. Also, a lot of the underlying structure is only an "artifact" of our specific smart-contract code. This structure has to be known to the client code, but not to the node (and might differ between contracts). For example:

    • Signature data is parsed inside verify (which, for example, might decode signatures from a field within tx calldata)
    • If we're using the generalized nonce scheme, the nonce field is only parsed inside the noncethreshold method of the contract.

    Of course, clients that create transactions need to know exactly how to construct them, so they need a much more detailed API. We have to provide one that is compatible with our specific genesis contracts, but, ideally, it would be "nice" enough that to be reused by most custom contracts in the future.

avive commented 2 years ago

i think that this smipp should also specify exactly how the unique tx id which is used in many places should be computed from the tx data. e.g the hash function used and the primage.

countvonzero commented 1 year ago

made obsolete by current implementation https://github.com/spacemeshos/go-spacemesh/issues/3220