hyperledger-archives / iroha

Iroha - A simple, decentralized ledger

Home Page:http://iroha.tech

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Command processing simplification proposal

Warchant opened this issue · comments

Nobody reads longposts, so I will try to be short.

Problem

Currently to implement own command type I need to:

  • write its interface in sm
  • write protobuf implementation
  • write executor
  • add command to commands.proto
  • (maybe something else I forgot?)

The point is that it is hard to do and I need to do changes in many places. No good.

Proposal

Main point: use interpreter pattern.

  • transaction.proto becomes:

    message Transaction {
     message Payload {
       bytes  commands = 1;
       string creator_account_id = 2;
       uint64 created_time = 3;
       uint32 quorum = 4;
      }
    
     Payload payload = 1;
     repeated Signature signatures = 2;
    }
  • client side - compiler (C++ example):

    #define OP_CREATEDOMAIN 0xfd
    
    class TransactionBuilder {
      // a-la stack
      std::vector<uint8_t> commands;
    
      ...
    
      TransactionBuilder createDomain(
        std::string domain_id,
        std::string default_role
        ){
        // push command type
        commands.push_back(OP_CREATEDOMAIN);
    
        // push args. as example, push <length>:<contents>
        push_string(&commands, domain_id);
        push_string(&commands, default_role);
        return this;
      }
    }

    data structures of arbitrary complexity can be encoded in this way with 1code (bencode extention).

  • iroha side - interpreter:

    std::vector<uint8_t> commands = tx.getCommands();
    while(!commands.empty()){
      opcode op = readOpcode(commands);
      // switch-case or handler map can be used:
      switch(op){
        ...
        case OP_CREATEDOMAIN: {
          // this command expects to receive 2 strings as args:
          std::string domain_id = readString(commands);
          std::string default_role = readString(commands);
    
          // execute...
        }
      }
    }

Features

  • complex and unnecessary code can be removed (lots of builders, interfaces, proto)
  • new commands can be added quickly with modifications in exactly 2 places (compiler, interpreter)
  • no proto modifications required to add new command
  • transaction becomes a flat structure. No complex protobuf code to build clients required
  • ethereum does the same in EVM, bitcoin does the same in script
  • this can be a starting point to smart contracts. opcodes for stack management, state management and math can be easily added.

Stack-based interpreter (VM) can also be used:

PUSH domain_id
PUSH default_role
OP_CREATEDOMAIN // pops top 2 items from a stack, interprets them as strings and executes OP_CREATEDOMAIN

P.S. in previous msg there is no stack, only pure string parsing