Stateful Smart Accounts


#1

While we’re in process of final testing and preparations for the first mainnet release for smart accounts, let’s discuss further developments and how if can fit current waves model.

As per now, waves smart accounts are stateless predicates: they consume data from blockchain and either allow or deny outgoing transactions from an account. While powerful enough for basic needs like atomic swaps and multisigs, a general custom application(decentralized or not) needs to have state. Waves does allow accounts to have state via data transactions, and those data fields can be read from smart account, but up until this point, smart accounts can’t write any state.

Currently, smart account has 1 function that returns boolean. Let’s generalize this a little:

  1. Let’s allow an account to have multiple named functions.
  2. Let’s make this functions return special constructs which represent inner transactions, that will be issued upon function invocation
  3. Add a new type of transaction : ContractInvocationTransaction(accountAddress, functionName, functionArgs…)

So, contract code could look like:

contract {
def init() : List[Transaction] = {
  List(DataTransaction("x", 0))
}

def add(x: int) : List[Transaction] = {
  let oldValue =  readInteger("x")
  let newValue = state + x
  List(DataTransaction("x", newValue))
}

def dec() : List[Tranaction] = {
  let oldValue =  readInteger("x")
  if (oldValue == 0) 
    throw("can't make x < 0")
  else 
     List(DataTransaction("x", oldValue - 1))
}

It this small example, we wrote a DApp that can modify contract state and rely on it in further calls(dec())

But why limit to DataTransactions? Let’s allow contract issue TransferTransaction as well:

contract {
...

def withdrawAlice(amount: Int) : List[Transaction] = {
  let aliceTotal=  readInteger("alice")
  if (aliceTotal >= amount)   
     List(
         DataTransaction("alice", aliceTotal - amount), 
         TransferTransaction(..., amount, ...))
  else throw("alice is eligible for less than $aliceTotal only")
 }

def ....
def ....
}

Upon calling the contact, only ContractInvocationTransaction will be put to blockchain. The inner Datas,Transafers and what not will be generated in-place implicitly, hence won’t consume any space in blockchain. The emitted transactions will be processed as usual ones, but atomically: if Transfer from the example is not allowed because contract has less than required, data change won’t happen either.

With this, we’ll onboard things like

  • dapp state
  • atomic transaction containers
  • payable methods

While preserving the following

  • no gas, predictable cost
  • no major changes to compiler and executor engine
  • functional approach within RIDE

What do you think?


#2

Thank you Ilya I appreciate your efforts on this. Looking forward to outcome.


#3

Hi Ilya,

that reads very promising indeed. Actually, according to the latest paper of the ERGO guys, having the possibility to trigger a new transaction from a Smart Contract would make that whole construct Turing complete, i guess that also holds for your suggestion.

Anyway, what i don’t see so far is how current use cases would work. So far, easy spoken, if a transaction should be executed, the node checks if there is a corresponding Smart Contract is in place and evaluates this SC. If it evaluates successfully, the tx is executed, if not, not. If there is no corresponding SC, the node checks if the signature is valid.

This is a very easy and straightforward contract. Would something like this also be possible in your new approach? Will there be something like a “default” method that will be executed for a simple tx?

Cheers
Marc


#4

Hi Marc,

Great observation regarding turing completeness, should hold!

Regarding the default function: For smart accounts, the default function is not going anywhere, for smart contracts it’s yet to be designed. Maybe it’ll be a new type of account, but I’d prefer not to.

Cheers! :wink:


#5

It would be better if SetScript will stay a Smart Account as of now.

But ContractInvocationTransaction could execute any Data with ByteArray as Script.


#6

Update tomorrow, stay tuned :slight_smile: