While going over Decred’s implementation of the Construction API to ensure we’re compliant, I noticed that on the docs, /construction/parse isn’t marked as being an online endpoint and I’d like to understand the rationale for that.
The issue is that currently in our implementation, /construction/parse is used to fetch the PublicKeyScripts (PkScripts) of the previous outputs that will be spent by a transaction, in order to fill the appropriate AccountIdentifier for a given debit operation. However, assuming /construction/parse will be called on an offline node, it would mean we can’t actually do that.
I’ve gone over the rosetta-bitcoin implementation and I see that it’s solving that issue by using a more complex structure for the unsigned transaction blob generated by /construction/preprocess: it piggybacks the pkscripts returned by /construction/metadata to the /construction/preprocess call, thus avoiding having to re-fetch it at the cost of encoding the final tx four times (wire encoding of the tx -> hex blob -> json encoding of the complex data structure -> hex encoding of the json data).
My current working proposal is to do the same process in our implementation, however before doing that I’d like to understand the rationale for having /construction/parse be an offline operation vs online.
Thanks for reaching out, @matheusd! This is a great question.
We use /construction/parse as an integrity check in some of our signing systems before attempting to sign a transaction (i.e. parsing an unsigned transaction) and before returning the signed transaction to our wallet for broadcast (i.e. parsing a signed transaction). If there is any discrepancy between the “intent” (what we provide to construction), the parsed unsigned transaction, and the parsed signed transaction, we abort + raise an error.
For security reasons, these signing systems are 100% offline (no traffic allowed outside of a predefined cluster of servers) and do not have the ability to retrieve any online info. While we could invoke /construction/parse before connecting to this signing system or after retrieving the result (to access the internet or some stateful service), we felt using an offline deployment presented an appealing set of checks/balances on our online deployment, made it more difficult for a malicious attacker to tamper with some set of addresses, and provided a deterministic audit trail of parsing info (parsing the same payloads will always yield the same result regardless of the state of some node).
I agree this can be a little burdensome but we felt like the additional benefits we got from an offline /construction/parse was well worth it. If its any consolation, rosetta-ethereum does away with the extra layer of hex encoding:
I am having a problem making parse an offline operation. I’ll either need to play the metadata games which I am trying to avoid. The only piece of information I don’t have is the value of inputs to the transaction.
I am wondering if my implementation would be considered out of spec if I simply omitted the values on transaction inputs when parse is called on an offline node. The outputs would be fully specified.
In short, Rosetta is whatever users of your implementation want it to be (we very much don’t want to be a gatekeeper here). If some users don’t have strict security requirements and keep all endpoints online, they should still be able to use your implementation.
That being said, not supporting offline construction would be considered “not adhering” to the spec in our view and it would fail our E2E testing (which puts your implementation in an offline environment when testing the Construction API).
Let me rephrase. Of course we want to support offline construction. I seems to me that offline construction can proceed just fine without the transaction input currency amounts. I was wondering if anything would break if we simply ommited those values when doing an offline parse.
If the user interacting with your implementation uses rosetta-sdk-go, it will fail construction because the rosetta-sdk-go construction logic checks that the intent provided during construction matches the result of /construction/parse before and after signing (this check looks at the amount of all operations when confirming).
Coinbase and rosetta-cli use rosetta-sdk-go exclusively, however, users that don’t perform these consistency checks (when using a different library or interacting directly with RPC) can proceed without issue!
Ahh that’s an interesting idea. In our rosetta-bitcoin implementation, all we can do to provide assurance is lookup the amounts for the UTXOs specified as inputs. This would definitely provide more assurance.
Yeah, we are always trying to come up with more ways to double-check out work. When moving crypto, you can never be too sure!