operanditech / statemirror

A fully featured receiver library for the operations sent by the nodeos statetrack_plugin
MIT License
3 stars 0 forks source link

Development Plan #8

Open andresberrios opened 6 years ago

andresberrios commented 6 years ago

Functionality:

Implementation ideas:

mmcs85 commented 6 years ago

I have done some work on this and currently:

Example: 4 trxs inside 2 blocks

- B1

- T1 
     - MODIFY (V1 to 3)
     - REMOVE (V1)

- T2
     - ADD (V1 1)

- B2

- T3
    - MODIFY (V1 to 2)

- T4
    - MODIFY (v1 to 4)
    - REMOVE (v1)

pop_block B2, B1

B2 ADD (V1 1)

B1 REMOVE (V1) ADD (V1 2)

As you can see when sending T3 we don't know that T4 will optimize the undo stack, also the ops reflect the actual state change. But on B2 undo operation the undo stack session only emits the op that reverts to the last state of B1. I can't see any way to group this op in any trxs on B2.

I believe that the best we can do is to broadcast trxs and when a fork happens broadcast a block with all the undo ops not grouped by trx or action.

andresberrios commented 6 years ago

Ok, I see what you mean, and I also think it would be fine for the majority of use cases to send the optimized changeset, but when we discussed the tracking of operations using a before_emplace event for example, I thought then you would use that to reverse the operations as soon as they come and store the reversed ones before they get applied to the state DB, by checking the current data before it is modified. That way you can just store them right next to where you store the forward operations, since each operation should have its reversed one, and they would all be grouped by transaction and action. But I think it's fine to maybe for the moment just send the undo ops per block, it would work well for most purposes.

mmcs85 commented 6 years ago

Sorry I didn't get that idea.

For this type of implementation:

I guess this is a tradeoff we need to address with the needs of dapp developers.

andresberrios commented 6 years ago
  • I believe that we need only a before_modify to be able to generate a modify for the old_value. Or at least a way to send both old_value and new_value in the applied_modify.

Yes, I think both options are fine, but maybe it's better to not send both values from chainbase since maybe other plugins will need only one, so the chainbase signal code would be doing extra work that wouldn't apply to cases other than ours.

  • Should we send all the reverse trx's with undo ops or in this case if we send in the modify op (old_value, new_value) inst it also possible that the receivers to apply the reverse of ops and we just send a pop_block event? This way there inst a need in plugin end to store undo ops and create that logic. But will need for the receivers to store the block for eventual reversing it.

I think we should avoid sending the reverse operations in the normal transaction messages, since we would be using a lot more bandwidth than necessary since the undos will not happen very often. It's better if the plugin keeps track of that and sends it only when it's required.

  • This would remove the need for emitting the undo ops.

Yes it would :) but maybe we should leave the signals in chainbase but just not use them, because they might be useful for other people making other plugins.

  • The reversed ops would be unoptimized but then It would be possible to send reversed trxs.

Yes, they would be unoptimized but when the receiver decides to apply them, they can very easily optimize them themselves. We can provide the optimizing code in the receiver library for them to use. It would simply need to go through the operations and remove the pairs that cancel each other (in the case of emplace and erase) or overwrite each other (in the case of modify). I can handle that part in the receiver code.