Steem as a Smart Contract Platform

avatar
(Edited)

As a blockchain developer I was excited to read the marketing material distributed about Lisk. The concept of a blockchain and smart contract platform entirely powered by JavaScript is something I have been wanting to build myself. I never got around to doing it because the complexity involved was beyond my time and budget.

The Purpose of Smart Contract Platforms

I recently reviewed the Lisk documentation to learn more about developing Smart Contracts on their platform. I was surprised to see that their approach to Smart Contracts is almost identical to what is possible with Steem today. Their first two examples were a messaging contract and a reddit contract.

I recently implemented a similar messaging application (aka plugin) for Steem. I will show a simplified version of my messaging plugin below. I simplified it by removing encryption.

Here is an example of how we would implement the messaging Smart Contract on Steem.

Step 1 - Define a message

  struct private_message {
      string from;
      string to;
      string message;
  };
  FC_REFLECT( private_message, (from)(to)(message) )

Step 2 - Define a database and indicies

This step is really no more complicated than using standard Boost Multi Index Containers. These containers have much higher performance than any SQL database with similar indices. In this case we build a robust index that makes it easy to query messages in the order they were received and/or sent. This enables "inbox" and "outbox" functionality for every user.

struct message_object {
    time_point received;
    string         from;
    string         to;
    string         message;
};
FC_REFLECT_DERIVED ( message_object, (db::object), (received)(from)(to)(message) )

struct by_to_date;
struct by_from_date;
struct by_id;  
typedef multi_index_container<
   message_object,
   indexed_by<
      ordered_unique< tag< by_id >, member< object, object_id_type, &object::id > >,
      ordered_unique< tag< by_to_date >, 
            composite_key< message_object,
               member< message_object, string, &message_object::to >,
               member< message_object, time_point, &message_object::receive_time >,
               member<object, object_id_type, &object::id >
            >,
            composite_key_compare< less<string>, 
                                   greater< time_point >, 
                                   less< object_id_type > >
      >,
      ordered_unique< tag< by_from_date >, 
            composite_key< message_object,
               member< message_object, string, &message_object::from >,
               member< message_object, time_point, &message_object::receive_time >,
               member<object, object_id_type, &object::id >
            >,
            composite_key_compare< less<string>, 
                                   greater< time_point >, 
                                   less< object_id_type > >
      >
   >
> message_multi_index_type;

typedef generic_index< message_object, message_multi_index_type> private_message_index;

Step 3 - Define an API

The purpose of defining an API is to allow 3rd parties to inspect the state of your app. In this case we need two API calls. One to fetch the inbox, and one to get the outbox.

class private_message_api : public std::enable_shared_from_this<private_message_api> {
   public:
      typedef vector<message_object> messages;
      private_message_api(const app::api_context& ctx):_app(&ctx.app){}
      
      messages get_inbox( string to, time_point newest, uint16_t limit )const;
      messages get_outbox( string from, time_point newest, uint16_t limit )const;
   private:
      app::application* _app = nullptr;
};

Step 4 - Implement Message Handler

The purpose of this method is to update state every time a private_message operation is included in the blockchain. This message handler verifies that the message was signed by the sender, and if so adds the message to the database.

void private_message_plugin::on_operation( const operation_object& op_obj ) {
  if( op_obj.op.which() == operation::tag<custom_json_operation>::value ) {
    const custom_json_operation& cop = op_obj.op.get<custom_json_operation>();
    if( cop.id == "private_message" )  {
      auto message = json::from_string(cop.json).as<private_message_operation>();
      FC_ASSERT( cop.requires_auth(message.from),"sender didn't sign message" );
      
      db.create<message_object>( [&]( message_object& pmo ) {
               pmo.from               = pm.from;
               pmo.to                 = pm.to;
               pmo.message            = pm.message;
               pmo.receive_time       = db.head_block_time();
            });
    }
  }
}

Step 5 - Implement the API

This API is accessible via JSON RPC to the steemd process. It will return up to limit messages that are older than newest where the receiver is to. The get_outbox api is almost identical except instead of using by_to_date it uses the by_from_date index.

messages private_message_api::get_inbox( string to, 
                                         time_point newest, 
                                         uint16_t limit )const 
{
   const auto& pmi = db.get_index_type<private_message_index>();
   const auto& idx = pmi.indices().get<by_to_date>();

   messages result;   
   auto itr = idx.lower_bound( make_tuple( to, newest ) );
   while( itr != idx.end() && limit && itr->to == to ) {
      result.push_back(*itr);
      ++itr;   --limit;
   }

   return result;
}

Things to Note

  1. The app developer did not have to implement any undo features.
  2. The app developer did not have to worry about fees.
  3. The app developer did not have worry about the difference between confirmed and unconfirmed.
  4. The app developer did not have to worry about serialization.
  5. The code is relatively short and concise

The Steem blockchain is powered by Graphene which automatically handles all of those complexities. Developers must still take care that their implementation does not create an infinite loop, memory leak, or generate undefined behavior.

Side Chains

A smart contract on Steem can use side chains. A side chain is really a fancy way of saying a multisig account where the transactions that should be signed are agreed upon by consensus and then signed by multiple independent parties as defined by a smart contract. Steem Smart contracts can interact with the rest of the Steem blockchain just like any other user can. The smart contract consensus algorithm will generate and sign valid Steem transactions which get included in the Steem blockchain.

App developers could use Steem and BitShares to implement smart contracts via Side Chains in the same manner. Steem has one major advantage that no other smart contract platform has: free transactions. This means that anyone can implement a side chain "smart contract plugin" without having to worry about the fees their contracts require.

Conclusion

Steem can be used as a powerful smart contract platform, the possibilities are endless.



0
0
0.000
19 comments
avatar
(Edited)

Ethereum forces App developers to connect to multiple smart contracts just build a Dapp, this burdens Dapp development among mainstream developpers, that's why Ethereum failed to produce more than a dozen working Dapps.

Lisk's easy deployment of Blockchain Apps using SDK and its sidechain design is guaranteed to scale easier than Ethereum, and we will soon see the Lisk App store boast far more Blockchain Apps than Ethereum.

Also, it's very unfair to compare Lisk that was released 7 days ago, to Ethereum that was released 1 or 2 years ago. And comparing Lisk to Steem is just laughable.

ps. Don't bother replying here, because I won't read it. If you want to discuss Lisk come to the official Lisk thread or chat on https://forum.lisk.io or https://chat.lisk.io

0
0
0.000
avatar

"Don't bother replying here, because I won't read it."

How much do you bet that you will read it ?

0
0
0.000
avatar

Looks like $24.89 so far ;)

0
0
0.000
avatar

Your thought on eth is accurate. I have my own issues with eth. I also believe lisk could become something eventually. I guess my feedback is that lisk needs to improve dev tools. The current examples are very complicated next to a similar eth or steem app.

0
0
0.000
avatar
(Edited)

solidity very similar to javascript anyways...

0
0
0.000
avatar

In terms of structure, syntax etc, yes. That's why it's preposterous for Lisk guys to say that Ethereum is "too hard" for javascript devs. It's not, and it'll make you a better programmer. The only people who can't learn Solidity shouldn't be writing Dapps directly onto the Lisk chain either. XD

Solidity requires to be compiled which means that you can catch bugs and stuff before they get on the chain. It also ensures that no non-deterministic behavior gets through while on Lisk it can.

0
0
0.000
avatar

It kind of blew my mind that the white paper, branding, crowdsale, creation, and on-going forum discussions of Lisk seemed easier than just learning to write Solidity. That was the first thought that entered my brain reading the white paper, it just seemed like a lot of extra work. I started with Javascript about a year ago with my intention being to learn Solidity when I felt comfortable With JS. I'm starting to learn solidity now...my point is that if I could do it more or less on my own, How is it too hard for an experienced programmer? Is this not like hanging your own "Banos" signs the restroom door @ your favorite restaurant because you have a lot of Spanish speaking friends?

0
0
0.000
avatar

One thing you're missing is that Lisk apps don't get deployed directly onto the main chain. With LIsk, each app (or DAPP) gets deployed onto its own sidechain.

0
0
0.000
avatar

This was a great read. Even though I knew the basic structure of the Graphene code already, I have never though adding a new operation (like private_message) would be that simple.

However, the usage of Boost multi index containers is still above my head. Maybe I can learn how to read that stuff eventually.

Thanks for that great post anyways!!!

0
0
0.000
avatar

based on my experience on messaging engine business. JavaScript always this first point to fail in a heavy duty environment

0
0
0.000
avatar

@dan, if I were to get a steemit logo tattoo on my arm, would you buy it for me? :P I would do it! Would be good marketing.

0
0
0.000
avatar

Steem is a great invention, here will be brilliant.

0
0
0.000
avatar

Would be great to have a prediction market contract so there could be bettings and such.

0
0
0.000