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

[RPC] Add utility getsignaturehash #11653

Closed
wants to merge 1 commit into from

Conversation

NicolasDorier
Copy link
Contributor

@NicolasDorier NicolasDorier commented Nov 10, 2017

Add an utility to get the signature hash in a generic way.
signrawtransaction can't create a signature for an arbitrary scriptCode, as it is using ProduceSignature internally. This make it impossible to create complex scripts without a library.

src/rpc/misc.cpp Outdated
if (!request.params[5].isNull()) {
RPCTypeCheckArgument(request.params[5], UniValue::VSTR);
static std::map<std::string, int> mapSigHashValues = {
{ std::string("ALL"), int(SIGHASH_ALL) },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This table is duplicated with signrawtransaction, which makes it harder to change later. Please factor it out.

@NicolasDorier
Copy link
Contributor Author

Just refactored.

self.setup_clean_chain = True

def run_test(self):
assert_equal("64e049981a10cf597406a175d7443c8499d308168915377637e3f706ce186137", self.nodes[0].getsignaturehash(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No trailing white space, please.

Copy link
Member

@promag promag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments.

Missing tests for all sighashtype values and missing test for sigversion = WITNESS_V0?

@@ -131,6 +131,25 @@ uint256 ParseHashV(const UniValue& v, std::string strName)
result.SetHex(strHex);
return result;
}

int ParseSigHash(std::string strHashType)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const std::string& hash_type

{ std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY) },
};
if (mapSigHashValues.count(strHashType))
nHashType = mapSigHashValues[strHashType];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid 2nd lookup by using map::find.

if (mapSigHashValues.count(strHashType))
nHashType = mapSigHashValues[strHashType];
else
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For getsignaturehash the parameter name is sighashtype.

from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, remove 2nd empty line.

# optional
assert_equal("64e049981a10cf597406a175d7443c8499d308168915377637e3f706ce186137", self.nodes[0].getsignaturehash(
# tx
"010000000243ec7a579f5561a42a7e9637ad4156672735a658be2752181801f723ba3316d200000000844730440220449a203d0062ea01022f565c94c4b62bf2cc9a05de20519bc18cded9e99aa5f702201a2b8361e2af179eb93e697d9fedd0bf1e036f0a5be39af4b1f791df803bdb6501210363e38e2e0e55cdebfb7e27d0cb53ded150c320564a4614c18738feb124c8efd21976a9141a5fdcb6201f7e4fd160f9dca81075bd8537526088acffffffff43ec7a579f5561a42a7e9637ad4156672735a658be2752181801f723ba3316d20100000085483045022100ff6e7edffa5e0758244af6af77edd14f1d80226d66f81ed58dba2def34778236022057d95177497758e467c194f0d897f175645d30e7ac2f9490247e13227ac4d2fc01210363e38e2e0e55cdebfb7e27d0cb53ded150c320564a4614c18738feb124c8efd21976a9141a5fdcb6201f7e4fd160f9dca81075bd8537526088acffffffff0100752b7d000000001976a9141a5fdcb6201f7e4fd160f9dca81075bd8537526088ac00000000",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declare tx only once, and at the same time these 2 asserts will be more readable.

0
))


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove 2nd empty line.

int ParseSigHash(std::string strHashType)
{
int nHashType = 0;
static std::map<std::string, int> mapSigHashValues = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should ANYONECANPAY|SINGLE be possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it's not.

src/rpc/misc.cpp Outdated
UniValue::VSTR, // amount
UniValue::VSTR, // sigVersion
UniValue::VNUM // inputIndex
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong indentation?

src/rpc/misc.cpp Outdated
false);

CMutableTransaction mtx;
if (!DecodeHexTx(mtx, request.params[0].get_str(), true))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, there are a couple of {} missing, as per developer notes.

src/rpc/misc.cpp Outdated
"\nCreate the hash to sign for the given input\n"

"\nArguments:\n"
"1. \"tx\" (string, required) The transaction hex string\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please align the descriptions.

src/rpc/misc.cpp Outdated
std::vector<unsigned char> scriptCodeData(ParseHexV(request.params[1], "scriptCode"));
CScript scriptCode(scriptCodeData.begin(), scriptCodeData.end());

auto amount = AmountFromValue(request.params[2].get_str());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New RPCs should use satoshis, especially for low-level stuff.

src/rpc/misc.cpp Outdated

"\nArguments:\n"
"1. \"tx\" (string, required) The transaction hex string\n"
"2. \"scriptcode\" (string, required) The scriptCode to sign\n"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't explain what it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the scriptCode is difficult to explain, it depends on OP_CODESEPARATOR and whether you are using Segwit/P2SH/Segwit-P2SH/Normal script. It will never fit in one line.

@luke-jr
Copy link
Member

luke-jr commented Nov 10, 2017

(Light concept NACK because utilities should be in libraries, not RPC.)

@promag
Copy link
Member

promag commented Nov 10, 2017

@luke-jr I understand that but there is no harm in having these utilities:

  • they don't block, just spend a thread handling the request;
  • make the source stronger by using core code and having test coverage;
  • always updated response, libraries can have bugs or be outdated.

That said, most *rawtransactions are also utilities, and they are supported.

@NicolasDorier
Copy link
Contributor Author

NicolasDorier commented Nov 11, 2017

@luke-jr When you start doing services which span multiple blockchain (cross chain swap), then library can't possibly know how to sign each and every of them. While if each expose getsignaturehash it becomes possible. I bumped into the need of that as I was trying to do a cross chain swap between bitcoin and elements.

@sipa
Copy link
Member

sipa commented Nov 11, 2017

@NicolasDorier I don't see how that is related. You need some code specific for each chain anyway, no?

@NicolasDorier
Copy link
Contributor Author

NicolasDorier commented Nov 11, 2017

@sipa, not really. By using using decoderawtransaction, decodescript, createrawtransaction and all of those utilities, I can create transaction on two chains even if their binary representation of a transaction is completely different.
Basically, this is one of the piece missing to have a generic code for all crypto forked from Bitcoin, which does not rely on a library knowing the details.

@sipa
Copy link
Member

sipa commented Nov 11, 2017

@NicolasDorier I don't understand, you can't just paste signature hashes into any other RPC, so it can't be a 'missing piece'. You still need to know what the chain's signatures look like (ECDSA, sighash flags, scripting system, ...) to use that information for anything. I expect that if not already, between any two interesting chains those things will differ significantly.

A more useful thing would be an RPC which you give an unsigned transaction, a key and/or an output being spent, possibly a scriptCode, and a sighash flag, and it gives you a piece of scriptSig/witness containing a valid signature for it. You'd still be responsible for combining it with other script elements. Even that isn't a missing piece IMHO, but it wouldn't need intricate knowledge of the digital signature system in your application.

@NicolasDorier
Copy link
Contributor Author

NicolasDorier commented Nov 11, 2017

@sipa there is indeed the creation of script that the library need. But the scripts are most likely similar accross all chains.
Good point for the ECDSA. I thought they were not different, but they are: Bitcoin Cash is using another sighash. I agree, having a RPC method gettransactionsignature where you pass the private key be more generic. Will work on another PR for this as well.

@NicolasDorier
Copy link
Contributor Author

I addressed the nits, I keep this open while working on an alternative gettransactionsignature which accept a private key as well and returns the signature.

luke-jr pushed a commit to bitcoinknots/bitcoin that referenced this pull request Nov 11, 2017
@NicolasDorier
Copy link
Contributor Author

NicolasDorier commented Nov 12, 2017

Alternative signinput: #11666

@NicolasDorier
Copy link
Contributor Author

supersede by #11666

@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants