-
Notifications
You must be signed in to change notification settings - Fork 3
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
Coupling between transaction
and chainhead
functions
#79
Comments
The reason why transactions functions can lag behind the chainHead functions is in case of a load balancer that redirects transaction functions to one node and chainHead functions to a different node, and that the node handling transaction functions is lagging behind. But I want to point out that if a node is lagging behind, its chainHead functions will lag behind as well, and the transactions validated using this node might be invalid as a result. Consequently, coupling transaction and chainHead functions doesn't solve this problem. In fact, nothing on the JSON-RPC level can solve this problem, it's just something to accept. |
I concur that if a node's However, my central argument for merging the By merging them:
Considering solutions 3 and 4: If we choose the former (merging While I acknowledge the limitations you highlighted, I still think that merging the 2 groups of functions (in one way or the other) would be the right thing to do if the |
FWIW I can see the appeal of having eg a The events (dropped, error etc) would still be useful I think (to me at least!), for the same reasons as before:
On these threads I feel like I am in the minority with my position on this, but there you go :) |
Sorry, it seems that I didn't explain myself correctly. It's not that you will no longer have access to these events, it's that they will be encompassed by the already existing events on For instance the current
If we merged
I mean, sure, we could have some redundant events for the |
From my perspective, I believe that merging the two classes of functionality would be the cleanest from substrate perspective and user interaction (see my original comment here). The events produced by the actual transaction_unstable_submitAndWatch would still be valuable to the end user, at least from my view of the chain through the subxt lens. I believe having this low-level API would allow us (subxt / capi) to expose nicer APIs that may be more simplistic and still be efficient, we could filter out easily the events of the chainHead. |
Aah, gotcha, yup def makes sense to be consistent if we were to go this route!
If the node is already checking for the tx in blocks, then having it tell the client about the result doesn't feel redundant to me; it's just sharing potentially useful information that it already knows and which you'd otherwise have to work out locally instead, duplicating what the node is doing (which can be easily ignored if not interesting to you). Maybe we'll just have to agree to disagree on their usefulness (but blah blah full node, performance win not downloading block bodies if I don't have to too :)) (I'd also add/question this: downloading block bodies when |
Sorry, I mistakenly assumed that you were well acquainted with the proposal that I made on #78 . In that PR I suggested this. In a nutshell: the already existing
If we went down that this path (or a similar one), then the events that you are mentioning would certainly be redundant. Although, again, I wouldn't necessarily be opposed to having those redundant events (as long as I get to have the simplest one, of course). |
Sorry, I only saw your edit after I had already answered.
If we went with something like what I was proposing in #78 , then yeah, of course... there wouldn't be a need for the client to download the bodies, no. At least not for the purpose of finding the transaction inside the block, nope. |
Regarding the events of the tx on the chainHead:
"submittedTransactions": [
{
"operationID": "...",
"index": 0
},
...
], Then we could remove the need for the We could adjust the #78 to keep parity between the APIs while offering the guarantee of the pinned block of the transaction. From a substrate standpoint, synchronization of the TransactionStatus with the generated blocks of the chainHead would introduce a certain level of complexity. This synchronization process should be approached thoughtfully |
That's because after looking at the implementation on
No, it doesn't. It adds a "dictionary", for which the keys are the operationIds and the values the index of the transaction inside the block. Please, pay closer attention.
Please, please, please read it well 🙂 . This is not correct. Notice the code of the example, in the PR: {
"submittedTransactions": {
"operationIdA": 0,
"operationIdB": 3,
...
},
} And it's also in the description:
|
The impossibility to download block bodies, or the transactions pool being full. In the case of a full node, in case of a reorg, the transactions pool might need to be filled with older transactions which kick out more recent ones. I see a lot of arguments in these discussions which I think are wrong but I don't have the energy to answer everything. I'll do a write up in the near future. |
Awesome! Then I stand corrected! So, it seems that if we went down this path, then we would need a specific event for the
😞
Thanks @tomaka ! Really looking forward to it! |
Objective and how things workWhat we want to do is: construct the transaction, send it out, then detect when it's included in the chain. Constructing the transactionIn order to construct a transaction, a UI needs to know, amongst other things, a block hash (for mortal transactions), a spec version, transaction version, and metadata hash. All this data should be obtained by the UI through the After the transaction's body has been constructed, there exists three different situations:
Note that in the case of mortal transactions the block hash found within a transaction do not have to match the block the transaction is valid against. The block hash found within a transaction is meant to be the reference point at which the transaction starts being valid, and, in fact, as far as I can tell, the block hash found within a transaction is completely unused. It is important to note that a transaction is only ever valid or not against a specific block. If multiple nodes disagree on which block is the best block, they might also disagree on whether a certain transaction is valid. A transaction might be valid ag against a certain block and not the next, or vice versa, or might be valid againt a certain block but not its sibling. Sending out the transactionOn a light client, submitting a transaction consists in sending the transaction to the full nodes it's connected to. A full node that receives a transaction through its JSON-RPC server and adds it to its local pool always checks whether the transaction is valid. This is necessary in order to not fill the pool with invalid transactions. When a full node receives a transaction over the networking, it might also discard said transaction if its local pool is already full. In that situation, no feedback is given to the sender. This is a niche situation but that can realistically happen. Detecting when the transaction is includedIn order to detect when a transaction is included, a UI or JSON-RPC server has to download the block bodies of every block that was authored after the transaction has been sent out, and check whether the desired transaction is found in one of the bodies. It is important to note that it is not possible to (reasonably) be sure that a transaction has been included. For example, one could send out a transaction then lose Internet connectivity for a few minutes during which the transaction might have been included. It is possible to check for example whether the nonce within the transaction has been used, but not whether a specific transaction has been included (except by downloading every single block that was missed, which is not a scalable solution). It might also for example simply be impossible to download block bodies due to peers refusing to respond. Resolved questionsShould transactions be validated (either by the JSON-RPC client or server or both) before being sent out?It depends. If the number of transactions being gossiped in total at the same time by a node is significant (more than 2/3) then yes in order to avoid the node being banned, otherwise it's not necessary. Should the JSON-RPC server validate the transactions that it receives from the JSON-RPC client?It depends. As explained above, if the number of transactions being gossiped at the same time is very small, then no. Additionally, if the JSON-RPC server trusts the JSON-RPC client to always submit valid transactions, then no. In other situations (JSON-RPC client untrusted and a large number of transactions), then yes. How does the JSON-RPC client-server combination that gossips a transaction know when to stop gossiping?This question is less trivial than it seems. It is possible, due to the asynchronous nature of blocks gossiping and transactions gossiping, for a full node to receive a transaction from the peer-to-peer networking after this transaction has been included in a block. In that situation, because we don't want the same transaction to be included a second time, it is assumed that the runtime will designate a transaction as invalid if that transaction has been included in the chain in the recent past. Thanks to this property, there is no point in gossiping a transaction after it has been included in the chain. A node that gossips the transaction should therefore stop gossiping at the latest after the transaction has been included in the finalized chain or has become invalid in the finalized chain. This can be determined either by the JSON-RPC server itself, or with the help of the JSON-RPC client. If a transaction is not included in the chain, can a JSON-RPC client or server know the reason why not?A transaction might not be included because other nodes consider it invalid, but also because the transaction pools of all other nodes is full, or maybe the chain is simply temporarily overloaded and the transaction will be included later. Even if a JSON-RPC client or server validates the transaction it sends out, this does not offer a guarantee that other nodes consider the transaction as valid, and thus does not offer a guarantee that this transaction will be included in the chain in the future. All in all, the answer to the question is no. The best a JSON-RPC client or server can do is send the transaction again after a little while and/or rotate its peers, and hope that it will be included. On the other hand, if a transaction is invalid against the finalized block, then it can be assumed that it will remain invalid forever (see previous question). In other words:
Does the JSON-RPC server used to generate or validate the transaction have to be the same JSON-RPC server that gossips the transaction?If the JSON-RPC server that gossips the transaction doesn't validate the transaction, then obviously no, as there is no problem. If the JSON-RPC server that gossips the transaction validates the transaction, then also no for the reason explained below. The JSON-RPC server that watches the chain might think that a transaction is valid while the JSON-RPC server that sends out the transaction might think that it's not, or vice versa. However, this is also the case for all nodes of the peer-to-peer network. The very vast majority of the time, there will be no mismatch: the transaction will either be considered as valid by both JSON-RPC servers or invalid by both JSON-RPC servers. If there is a mismatch, it is in practice likely cause by one of the JSON-RPC servers being misconfigured or buggy or lagging behind, in which case there will also be a mismatch between one of the two JSON-RPC servers and the rest of the peer-to-peer network. When it comes to checking whether the transaction has been included, does the JSON-RPC server that follows the chain have to be the same JSON-RPC server that gossips the transaction?No. There is no connection whatsoever between gossiping a transaction and receiving the block in which it has been included. In other words, the chances of finding the transaction in a block is exactly the same whether the chain is watched through the JSON-RPC server that has gossiped the transaction or through a different JSON-RPC server. (provided that there is no netsplit, but since we're in a situation where the same JSON-RPC client is able to reach both JSON-RPC servers, these two JSON-RPC servers are normally also able to talk to each other) (also note that this is not really true if the JSON-RPC server is a validator, in which case that validator might generate the block containing the transaction, which is obviously an advantage, but we ignore that possibility because validators aren't supposed to be publicly-available JSON-RPC servers) Does it make sense for a JSON-RPC server to support sending out (i.e. gossiping) transactions without supporting following the chain?Not really. This question is relevant, because sending out transactions can be implemented in a few thousand lines of code (provided transactions aren't validated), while following a chain requires probably at the very least 20k to 30k lines of code. Even ignoring implementation difficulty, gossiping transactions doesn't require downloading and compiling the runtime of the chain while following the chain does. If a JSON-RPC server supports both, it is still advantageous to not follow the chain and only gossip transactions. However, if a JSON-RPC server (or a group of JSON-RPC servers behind a load balancer) doesn't support following the chain, then a UI can only generate immortal transactions and can't know whether a transaction has been included in the chain. Alternatively, we could imagine a micro-services architecture where some short-lived micro-services follow the chain and generate transactions, then dispatch these transactions to long-lived micro-services that only them send out, or something similar. Also a rare edge case. Open/controversial questionsIf the JSON-RPC server validates transactions that it gossips, should it report to the JSON-RPC client when the validation fails? And should the JSON-RPC client validate transactions?A JSON-RPC client is expected to only ever submit valid transactions. There is in general no point in submitting invalid transactions except for malicious intents. When it comes to designing the API, we simply ignore situations where the JSON-RPC client intentionally submits invalid transactions. There are then three possibilities:
Put differently, the only situation where reporting validation failures to the JSON-RPC client is useful is if the JSON-RPC client does not continuously validate the transactions it submits. The vast majority of the time, JSON-RPC clients validate transactions that they submit at least once before submitting them (in order to calculate fees, see first question), and consequently validating them continuously doesn't seem like much more effort to me in terms of implementation. Should the JSON-RPC server continuously validate the transactions that it receives from the JSON-RPC client?(this is a revisit of the question above) If the JSON-RPC server must indicate when validation fails, then obviously yes. Otherwise, the answer is the same as above: if the number of simultaneously gossiped transactions is small (2 to 3) then no, otherwise yes. Should the JSON-RPC server report to the JSON-RPC client in which block a transaction is included?This is where the problem originally stems from. If the JSON-RPC server does report blocks in which a transaction is included, then these blocks might conflict with the blocks reported by the This problem can be solved:
Should the JSON-RPC server follow the chain in order to find whether a transaction is included?If the JSON-RPC server must report to the JSON-RPC client the block in which a transaction is included (see previous question), then yes. Otherwise, the JSON-RPC server needs to a way to know when to stop gossiping transactions. ConclusionThe paragraphs above can be summarized as:
We can also add:
There are therefore three valid possibilities:
My PR (#77) picks options 1 and 3 in this list. Overall I'm still in favor of my PR (#77). |
|
Thanks, @tomaka, for the detailed write-up. I've gone over it multiple times to fully understand. With the newfound context from the earlier issue, I must clarify a pivotal realization I had only recently. My primary concern, now clearer than before, is understanding in "real-time" which blocks the light-client (or the JSON-RPC server) has assessed for pending transactions. In essence, if I could have this insight, it would satisfy my main requirement. I regret not having articulated this from the start—it's only now that I truly recognized this as the crux of my needs. Furthermore, I'd like to apologize for any instances where I may have conflated my needs as a consumer of the API with operational requirements. I appreciate your patience in helping clear up these distinctions. Given this clarified stance, the questions remain: Is it feasible to convey this information to the client? If not, what alternatives exist? And if yes, how best to relay it? If conveying block-scrutiny details isn't feasible, I can settle with just having #77, with one request: the inclusion of If it is feasible, two options come to mind: Option 1: Merging
|
Everything is feasible.
Keep in mind that it's not because a transaction is found within a block that it won't also be found in the parent of the block. |
I'm well aware of this 😉. At the same time, I can totally see why you felt compelled to remind me of this 🙂 - so, thanks!
Awesome! I was asking because it's something that I hadn't brought up before your write-up, and since it's well stablished by now that I'm capable of making wrong assumptions... 😅 So, what are your thoughts on the addition of the |
The principle sounds good to me 🤷 |
Awesome!
Got it! For sure, the snipped that I suggested was a just a draft... I certainly hope that we can -at least- come up with a better name for the event 🙈 Ok, so -as far as I'm concerned- we have a plan of action:
Once both PRs are merged, we close this issue 🎉 . @jsdw @lexnv are we all in agreement that this is the best way to go? 🤞 |
I don't think we need to merge #77 then? The only reason why #77 is a good idea is if we want to have servers that implement |
I suppose that's true, yes. I surely wouldn't use it. I thought that perhaps it was a good idea to have it there, because it could be potentially beneficial to other users... However, you are right, I can't think of a single use-case in which the consumer would need it. So, if and when that need arises we can revisit its addition. Let's leave it out for now, yes 💯 So, @jsdw @lexnv are we all in agreement that the addition of this new TBN event is the best way to go? 🤞 |
So, Is the idea that this
In principle I have no objection to this sort of event, since it's just letting the client know a little more about what's happening, which doesn't feel like a bad thing! @josepot I'm curious to know what use case you actually have for such an event though? I guess you want to know ASAP which blocks don't contain a tx so you can unpin them sooner? It also makes me wonder a bit on the overlap between
Perhaps that gives the information needed without having any overlap with the But anyway, it's all good for me (I made a lot of guesses above so I may well be way off the mark) :) |
Yes
correct
correct
I assume that you must be referring to the best/finalized events produced by I mean, just to be clear: the server should try to communicate these "scrutinized" events to the client ASAP. However, let's say that the server is batching the messages that it plans to send to the client in the next batch, then I wouldn't expect for the messages of that batch to arrive in any particular order. As long as the server sends them as soon as it's technically feasible (without having to sacrifice performance), then I'm cool and I don't expect them to come in any particular order. All that being said: we can discuss about the possible convenience of these guarantees in incoming PR.
Amazing! 🙌
I think that I have explained this at length across multiple comments in different issues and PRs... I really don't have the energy right now to explain it again.
Partially... yes.
Please, don't assume that there is necessarily an overlap. This event should only be useful for those users who want to combine the information from this event with the info that they are getting through
No, this alone wouldn't cover my needs, no.
It doesn't.
Awesome!
A little bit 🙂 |
Fair enough! The reason I ask is that I can't see much use myself for this new event. Because as I understand it, it will either report the TX in a block (but this may not be the eventual block that But for this reason I also don't care much either way (and I appreciate that more information from the server is often good) so if you and @tomaka can see the utlity in it then no objections from me :) |
If I understand correctly, option 2 introduces the "blocksScrutinized" event, containing various block hashes. When the server responds, it includes block hashes within the "blocks" field / hash map. Optionally, an index is provided if the transaction exists in the block.
In case servers choose to send individual events, might this resemble a subset version of the According to the information shared at #77 (comment), my understanding is that CAPI's aim is to promptly notify users about transactions as soon as a block is encountered. Could you kindly confirm if my interpretation aligns with yours, @josepot? However, in certain situations there might be potential delays with the "blocksScrutinized" event, causing it to fall out of sync with the reported blocks in the "chainHead." To address this gap more effectively, users have the option to utilize transaction_submitAndWatch, allowing them to discontinue event tracking once the "Broadcasted" event occurs. Additionally, it might prove more efficient to inspect the content of each block produced in the "chainHead" for transactions, rather than waiting for events from an alternative subscription. Wouldn't it be beneficial to introduce a similar version of |
the specifics about this event have been deliberately omitted so that we can discuss them in detail in the incoming PR... Whether the server is allowed to report many blocks at once in the same event, whether the payload should be an array or a dictionary, the name of the event, the guarantees, etc are things that IMO should be ironed out in the PR for that event.
Partially... yes.
That is one of the reasons (not the only one).
I am well aware of that... That's why in my previous comment I said that: "It's just a "nice to have" so that -in most cases- they don't have to do again work that has already been done by the server. That's all it is, really."
Sigh... Thanks for you "insight", but I wouldn't be "waiting for events". Instead, I would be checking if they happened in the past, so that by the time that a block becomes the best block or the finalized block (via Then there is the whole set of edge-cases related to the "discontinuity" of the tracking of finalized blocks, which -despite the fact that I already have a really good solution for- I really don't think that I should have the need to explain in detail right now. Please, I have been developing complex applications that work with real-time data since way before I joined parity. So, please: unless you really understand the problem that I'm trying to solve, please stop trying to tell me how I should be solving it.
No, as Pierre already pointed out: it wouldn't. |
Thank you for your response. I understand your perspective and I appreciate your patience. I do agree that Subxt and the new CAPI have very different goals, and it seems our conversations sometimes end up in circles because we're trying to solve different problems. I'm sorry if my explanations have been repetitive, but I'm eager to break the current cycle of: "we can't be light-client first because the new JSON-RPC spec it's not stable" <-> "the new JSON-RPC spec is not stable because we are not using it." As a developer working on the "new CAPI" (a light-client first library which tries to break this vicious cycle), I have to address problems and constraints that might not yet be on the radar for Subxt (a library which is waiting for this vicious cycle to be broken). I understand that you don't see much use for this new event, and you've made it clear that being light-client first is not Subxt's primary concern ATM. I respect that, and I want to clarify that I'm not trying to convince you to change your approach. However, when we discuss these changes, it feels like my points get brushed aside because Subxt is not able to see things from a light-client first perspective. This is quite frustrating, particularly when what I'm proposing has no impact on Subxt and could be beneficial for other projects. Your interpretation of the event reporting is partially correct, but the complete picture is more nuanced. I have tried to explain it multiple times, and perhaps I've failed to communicate the full implications. I believe that the disconnect stems from our different focuses: Subxt's traditional RPC approach versus CAPI's light-client first requirements. I would appreciate it if, in future discussions, we could respect the fact that we're coming from different perspectives and might not fully understand each other's needs. I kindly ask that you acknowledge that our goals are different, and what might not make sense for Subxt could be critical for CAPI. Given that these proposed changes have no impact on Subxt and could potentially benefit other projects, would it be possible for you to simply say something like, "I don't mind, go for it!"? It would make my work on CAPI more straightforward and less frustrating, and I'd be able to focus more on making progress. |
Hey Josep, Thanks a lot for your patience and for sharing your perspective regarding this! Indeed, at the moment Subxt and CAPI are different in terms of implementation. That is to say, subxt's implementation is heavily based on the traditional RPC APIs. We are making progress towards offering a common API that handles under the hood both the new RPC spec V2 and the traditional RPCs. The RPC spec V2 will be supported by both the light client and the substrate servers. My goals are to understand the spec better to efficiently implement it in substrate and to get a clearer picture of what would need to be done there; while also keeping in mind user interactions (may that be from a biased subxt perspective). @josepot Since these new events could be beneficial for CAPIs use cases and could be filtered out by other users, would you be up for creating a PR to add them? From my perspective, I would like to learn and understand more about these events since we could probably take a similar approach with Subxt and CAPI. Again, thanks for your patience as I understand these discussions could cause frustration sometimes, and look forward to making progress here! 👍 |
@josepot I am indeed fine for these things to be added, as I said above a couple of times. I also very much do appreciate and understand the fact that we have different perspectives. My goal in asking any further questions has simply been to try and understand your perspective and use cases. This obviously hasn't worked out in this case. As long as somebody else does, it's all good for me! As you say, this proposed event addition doesn't adversely impact Subxt. |
I thought I'd do a PR like requested in #80, but I fail to understand how adding the The If the To me the only solution to your problem remains #77 |
perfect!
Also perfect!
Whether the transactions subscription searches for those blocks or not is secondary. The primary objective is to identify the finalized blocks and their relevance to the transaction in question.
I'm unsure where the confusion arises. Even if the
My primary concern is the finalized blocks. Non-finalized blocks, regardless of their origin or difference, aren't relevant to the problem I'm addressing.
Again, I'm unclear as to the rationale here. I'll certainly have the ability to unpin those blocks.
The assertion that #77 is the "only solution" is quite a bold one. My problem:I will try to explain -once again- what I'm after. I'm looking for a specific functionality, and I'll break it down simply: Whenever a block is finalized, I need to determine the status of an ongoing transaction. Specifically:
From your explanation, it seems that (with the Also, I'd like to point out that consuming an operation slot just in the precise moment when a block gets finalized is not ideal. This is the time when the consumer is keen to commence operations to gauge how the finalized block impacts the app's state. Lastly, I'm unsure where the idea came from that I won't be able to "unpin" unrelated blocks. I'll handle them just as I do with blocks not in the finalized chain. The purpose of this "nice to have" event is to swiftly inform the user about the transaction's status in the finalized block. Prompt feedback means users can decide on any subsequent actions faster. Plus, the quicker I understand the user's interaction with that block, the sooner I can determine if it's ripe for unpinning. Addressing Specific Queries:1. Is the
|
That's what is extremely surprising to me. Being able to show in a UI when a transaction is included in the best chain, instead of only when it's finalized, seems like a critical feature to me. If you only care about the finalized block, then half of this discussion is off-topic. Most of the discussion points are relevant only because nodes disagree on the non-finalized chain, whereas the finalized chain can be assumed to always be the same for everyone.
You have never actually explained anywhere what you were trying to do. You jump directly to the problems that you are facing.
The only possible drawback of #77 that is valid is that it makes the client-side implementation more complex. #77 strictly consists in stripping down functionalities from the JSON-RPC server. |
It might be surprising, but while indicating a transaction's presence in the best-block is valuable, it's not critical. The primary utilities of such information are for optimistic dApp updates (that may need to be reverted) and showing intermediate transaction states. These are beneficial but not vital. Hence, while CAPI will strive to provide this insight, its absence isn't detrimental. And, as you're likely aware, the
From the onset, my issue title:
explicitly emphasized the
Agreed, the primary concern with #77 is the added complexity on the client-side. But we should tread carefully. Relying heavily on the argument that client-side implementations can manage everything is a slippery slope. Where is the boundary when most tasks could potentially be handled by the client? In my view, if a function requires an external process for effective client-side implementation, it's better suited for the "server". |
The boundary is actually pretty clear: if there are multiple different ways to implement something that have different trade-offs, and that which way is the best depends on the use case, then it should be on the client side. In other words, the server should be as un-opinionated as possible and just follow instructions. According to this definition, searching for transactions in block bodies should clearly be a client-side process, because there are multiple different ways of searching for the transaction (all forks/only best fork/only finalized, accept/reject trees where some bodies are unknown, etc) that have different trade-offs in terms of bandwidth, latency, and amount of information provided. If you only care about finalized blocks, you can actually do a more efficient search than what smoldot is doing right now, as you can search only in blocks that are children of the latest finalized block, which overall reduces the chances that you'll search in a block that will later not be finalized, and thus reduce the number of block bodies that are downloaded (by 12.5% if I'm not mistaken). The only reason why I think it's not a bad idea to look for solutions other than #77 is because I understand that this significantly complicates the client-side. But if we follow the guiding principles behind which this entire JSON-RPC API has been built around, #77 naturally follows. |
I agree that exploring alternatives to #77 seems prudent. And to clarify, I've never been against #77, but I don't see it as the sole solution for my concerns. Are you suggesting that there's been a change in perspective regarding the
On the topic of efficient block searches: I might be overlooking something fundamental here. Outside of disruptions like disconnections (or a similar situation that makes it impossible for the server to have continuity on the current In the absence of anomalies like disconnections, why would smoldot look for a transaction in blocks that aren't descendants of the most recent finalized block? It's not a critique of smoldot's approach; I'm genuinely trying to clarify a potential gap in my understanding. Could it be related to real-time uncertainties causing such "discontinuities"? |
I initially said yes to the principle of the It does solve the problem if you only care about finalized blocks, but it doesn't if you also care about in which best block the transaction is included. As I've said, I'm extremely surprised that you don't care that a transaction has been included, and I'm very confident that this is something that you will add (or asked to add) later, because to me it's a pretty critical thing. The API of
I said "children of the latest finalized block", and I think you read "descendants" instead of "children". Smoldot tries to report as soon as possible when a transaction is in the chain, so as soon as block appears at the head of the chain smoldot tries to download its body. Unfortunately, 12.5% (I think) of the time this block will end up not being finalized. If instead you wait a little bit then this problem disappears. |
I share your concerns about the
Both alternatives aim for a seamless and comprehensive experience. I believe they might address our current design challenges more effectively than the existing |
The more I think about it, the more I'm leaning towards the approach of splitting the responsibilities of @tomaka, I'm particularly interested in your perspective on this proposal. Could you please share your thoughts when you have a moment? 🙏 |
I completely disagree with "a cleaner design".
You can solve some of these problems by adding an "event ID" to each event, and indicating in the confirmation to I don't care so much about precise answers to these questions, what I what to demonstrate is the fact that this design isn't straight forward at all. You can solve these problems by adding more complexity to the API, but this is not something that we want. |
Thank you, @tomaka, for taking the time to enumerate your concerns. I'd like to address them individually:
Finally, while I respect your viewpoint on the complexity of this design, I believe this approach streamlines the client-side consumption of the API. By shifting some complexity server-side, we're simplifying things for the consumer, which is a worthy trade-off in my opinion. |
But you're not shifting complexity server side. You're shifting some work server side. Yes, the server does more things automatically with your design than with #77. But I'm pretty convinced that the complexity of the code on the JSON-RPC client, in other words the number of possible edge situations to think about, is way higher with your proposal than with #77. That's because you're splitting in two something that shouldn't be split in two. The code that follows blocks and downloads their bodies should be entirely either JSON-RPC-client-side or JSON-RPC-server-side, but putting some on the client side and some on the server side just creates an insanely complex interface between the two. |
I appreciate your feedback, but I have a differing perspective on the matter.
In essence, I believe my approach, far from complicating matters, aims to streamline processes, prioritize performance, and make efficient use of resources. |
For what it's worth, the approach I will probably take in the first case when submitting a transaction is:
The hope is that most of the time, the block hashes I'm told about in the I wonder whether Another thought/question is: |
This issue has been mentioned on Polkadot Forum. There might be relevant details there: https://forum.polkadot.network/t/new-json-rpc-api-mega-q-a/3048/16 |
Problem Statement
Currently, the only way to send a transaction is through
transaction_unstable_submitAndWatch
. This method undertakes several tasks:Despite its comprehensive functionalities, a significant challenge arises due to its interactions with another function:
chaihead_unstable_follow
. This function, belonging to a different group, provides crucial information about the latest finalized block, which is indispensable for creating valid transactions.However, the inherent separation of these function groups and the lack of synchronization mechanisms pose risks:
Lack of Synchronization: If the
transaction
function lags behind thechainhead
, it could result in users being unable to send transactions altogether.Delayed Events: Events from the
transaction
function might be delayed or misaligned with the actual block status, rendering them ineffective for many applications. In such cases, users are forced to fetch block bodies manually and verify transaction presence, adding unnecessary complexity and duplication of efforts.In essence, while the
chainhead
group of functions is properly isolated from other functionalities, the same can't be said for thetransaction
group. Its dependencies on thechainhead
group bring up synchronization and information consistency concerns, which are pivotal for seamless transaction handling.Proposed Solutions and Concerns
1. Tight Coupling of Function Groups
transaction
group of functions is intrinsically linked to thechainhead
group. Hence, iftransaction
is available, so ischainhead
. This means thattransaction
would internally usechainhead
.2. Decoupling
transaction
fromchainhead
transaction
group would be broadcasting a transaction. This would shift validation and block body transaction tracking responsibilities to the client.chainhead
.3. Merging Function Groups
transaction
andchainhead
) into a single group, indicating their close interdependency.4. Superset Approach with
transaction
transaction
group of functions to encompass the responsibilities of thechainhead
group, effectively makingtransaction
a supergroup. Same solution as before, but leavingchainhead
untouched.I understand that these solutions aren't exhaustive and hope they provide insight into the possible ways forward. As a spec consumer, I find it crucial not only to highlight issues but also to offer potential resolutions. Eager to hear your insights on this.
cc: @tomaka
The text was updated successfully, but these errors were encountered: