Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

copy of issue in EOS #5568- Best practice question relating to Demux #58

Closed
halsaphi opened this issue Oct 4, 2018 · 2 comments
Closed

Comments

@halsaphi
Copy link

halsaphi commented Oct 4, 2018

Summarizing the Problem

What is the best practice when it comes to tracking RAM changes on the ledger? Consider the following situation: we have a smart contract with a series of actions that are manipulating various tables on the on-chain RAM. When a smart contract action manipulates multiple entries on the RAM tables, how do we get that information on the ledger?

Example: A user can have an account, items to trade, and can send and receive trade offers. Consider the following action:

deleteAccount

data: {

id: 7

}

The smart contract takes that action and performs the following logic:

get account with an ID of 7
get all items that belong to that account
get all offers that belong to each of those items
delete offers
delete items
delete account
The ledger, to our understanding, just sees the information passed into the account, which is:

deleteAccount

data: {

id: 7

}

Those watching the blocks (such as applications running demux to track the state of this particular dApp) would be unaware of the other entries that were manipulated on RAM (offers and items).

We are looking for a way to expose any change done to RAM on the ledger so that anybody or anything watching the blocks can derive a state locally if they replay the chain.

We have come up with a few approaches, and were wondering if there’s a best practice and/or a more appropriate way of doing this than presented below.

Approach one

Make an assumption of what will be affected by the smart contract action by looking at your local state and passing that information in the action. The local state would be derived from a demux implementation that’s watching all blocks from the chain and mapping relevant data to our local database.

So by following the example above, before we pass the deleteAccount action to the smart contract, we would first look to our database and gather all of the other entities that will be affected and include them in the payload to the smart contract.

deleteAccount

data: {

id: 7,

items: [10, 13, 44, 233, 321],

offers: [32, 108, 2332, 2433]

}

Then the logic would be as follows:

get account with an ID of 7
get all items that belong to that account
verify items retrieved equal 10, 13, 44, 233, 321
get all offers that belong to each of those items
verify the offers retrieved equal 32, 108, 2332, 2433
delete offers
delete items
delete account
If either of the verification steps fail, the action would be kicked back as invalid. But if all succeeds, then data that flows through to the ledger would fully instruct a demux implementation of how to update a local database’s state.

Approach two

The seconds approach would follow the same philosophy of packaging all information in action’s payload that will be affected by the smart contract, but instead of retrieving the information from the local database, it retrieves that information from the chain's database through an API node.

So the payload below would reach out the API node and request all items that belong to account 7. Simultaneously it would request all offers that belong to each item retrieved. Then it would include that freshly-retrieved information in the payload and pass it to the smart contract, which would follow the same logic of verifying the state is in-sync before processing.

deleteAccount

data: {

id: 7,

items: [10, 13, 44, 233, 321],

offers: [32, 108, 2332, 2433]

}

Questions

The only difference between these two approaches is the way they each get the ancillary data before passing it into the smart contract. Our questions are:

Is this design philosophy the most effective way to make the changes to RAM transparent on the ledger?
Which approach would be quicker while keeping in mind the necessity for accuracy: using our local database or using an API node?
Is there no way to include additional data with an action as it hits the ledger, such as response{...} or result{...}?

@flux627
Copy link
Contributor

flux627 commented Oct 4, 2018

There are some changes coming that will make this process obsolete, but as of right now, you need to re-implement contract state-changing logic in your Updaters so that your database can track the values in parallel. In other words, you need to track all actions that may affect the RAM state value of terms, offers, accounts, etcetera, so that when you get your deleteAccount action, you can properly update these values, too.

The only thing different from your second option and what I would recommend is, instead of modifying the payload of the deleteAccount action with the additional fields, simply retrieve the database values you need in the deleteAccount Updater function.

Soon, we'll be able to track state within Demux natively, which means that the state updates will simply come in as "virtual" actions (an action that may be processed by its corresponding updater).

I'm going to close this and re-open an issue related to capturing blockchain state, but feel free to continue the conversation here / ask any followup questions.

@flux627 flux627 closed this as completed Oct 4, 2018
@flux627
Copy link
Contributor

flux627 commented Oct 4, 2018

Created a new issue here: EOSIO/demux-js-eos#18

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants