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
Moved to Jira: https://jira.hyperledger.org/browse/IR-195