Skip to content

Commit 9bcbc9d

Browse files
committed
Implement and test handle_blockchain_transaction_get.
1 parent 23d7d2f commit 9bcbc9d

2 files changed

Lines changed: 113 additions & 7 deletions

File tree

src/protocols/protocol_electrum.cpp

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,40 @@ void protocol_electrum::handle_blockchain_transaction_broadcast(const code& ec,
447447
}
448448

449449
void protocol_electrum::handle_blockchain_transaction_get(const code& ec,
450-
rpc_interface::blockchain_transaction_get, const std::string& ,
451-
bool ) NOEXCEPT
450+
rpc_interface::blockchain_transaction_get, const std::string& tx_hash,
451+
bool verbose) NOEXCEPT
452452
{
453-
if (stopped(ec)) return;
454-
send_code(error::not_implemented);
453+
if (stopped(ec))
454+
return;
455+
456+
// Changed in version 1.2: verbose argument added.
457+
// Changed in version 1.1: ignored argument height removed.
458+
459+
hash_digest hash{};
460+
if (!decode_hash(hash, tx_hash))
461+
{
462+
send_code(error::invalid_argument);
463+
return;
464+
}
465+
466+
const auto& query = archive();
467+
const auto tx = query.get_transaction(query.to_tx(hash), true);
468+
if (!tx)
469+
{
470+
send_code(error::not_found);
471+
return;
472+
}
473+
474+
const auto size = tx->serialized_size(true);
475+
if (verbose)
476+
{
477+
// Verbose means whatever bitcoind returns for getrawtransaction, lolz.
478+
send_result(value_from(bitcoind(*tx)), two * size, BIND(complete, _1));
479+
}
480+
else
481+
{
482+
send_result(to_hex(*tx, size, true), two * size, BIND(complete, _1));
483+
}
455484
}
456485

457486
void protocol_electrum::handle_blockchain_transaction_get_merkle(const code& ec,
@@ -486,7 +515,7 @@ void protocol_electrum::handle_server_banner(const code& ec,
486515
if (stopped(ec))
487516
return;
488517

489-
send_result({ options().banner_message }, 42, BIND(complete, _1));
518+
send_result(options().banner_message, 42, BIND(complete, _1));
490519
}
491520

492521
void protocol_electrum::handle_server_donation_address(const code& ec,
@@ -495,7 +524,7 @@ void protocol_electrum::handle_server_donation_address(const code& ec,
495524
if (stopped(ec))
496525
return;
497526

498-
send_result({ options().donation_address }, 42, BIND(complete, _1));
527+
send_result(options().donation_address, 42, BIND(complete, _1));
499528
}
500529

501530
void protocol_electrum::handle_server_features(const code& ec,
@@ -520,7 +549,7 @@ void protocol_electrum::handle_server_ping(const code& ec,
520549
return;
521550

522551
// Any receive, including ping, resets the base channel inactivity timer.
523-
send_result({ null_t{} }, 42, BIND(complete, _1));
552+
send_result(null_t{}, 42, BIND(complete, _1));
524553
}
525554

526555
// Handlers (mempool).

test/protocols/electrum/electrum_transactions.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ BOOST_FIXTURE_TEST_SUITE(electrum_tests, electrum_setup_fixture)
2626
// blockchain.transaction.broadcast
2727

2828
using namespace system;
29+
static const code not_found{ server::error::not_found };
30+
static const code not_implemented{ server::error::not_implemented };
2931
static const code invalid_argument{ server::error::invalid_argument };
3032
static const code unconfirmable_transaction{ server::error::unconfirmable_transaction };
3133

@@ -63,4 +65,79 @@ BOOST_AUTO_TEST_CASE(electrum__blockchain_transaction_broadcast__genesis_coinbas
6365
BOOST_CHECK_EQUAL(response.at("error").as_object().at("code").as_int64(), unconfirmable_transaction.value());
6466
}
6567

68+
// blockchain.transaction.get
69+
70+
BOOST_AUTO_TEST_CASE(electrum__blockchain_transaction_get__empty_hash__invalid_argument)
71+
{
72+
BOOST_CHECK(handshake());
73+
74+
const auto response = get(R"({"id":77,"method":"blockchain.transaction.get","params":["",false]})" "\n");
75+
BOOST_CHECK_EQUAL(response.at("error").as_object().at("code").as_int64(), invalid_argument.value());
76+
}
77+
78+
BOOST_AUTO_TEST_CASE(electrum__blockchain_transaction_get__invalid_hash__invalid_argument)
79+
{
80+
BOOST_CHECK(handshake());
81+
82+
const auto response = get(R"({"id":78,"method":"blockchain.transaction.get","params":["deadbeef",false]})" "\n");
83+
BOOST_CHECK_EQUAL(response.at("error").as_object().at("code").as_int64(), invalid_argument.value());
84+
}
85+
86+
BOOST_AUTO_TEST_CASE(electrum__blockchain_transaction_get__nonexistent_tx__not_found)
87+
{
88+
BOOST_CHECK(handshake());
89+
90+
const auto bogus = "0000000000000000000000000000000000000000000000000000000000000042";
91+
const auto request = R"({"id":79,"method":"blockchain.transaction.get","params":["%1%",false]})" "\n";
92+
const auto response = get((boost::format(request) % bogus).str());
93+
BOOST_CHECK_EQUAL(response.at("error").as_object().at("code").as_int64(), not_found.value());
94+
}
95+
96+
BOOST_AUTO_TEST_CASE(electrum__blockchain_transaction_get__missing_param__dropped)
97+
{
98+
BOOST_CHECK(handshake());
99+
100+
const auto& coinbase = *genesis.transactions_ptr()->front();
101+
const auto tx_hash = encode_hash(coinbase.hash(false));
102+
const auto request = R"({"id":80,"method":"blockchain.transaction.get","params":["%1%"]})" "\n";
103+
const auto response = get((boost::format(request) % tx_hash).str());
104+
BOOST_CHECK(response.at("dropped").as_bool());
105+
}
106+
107+
BOOST_AUTO_TEST_CASE(electrum__blockchain_transaction_get__extra_param__dropped)
108+
{
109+
BOOST_CHECK(handshake());
110+
111+
const auto& coinbase = *genesis.transactions_ptr()->front();
112+
const auto tx_hash = encode_hash(coinbase.hash(false));
113+
const auto request = R"({"id":81,"method":"blockchain.transaction.get","params":["%1%",false,"extra"]})" "\n";
114+
const auto response = get((boost::format(request) % tx_hash).str());
115+
BOOST_CHECK(response.at("dropped").as_bool());
116+
}
117+
118+
BOOST_AUTO_TEST_CASE(electrum__blockchain_transaction_get__genesis_coinbase_verbose_false__expected)
119+
{
120+
BOOST_CHECK(handshake());
121+
122+
const auto& coinbase = *genesis.transactions_ptr()->front();
123+
const auto tx_hash = encode_hash(coinbase.hash(false));
124+
const auto request = R"({"id":82,"method":"blockchain.transaction.get","params":["%1%",false]})" "\n";
125+
const auto response = get((boost::format(request) % tx_hash).str());
126+
BOOST_CHECK_EQUAL(response.at("result").as_string(), encode_base16(coinbase.to_data(true)));
127+
}
128+
129+
BOOST_AUTO_TEST_CASE(electrum__blockchain_transaction_get__genesis_coinbase_verbose_true__expected)
130+
{
131+
BOOST_CHECK(handshake());
132+
133+
const auto& coinbase = *genesis.transactions_ptr()->front();
134+
const auto tx_hash = encode_hash(coinbase.hash(false));
135+
const auto request = R"({"id":83,"method":"blockchain.transaction.get","params":["%1%",true]})" "\n";
136+
const auto response = get((boost::format(request) % tx_hash).str());
137+
BOOST_CHECK_EQUAL(response.at("result").as_object(), value_from(bitcoind(coinbase)));
138+
}
139+
140+
// blockchain.transaction.get_merkle
141+
// blockchain.transaction.id_from_pos
142+
66143
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)