New alternate contract language

Do you mean simulating a blockchain environment of having a more general purpose language which could be used for “other” things as well?

No, I thought about a language that you can use as a general purpose language if you will not use blockchain-specific features. So just imagine a simple math library or whatever library that will not touch blockchain specific things. You don’t even need to simulate a blockchain environment for it to work. It would be nice if you can write such libraries, test them and even import them to, compile and run as a command-line program. Currently Sophia code is compiled to the æternity VM bytecode and I am not sure if it will be possible to further run it as a linux executable for example. Probably it would be easier to do that if AE VM were designed for that from the beginning. I am not sure if it is worth to thing about that, just giving an idea.

The other thing, I am very curious what syntax do you want to use. More like ruby, elixir or scala? Do you have any draft?

I am not a developer, but what I continually hear from the community is that we should try making it easier for smart contract (SC) devs from other blockchains to start building on aeternity. I am not sure exactly how this feedback could be useful, but it is something to keep in mind. The most popular SC language out there is Solidity.

2 Likes

Regarding ease: it’s not clear to me, if Solidity made Smart Contract programming look too easy but it certainly set the standard = it’s what people expect and what they measure new things against. Not too many people have a lot of experience with functional programming.

I love Sophia and its true advantages regarding safety, and enforcing robust apps, but also speed might not be immediately apparent. It can be quite difficult to get the more demanding stuff out without losing the advantages but Elixir kind-of showed the way.

I think for inspiration it should make sense to look at the language that Vitalik Buterin favors, Viper GitHub - vyperlang/vyper: Pythonic Smart Contract Language for the EVM . He wrote this after Solidity was already a success, continuing his Python-leaning bent from the first language he made for Ethereum, Serpent.

Solidity had actually been started to make it easier to have formal verification right in the language but it never really arrived where it was supposed to go, or at least very much too late.

For convenience, this is how Viper looks
https://github.com/ethereum/vyper/blob/master/examples/voting/ballot.vy:

# Voting with delegation.

# Information about voters
struct Voter:
    # weight is accumulated by delegation
    weight: int128
    # if true, that person already voted (which includes voting by delegating)
    voted: bool
    # person delegated to
    delegate: address
    # index of the voted proposal, which is not meaningful unless `voted` is True.
    vote: int128

# Users can create proposals
struct Proposal:
    # short name (up to 32 bytes)
    name: bytes32
    # number of accumulated votes
    voteCount: int128

voters: public(map(address, Voter))
proposals: public(map(int128, Proposal))
voterCount: public(int128)
chairperson: public(address)
int128Proposals: public(int128)


@private
@constant
def _delegated(addr: address) -> bool:
    return self.voters[addr].delegate != ZERO_ADDRESS


@public
@constant
def delegated(addr: address) -> bool:
    return self._delegated(addr)


@private
@constant
def _directlyVoted(addr: address) -> bool:
    return self.voters[addr].voted and (self.voters[addr].delegate == ZERO_ADDRESS)


@public
@constant
def directlyVoted(addr: address) -> bool:
    return self._directlyVoted(addr)


# Setup global variables
@public
def __init__(_proposalNames: bytes32[2]):
    self.chairperson = msg.sender
    self.voterCount = 0
    for i in range(2):
        self.proposals[i] = Proposal({
            name: _proposalNames[i],
            voteCount: 0
        })
        self.int128Proposals += 1

# Give a `voter` the right to vote on this ballot.
# This may only be called by the `chairperson`.
@public
def giveRightToVote(voter: address):
    # Throws if the sender is not the chairperson.
    assert msg.sender == self.chairperson
    # Throws if the voter has already voted.
    assert not self.voters[voter].voted
    # Throws if the voter's voting weight isn't 0.
    assert self.voters[voter].weight == 0
    self.voters[voter].weight = 1
    self.voterCount += 1

# Used by `delegate` below, callable externally via `forwardWeight`
@private
def _forwardWeight(delegate_with_weight_to_forward: address):
    assert self._delegated(delegate_with_weight_to_forward)
    # Throw if there is nothing to do:
    assert self.voters[delegate_with_weight_to_forward].weight > 0

    target: address = self.voters[delegate_with_weight_to_forward].delegate
    for i in range(4):
        if self._delegated(target):
            target = self.voters[target].delegate
            # The following effectively detects cycles of length <= 5,
            # in which the delegation is given back to the delegator.
            # This could be done for any int128ber of loops,
            # or even infinitely with a while loop.
            # However, cycles aren't actually problematic for correctness;
            # they just result in spoiled votes.
            # So, in the production version, this should instead be
            # the responsibility of the contract's client, and this
            # check should be removed.
            assert target != delegate_with_weight_to_forward
        else:
            # Weight will be moved to someone who directly voted or
            # hasn't voted.
            break

    weight_to_forward: int128 = self.voters[delegate_with_weight_to_forward].weight
    self.voters[delegate_with_weight_to_forward].weight = 0
    self.voters[target].weight += weight_to_forward

    if self._directlyVoted(target):
        self.proposals[self.voters[target].vote].voteCount += weight_to_forward
        self.voters[target].weight = 0

    # To reiterate: if target is also a delegate, this function will need
    # to be called again, similarly to as above.

# Public function to call _forwardWeight
@public
def forwardWeight(delegate_with_weight_to_forward: address):
    self._forwardWeight(delegate_with_weight_to_forward)

# Delegate your vote to the voter `to`.
@public
def delegate(to: address):
    # Throws if the sender has already voted
    assert not self.voters[msg.sender].voted
    # Throws if the sender tries to delegate their vote to themselves or to
    # the default address value of 0x0000000000000000000000000000000000000000
    # (the latter might not be problematic, but I don't want to think about it).
    assert to != msg.sender
    assert to != ZERO_ADDRESS

    self.voters[msg.sender].voted = True
    self.voters[msg.sender].delegate = to

    # This call will throw if and only if this delegation would cause a loop
        # of length <= 5 that ends up delegating back to the delegator.
    self._forwardWeight(msg.sender)

# Give your vote (including votes delegated to you)
# to proposal `proposals[proposal].name`.
@public
def vote(proposal: int128):
    # can't vote twice
    assert not self.voters[msg.sender].voted
    # can only vote on legitimate proposals
    assert proposal < self.int128Proposals

    self.voters[msg.sender].vote = proposal
    self.voters[msg.sender].voted = True

    # transfer msg.sender's weight to proposal
    self.proposals[proposal].voteCount += self.voters[msg.sender].weight
    self.voters[msg.sender].weight = 0

# Computes the winning proposal taking all
# previous votes into account.
@private
@constant
def _winningProposal() -> int128:
    winning_vote_count: int128 = 0
    winning_proposal: int128 = 0
    for i in range(2):
        if self.proposals[i].voteCount > winning_vote_count:
            winning_vote_count = self.proposals[i].voteCount
            winning_proposal = i
    return winning_proposal

@public
@constant
def winningProposal() -> int128:
    return self._winningProposal()


# Calls winningProposal() function to get the index
# of the winner contained in the proposals array and then
# returns the name of the winner
@public
@constant
def winnerName() -> bytes32:
    return self.proposals[self._winningProposal()].name
2 Likes

Has anyone with AE considered somehow/where asking smart contract developer outside of the AE ecosystem (e.g. Ethereum SC developers) to see what their issues are in Solidity, dev tools and/or integration of tools…?

And in Viper they use assert keyword which is most obvious way to assert conditions in programming language. Aeternity extended Sophia language with keyword require:

I don’t like it as it is like blindly mimic trends in Solidity - the language that at some stage might be deprecated.

I think require keyword should be reserved for other purposes.

I don’t know if anyone has done a study on what users from other blockchains would like to see. I guess that it very much depends on what they think of the contract they are using now: if they like then they would probably prefer to see a similar language, while if they hate it then anything else would be better.

The interesting question is in what way Solidity is the most popular SC language. Is it because it is the most commonly used (is it?) or because people really like it?

2 Likes

I am guessing here that FATE, the aeternity VM, could be used as a general purpose language. It is however a VM designed for Sophia, a functional language, so you would have these restrictions on you could do. For example data is immutable, except for the state record, which you would then see in your language. However as soon as you do something related to blockchains then you would automatically be in the aeternity world. Contracts as such are on the blockchain so calling another contract means you are in the aeternity world.

I don’t think that anyone has attempted to make a stand-alone implementation.

About syntax I can say I am not that enthusiastic about Ruby, elixir or Scala. In general I don’t really like languages in which line breaks and indentation are significant, which rules out Python. I also prefer simple syntaxes with too many special cases or other cruft. The erlang syntax follows these goals even if it does look a bit strange. :grinning:

I did start work in Aeternity on another contract language which would have been called Varna. The syntax I started with was Lua based but the project was put on hold.

Of course the absolutely best syntax is LISP. :wink: It is simple, consistent, powerful and extremely versatile. Unfortunately not everyone gets it. :cry:

2 Likes

Viper looks way too much like Python. :wink:

2 Likes

I think next to a language, we are especially looking for a solution to run Erlang in the browser. That would solve many client side trust problems.

Best

1 Like

How do you mean run Erlang in the browser?

Ha! Sorry this was the wrong thread. This message ended up here by accident. To clarify: currently most of the heavy lifting are done in the node by the fsm and the compiler. As a user, you might not want to trust the node as it could trick you to something you do didn’t want. Therefore we need a more trustless way, client side. One way would be to reengineer the FSM and other parts in for example Javascript so users can run and verify it client side. Or, this was my message all about, we manage to use the Erlang code somehow.

@jsnewby presented a few ideas here. I think @botanicalcarebot.chain can comment too.

@nikitafuchs.chain maybe you can add a few things here too.

1 Like

I think it is mostly because it was the first smart contract language (based on the popular Javascript) → developed a large dev community (network) → many code libraries became available (for copy/paste-ing into your own project) → devs got used to it. I am not sure if they like it.

2 Likes

Correct, this topic doesn’t seem to be related to the original discussion :slight_smile:

Anyway, @emin.chain referred to the discussion on how to get the Aeternity node (and implicitely the State Channels component) on mobile devices. One approach which has been proposed by and is being prototyped at the momentby @jsnewby (afaik) is using Lumen to cross-compile the node as is for WASM. @nikitafuchs.chain planned to get a working group going on the topic to get a better idea of the requirements and possible approaches.

2 Likes

I really like those efforts and think it is the right way to go.

Before we try to write a VM in Javascript and having it maintained and updated whenever something updates in the core protocol, we should check out whats possible with WASM/Lumen and so on.

Would you agree?

PS: i think its still relevant for this threat even though we talk about alternate contract languages.

1 Like

Agree, especially because our VM is orders of magnitude more complex than the EVM. Regarding another language: I havn’t seen any signs of necessity so far, to be honest. Where we would truly need your expertise @rvirding is to somehow get the FSM or a stripped-down-for-payments-only version of it running on - at least - android. This would put us ahead of other protocols by far, and could empower mass adoption of aeternity for the means of payment in poorer countries.

2 Likes

I think trying out the WASM/Lumen path is something which will yield good insight into some of the cross-platform breaking points. However, I don’t think it will be a solution, mostly because Lumen is young, incomplete and untested and therefore it shouldn’t be used for such critical use-cases.

Another option for the WASM approach would be to actually go via the Erlang HiPE LLVM backend. While this will still require a lot of effort, the parts which are in place are well-tested and solid. @Happi is the person to talk to in that regard.

1 Like

The state channels team has started creating a quickcheck model of the FSM. Once that is done it will be a lot easier to create sub-models for a subset of functionality which in turn would be a great help for creating alternative smaller FSMs. We should get started on gathering requirements though soon.

1 Like

OK, so I find both options that have been discussed here, an alternate contract language or implement Sophia in the browser, very interesting. But they require a very different level of work so in one way it is difficult to compare them.

For an alternate contract language you already have everything in the node already implemented and accessible through the FATE vm. You “just” need to put a new layer on top of it and if you are a little cunning it shouldn’t be too hard to interface.

Implementing Sophia in a browser is a completely different thing and much more complex. One way to do it would be to implement the Erlang vm in the browser with say Web assembly or javascript. This would (hopefully) allow you to run most of the aeternity node, or at least those bits you need. It would also be something interesting for not just aeternity nodes but running general erlang stuff in the browser.

Implementing Sophia directly in the browser with just limited node functionality would/could perhaps be easier but more restricted.

I personally think that doing either would be a lot of fun, but they are completely different levels so someone has to decide how to go forwards.

4 Likes

I totally agree on everything. I also really like that Sophia and the æ VMs limit mutations to the state record. I think that trying to manage state correctly is the thing that causes most bugs in any application. While Haskell Mondas are probably the cleanest and most powerful solution for this, they seem to be too complex or too alien for most people to hook on.
Vue, React and Flux on the other hand also use confined-state updates (though only by convention, not enforceable in JS), and are hugely popular.
I think the language of my dreams would combine LISP syntax with static type inference and checks (maybe similar to Typed Clojure) and confined state updates.

1 Like