Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vm: account abstraction and new tx format #3220

Closed
6 tasks
dshulyak opened this issue May 22, 2022 · 0 comments
Closed
6 tasks

vm: account abstraction and new tx format #3220

dshulyak opened this issue May 22, 2022 · 0 comments
Assignees

Comments

@dshulyak
Copy link
Contributor

At genesis we will launch vm with 3 precompiled templates:

  • simple (single-sig) wallet
  • multisig wallet
  • vesting contract

Precompiles will be implemented as a simple golang modules, while trying to preserve boundaries discussed during design.

Templates

Templates are identified by an address, and will have their own address space.

For genesis we will define 3 constant addresses:

  • 0x01 - singlesig wallet
  • 0x02 - multisig wallet
  • 0x03 - vesting

TODO maybe start fron 0x00, any use case for empty address?

For spawned accounts we will store one of this addresses in the account table.

Template API

Load

Loads stored state or initializes state using arguments from a self spawn transaction.

Parse (ParsePayload)

decodes generic arguments from the concrete payload

  • method arguments
  • min/max layer
  • nonce counter/bitfield
  • max gas
  • gas price
  • max spend ?

some of the fields might not be specified by the transaction, by design it depends on the template. for example max gas is known in advance, since we are using fixed gas estimator. nonce for spawn transaction is 0.

result of the Parse returned to the mempool.

MaxSpend

inputs: selector, method arguments, state

TODO merge it with Parse for now

Verify

transaction validity

input: raw transaction and state

TODO this is really weird that we need to read transaction from the end when we parsed everything before the signature.

TODO can we unmarshal signature into concrete type?

Exec

Apply changes to the account state, by executing one the methods.

Accounts

every account with funds but without attached template is a stub account and needs to be spawned before it can be used.

In the database stub account will have null template field.

VM API

On gossip

Before accepting transaction into the local database it needs to pass validation.

Next sequence of template APIs is executed:

  1. Load (use conservative state)
    Probably will be implemented by conservative passing AccountState from conservative cache. Or maybe method will accept callback that will load state from conservative state.
  2. Parse
    Optionally after Parse tx can be validated by the conservative state, but with current API it is simpler after Verify.
  3. Verify
    After verify tx is saved to the pool, and conservative state may do other things.

If verify fails - transaction is discarded, and peer is blocked (tm).
Otherwise mempool may do anything with transaction.

On apply

  1. Load (non-conservative state)
  2. Parse
    Most of the transaction will be stored as a blob for sync efficiency, so we will Parse it again.
  3. No Verify
    No need to execute signature verification, but need to consume gas.

Verify has access only to immutable state so it is guaranteed to pass.
4. Exec

If tx fails before Exec - it is returned to mempool and may be either discarded or saved for later, this is irrelevant for vm.

If tx fails in Exec - transaction will be applied to the state as failed, account will pay for gas used in validation (Load/Parse/Verify).

Node API

execution result

each transaction that was applied to the state will have execution result. this API will significantly change after SVM introduction.

type ExecutionResult struct {
    Result   uint8 // FAILED or SUCCESS
    Reason   string // message of the failure
    GasSpent uint64 //
    // for spawn
    SpawnedAddress [20]byte 
}

TODO think more what is missing and might be helpful for debugging

api to read precompile state state

each precompile state has some fields that might be useful for smapp, such as:

type Wallet struct {
    Owner PublicKey
}
type MultiSigWallet struct {
    Owners OrderedSet[PublicKey]
    Required uint32
}

API will return byte buffer with whole state serialized using SCALE, in fact it will simply return what is stored in the latest account state.

Subtasks

  • core vm changes
  • simple wallet
  • multisig wallet
  • vesting wallet
  • execution results and API for them
  • API changes to read account state (including SCALE encoded state)
@dshulyak dshulyak self-assigned this May 22, 2022
bors bot pushed a commit that referenced this issue Jun 11, 2022
…signle key wallet) (#3229)

related #3220

- state

account extend with Template and State fields.
stub accounts will have both Template and State as nil. When account is spawned with template - Template will store the address of the template, and State will store mutable and immutable state encoded using scale.

- address

when account is spawned address is computed as `sha256(template_address, spawn_args)`. this must be taken into an account when configuring the coinbase for a node.

- validation and mempool

tx id is computed as a `sha256(raw_tx)`, note that raw_tx is a full body of the transaction including signature.
tx header can't be decoded without executing template code (specifically parse_payload and max_spend methods). 

in the upcoming pr - mempool will call into vm to initialize a validation flow (which includes parsing of the tx header). validation api is a 2 step process:
- parse. returns transaction header that can be validated against conservative state
- verify. executes templates verify method. it is assumed that this method costs much more than parse, so it makes sense to call it only if conservative validation succeeded.

- applying transaction

vm.Apply API method accepts layer id, transactions and rewards. Every transaction loads state, executes parse payload, initializes state and executed. Template/Handler API is specified in `genvm/core/types.go`.

Transaction can be skipped for 3 reasons:
- transaction is malformed (expectation is that such transactions should not be added to the block at all)
- account is not spawned (same as a nonce mismatch)
- nonce doesn't match the expected nonce of the account
- can't cover max gas with the account balance

If transaction is skipped it is returned back to the caller (presumably conservative state and the caller is free to do anything about it). Otherwise transaction is consumed and will pay fee to smeshers (in the followup pr for every consumed transaction we will store execution result). Logic for the fee distribution is not changed.
@dshulyak dshulyak changed the title vm: account abstraction and precompiles for genesis vm: account abstraction and new tx format Jun 22, 2022
@pigmej pigmej moved this to 🔖 Ready in Dev iterations Jun 22, 2022
@dshulyak dshulyak moved this from 🔖 Ready to ✅ Done in Dev iterations Jul 1, 2022
@dshulyak dshulyak closed this as completed Jul 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Status: Done
Development

No branches or pull requests

1 participant