Tx proof (revised):

- refactoring: proof generation/checking code was moved from simplewallet.cpp to wallet2.cpp
- allow an arbitrary message to be signed together with txid
- introduce two types (outbound & inbound) of tx proofs; with the same syntax, inbound is selected when <address> belongs to this wallet, outbound otherwise. see GitHub thread for more discussion
- wallet RPC: added get_tx_key, check_tx_key, get_tx_proof, check_tx_proof
- wallet API: moved WalletManagerImpl::checkPayment to Wallet::checkTxKey, added Wallet::getTxProof/checkTxProof
- get_tx_key/check_tx_key: handle additional tx keys by concatenating them into a single string
This commit is contained in:
stoffu 2017-09-12 10:05:41 +09:00
parent dc6a8014bd
commit 998777ecd7
No known key found for this signature in database
GPG key ID: 41DAB8343A9EC012
13 changed files with 876 additions and 532 deletions

View file

@ -623,6 +623,8 @@ namespace tools
if (req.get_tx_key)
{
res.tx_key = epee::string_tools::pod_to_hex(ptx_vector.back().tx_key);
for (const crypto::secret_key& additional_tx_key : ptx_vector.back().additional_tx_keys)
res.tx_key += epee::string_tools::pod_to_hex(additional_tx_key);
}
res.fee = ptx_vector.back().fee;
@ -685,6 +687,8 @@ namespace tools
if (req.get_tx_keys)
{
res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
for (const crypto::secret_key& additional_tx_key : ptx.additional_tx_keys)
res.tx_key_list.back() += epee::string_tools::pod_to_hex(additional_tx_key);
}
// Compute amount leaving wallet in tx. By convention dests does not include change outputs
ptx_amount = 0;
@ -1396,6 +1400,163 @@ namespace tools
res.value = m_wallet->get_attribute(req.key);
return true;
}
bool wallet_rpc_server::on_get_tx_key(const wallet_rpc::COMMAND_RPC_GET_TX_KEY::request& req, wallet_rpc::COMMAND_RPC_GET_TX_KEY::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
crypto::hash txid;
if (!epee::string_tools::hex_to_pod(req.txid, txid))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID;
er.message = "TX ID has invalid format";
return false;
}
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
if (!m_wallet->get_tx_key(txid, tx_key, additional_tx_keys))
{
er.code = WALLET_RPC_ERROR_CODE_NO_TXKEY;
er.message = "No tx secret key is stored for this tx";
return false;
}
std::ostringstream oss;
oss << epee::string_tools::pod_to_hex(tx_key);
for (size_t i = 0; i < additional_tx_keys.size(); ++i)
oss << epee::string_tools::pod_to_hex(additional_tx_keys[i]);
res.tx_key = oss.str();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_check_tx_key(const wallet_rpc::COMMAND_RPC_CHECK_TX_KEY::request& req, wallet_rpc::COMMAND_RPC_CHECK_TX_KEY::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
crypto::hash txid;
if (!epee::string_tools::hex_to_pod(req.txid, txid))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID;
er.message = "TX ID has invalid format";
return false;
}
std::string tx_key_str = req.tx_key;
crypto::secret_key tx_key;
if (!epee::string_tools::hex_to_pod(tx_key_str.substr(0, 64), tx_key))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY;
er.message = "Tx key has invalid format";
return false;
}
tx_key_str = tx_key_str.substr(64);
std::vector<crypto::secret_key> additional_tx_keys;
while (!tx_key_str.empty())
{
additional_tx_keys.resize(additional_tx_keys.size() + 1);
if (!epee::string_tools::hex_to_pod(tx_key_str.substr(0, 64), additional_tx_keys.back()))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY;
er.message = "Tx key has invalid format";
return false;
}
tx_key_str = tx_key_str.substr(64);
}
cryptonote::address_parse_info info;
if(!get_account_address_from_str(info, m_wallet->testnet(), req.address))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "Invalid address";
return false;
}
try
{
m_wallet->check_tx_key(txid, tx_key, additional_tx_keys, info.address, res.received, res.in_pool, res.confirmations);
}
catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_tx_proof(const wallet_rpc::COMMAND_RPC_GET_TX_PROOF::request& req, wallet_rpc::COMMAND_RPC_GET_TX_PROOF::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
crypto::hash txid;
if (!epee::string_tools::hex_to_pod(req.txid, txid))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID;
er.message = "TX ID has invalid format";
return false;
}
cryptonote::address_parse_info info;
if(!get_account_address_from_str(info, m_wallet->testnet(), req.address))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "Invalid address";
return false;
}
try
{
res.signature = m_wallet->get_tx_proof(txid, info.address, info.is_subaddress, req.message, er.message);
if (res.signature.empty())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
return false;
}
}
catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_check_tx_proof(const wallet_rpc::COMMAND_RPC_CHECK_TX_PROOF::request& req, wallet_rpc::COMMAND_RPC_CHECK_TX_PROOF::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
crypto::hash txid;
if (!epee::string_tools::hex_to_pod(req.txid, txid))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID;
er.message = "TX ID has invalid format";
return false;
}
cryptonote::address_parse_info info;
if(!get_account_address_from_str(info, m_wallet->testnet(), req.address))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "Invalid address";
return false;
}
try
{
uint64_t received;
bool in_pool;
uint64_t confirmations;
res.good = m_wallet->check_tx_proof(txid, info.address, info.is_subaddress, req.message, req.signature, res.received, res.in_pool, res.confirmations);
}
catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = e.what();
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res, epee::json_rpc::error& er)
{