-
Notifications
You must be signed in to change notification settings - Fork 37.8k
Add option to return non-segwit serialization via rpc #9194
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
Conversation
I also think this is a PR worthy of backport. |
Concept ACK, and I also think it would be worth considering for backport. |
Sigh, please no extra boolean arguments everywhere :(
|
@sipa Version argument? I'm willing to put in more work if there are better ideas. |
I don't see a use case to exclude only segwit signatures. Instead, it should strip all signatures, whether segwit or otherwise... (Also note this cannot affect users today, since segwit is not active today...) |
Turn the existing boolean argument into something else instead? true/false/stripped |
@luke-jr (may be misunderstanding you) older libraries/nodes expect older serialization, not witness serialization minus signatures? |
@luke-jr For compatibility reasons, I think that's a bad idea. scriptSigs
aren't strippable in any useful way.
@instagibbs What about a command-line argument to say whether RPC clients
support witnesses?
|
@instagibbs "Older serialization" is what you get when you strip signatures... And if they don't care about the signatures, then they don't care about any of the signatures. @sipa scriptSigs are no more or less useful to strip than segwit signatures. |
@luke-jr They are, they determine the txid. You can't strip scriptSigs for
any clients that expect to be able to compute the txid. Or expect to be
able to see the signatures for whatever other purpose, but don't know about
segwit.
|
Of course they are, because they are included in the txid calculation. I understand there's a user who is complaining, but I thought our view on this issue was that people just shouldn't upgrade their software until their rpc clients, zmq clients, REST clients etc were ready for segwit serialization. I haven't looked but I assume there are a lot of places in the code where this issue (of not knowing whether the consumer wants witnesses or not) would come up? I suppose we could try to do something like what @sipa suggests: a command line flag indicating the serialization to use (with/without witness) for all downstream consumers; it just seems tedious to get right. Might it not be better to just add a python script to contrib that takes a witness-serialized tx and returns a serialization without witness? I guess that would still require downstream library changes, so maybe that doesn't help. |
@sipa If they want the txids, they should be using the verbose mode in the first place, no? And if they actually need the signatures, they should need the segwit signatures as well... |
@sdaftuar in the interest of doing a command line level argument I'm going to audit how many RPC points would need to know about a flag. This exercise also may come in handy when it comes to switching over wallet functionality to segwit by default, which I'm imagining will be a similar mechanism. I also think that any time we have to change serialization in the future, we can ratchet whatever argument we have, and deprecate older versions if we can't trivially support them. |
@luke-jr Yes, in an ideal world everybody would use everything the way it
is designed. But in an ideal world, we'd also have segwit from the start,
and we'd never have any compatibility issue at all.
Stripping scriptSigs will break software.
|
I agree that adding another boolean for legacy purposes to the rpc api was suboptimal, so I have added a command line argument at startup to offer the same functionality called I can squash if this is deemed superior. |
273f1c2
to
165dd28
Compare
@@ -116,9 +116,9 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) | |||
return str; | |||
} | |||
|
|||
string EncodeHexTx(const CTransaction& tx) | |||
string EncodeHexTx(const CTransaction& tx, const bool fNonWitnessTx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps a serialize flag directly here is more appropriate and would effortlessly extend if we have additional serialization flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think thats a good idea-- and consistent with how things are done for p2p.
165dd28
to
dd906e2
Compare
676b293
to
0d757f0
Compare
Updated EncodeHexTx to take serialization flag directly, gettransaction["hex"] is now affected, and added more testing. |
As mentioned before and on IRC, I think if we're adding a command line argument to change the serialization for RPC calls, then for consistency's sake we ought to do the same for REST and ZMQ. Looks to me like just a couple additional call sites would be affected. |
071f146
to
742f1ac
Compare
updated as per @sdaftuar's reasonable request |
@@ -228,7 +228,7 @@ static bool rest_block(HTTPRequest* req, | |||
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); | |||
} | |||
|
|||
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); | |||
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0) ? SERIALIZE_TRANSACTION_NO_WITNESS : 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you extract out this conditional expression into a utility function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
utACK ebe6c30 |
utACK ebe6c30a2763a281425de35fd7b2f5dc87f48199 |
assert(self.nodes[2].getrawtransaction(segwit_tx_list[i]) != self.nodes[0].getrawtransaction(segwit_tx_list[i])) | ||
assert(self.nodes[1].getrawtransaction(segwit_tx_list[i], 0) == self.nodes[2].getrawtransaction(segwit_tx_list[i])) | ||
assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) != self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) | ||
assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps the test should explicitly test the correctness of the serializations, rather than just comparing output against each other? (Maybe just the node0/legacy-serialization case, since I presume something would break if the rpcserializationversion=1
handling were busted.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI this did the trick for me:
diff --git a/qa/rpc-tests/segwit.py b/qa/rpc-tests/segwit.py
index a618aec..e8a5512 100755
--- a/qa/rpc-tests/segwit.py
+++ b/qa/rpc-tests/segwit.py
@@ -219,10 +219,13 @@ class SegWitTest(BitcoinTestFramework):
assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False))
assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False))
for i in range(len(segwit_tx_list)):
+ from test_framework.mininode import FromHex
+ tx = FromHex(CTransaction(), self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
assert(self.nodes[2].getrawtransaction(segwit_tx_list[i]) != self.nodes[0].getrawtransaction(segwit_tx_list[i]))
assert(self.nodes[1].getrawtransaction(segwit_tx_list[i], 0) == self.nodes[2].getrawtransaction(segwit_tx_list[i]))
assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) != self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
+ assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness()))
print("Verify witness txs without witness data are invalid after the fork")
self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, included!
"no objection" utACK ebe6c30a2763a281425de35fd7b2f5dc87f48199 It's good that the RPC handling is tested with the segwit.py test; it'd be nice to update the zmq and rest python tests as well, but I think that can be done later. |
ebe6c30
to
ad5c4c9
Compare
Note: Needs release notes for 0.13.2 after merge. |
Needs rebase. |
ad5c4c9
to
412bab2
Compare
rebased |
ACK (however I did not test rest/ZMQ). |
@@ -380,6 +380,7 @@ std::string HelpMessage(HelpMessageMode mode) | |||
strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort())); | |||
strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy")); | |||
strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE)); | |||
strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(>0) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should say (1)
specifically, and not just (>0)
. If a value is passed that the node doesn't understand, it should complain, because it means the user is asking to serialize in a way it does not know about.
412bab2 Adapt ZMQ/rest serialization to take rpcserialversion arg (instagibbs) bc7ff8d Add option to return non-segwit serialization via rpc (Gregory Sanders)
Github-Pull: bitcoin#9194 Rebased-From: 835c75acaac004c3315395dcd7d1f193dfb9e5da
Github-Pull: bitcoin#9194 Rebased-From: ad5c4c93cae53a2a6f74880ca11b4d788677a378
… rpc 412bab2 Adapt ZMQ/rest serialization to take rpcserialversion arg (instagibbs) bc7ff8d Add option to return non-segwit serialization via rpc (Gregory Sanders)
Libraries may not be upgraded in time to handle the new serialization when segwit blocks and transactions come into the mainchain. This flag would allow people to use the RPC interface uninterrupted and intentionally upgrade as needed.
It's affecting users today.
update: I have added a command line flag instead. See below.