Skip to content

Commit 707d58f

Browse files
committed
Add generate block command
1 parent bde02d7 commit 707d58f

File tree

3 files changed

+134
-1
lines changed

3 files changed

+134
-1
lines changed

Diff for: client/src/client.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use serde_json;
2222
use crate::bitcoin::hashes::hex::{FromHex, ToHex};
2323
use crate::bitcoin::secp256k1::ecdsa::Signature;
2424
use crate::bitcoin::{
25-
Address, Amount, Block, BlockHeader, OutPoint, PrivateKey, PublicKey, Script, Transaction,
25+
Address, Amount, Block, BlockHeader, OutPoint, PrivateKey, PublicKey, Script, Transaction, Txid,
2626
};
2727
use log::Level::{Debug, Trace, Warn};
2828

@@ -186,6 +186,13 @@ impl RawTx for String {
186186
}
187187
}
188188

189+
/// The different authentication methods for the client.
190+
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
191+
pub enum MineableTx {
192+
RawTx(Transaction),
193+
Txid(Txid),
194+
}
195+
189196
/// The different authentication methods for the client.
190197
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
191198
pub enum Auth {
@@ -866,6 +873,23 @@ pub trait RpcApi: Sized {
866873
self.call("generate", &[block_num.into(), opt_into_json(maxtries)?])
867874
}
868875

876+
/// Mine a set of ordered transactions to a specified address
877+
/// and return the block hash.
878+
fn generate_block(
879+
&self,
880+
address: &Address,
881+
txs: &[MineableTx],
882+
) -> Result<json::GenerateBlockResult> {
883+
let tx_strs: Vec<_> = txs
884+
.iter()
885+
.map(|t| match t.to_owned() {
886+
MineableTx::RawTx(tx) => tx.raw_hex(),
887+
MineableTx::Txid(txid) => txid.to_hex(),
888+
})
889+
.collect();
890+
self.call("generateblock", &[address.to_string().into(), tx_strs.into()])
891+
}
892+
869893
/// Mark a block as invalid by `block_hash`
870894
fn invalidate_block(&self, block_hash: &bitcoin::BlockHash) -> Result<()> {
871895
self.call("invalidateblock", &[into_json(block_hash)?])

Diff for: integration_test/src/main.rs

+102
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ fn main() {
140140
test_generate(&cl);
141141
test_get_balance_generate_to_address(&cl);
142142
test_get_balances_generate_to_address(&cl);
143+
test_generate_block_raw_tx(&cl);
144+
test_generate_block_txid(&cl);
143145
test_get_best_block_hash(&cl);
144146
test_get_block_count(&cl);
145147
test_get_block_hash(&cl);
@@ -277,6 +279,106 @@ fn test_get_balances_generate_to_address(cl: &Client) {
277279
}
278280
}
279281

282+
fn test_generate_block_raw_tx(cl: &Client) {
283+
let sk = PrivateKey {
284+
network: Network::Regtest,
285+
inner: secp256k1::SecretKey::new(&mut secp256k1::rand::thread_rng()),
286+
compressed: true,
287+
};
288+
let addr = Address::p2wpkh(&sk.public_key(&SECP), Network::Regtest).unwrap();
289+
290+
let options = json::ListUnspentQueryOptions {
291+
minimum_amount: Some(btc(2)),
292+
..Default::default()
293+
};
294+
let unspent = cl.list_unspent(Some(6), None, None, None, Some(options)).unwrap();
295+
let unspent = unspent.into_iter().nth(0).unwrap();
296+
297+
let tx = Transaction {
298+
version: 1,
299+
lock_time: PackedLockTime::ZERO,
300+
input: vec![TxIn {
301+
previous_output: OutPoint {
302+
txid: unspent.txid,
303+
vout: unspent.vout,
304+
},
305+
sequence: Sequence::MAX,
306+
script_sig: Script::new(),
307+
witness: Witness::new(),
308+
}],
309+
output: vec![TxOut {
310+
value: (unspent.amount - *FEE).to_sat(),
311+
script_pubkey: addr.script_pubkey(),
312+
}],
313+
};
314+
315+
let input = json::SignRawTransactionInput {
316+
txid: unspent.txid,
317+
vout: unspent.vout,
318+
script_pub_key: unspent.script_pub_key,
319+
redeem_script: None,
320+
amount: Some(unspent.amount),
321+
};
322+
let res = cl.sign_raw_transaction_with_wallet(&tx, Some(&[input]), None).unwrap();
323+
assert!(res.complete);
324+
325+
let raw_tx = bitcoincore_rpc::MineableTx::RawTx(res.transaction().unwrap());
326+
let result = cl.generate_block(&cl.get_new_address(None, None).unwrap(), &[raw_tx]).unwrap();
327+
let tip = cl.get_best_block_hash().unwrap();
328+
assert_eq!(result.hash, tip);
329+
}
330+
331+
fn test_generate_block_txid(cl: &Client) {
332+
let sk = PrivateKey {
333+
network: Network::Regtest,
334+
inner: secp256k1::SecretKey::new(&mut secp256k1::rand::thread_rng()),
335+
compressed: true,
336+
};
337+
let addr = Address::p2wpkh(&sk.public_key(&SECP), Network::Regtest).unwrap();
338+
339+
let options = json::ListUnspentQueryOptions {
340+
minimum_amount: Some(btc(2)),
341+
..Default::default()
342+
};
343+
let unspent = cl.list_unspent(Some(6), None, None, None, Some(options)).unwrap();
344+
let unspent = unspent.into_iter().nth(0).unwrap();
345+
346+
let tx = Transaction {
347+
version: 1,
348+
lock_time: PackedLockTime::ZERO,
349+
input: vec![TxIn {
350+
previous_output: OutPoint {
351+
txid: unspent.txid,
352+
vout: unspent.vout,
353+
},
354+
sequence: Sequence::MAX,
355+
script_sig: Script::new(),
356+
witness: Witness::new(),
357+
}],
358+
output: vec![TxOut {
359+
value: (unspent.amount - *FEE).to_sat(),
360+
script_pubkey: addr.script_pubkey(),
361+
}],
362+
};
363+
364+
let input = json::SignRawTransactionInput {
365+
txid: unspent.txid,
366+
vout: unspent.vout,
367+
script_pub_key: unspent.script_pub_key,
368+
redeem_script: None,
369+
amount: Some(unspent.amount),
370+
};
371+
let res = cl.sign_raw_transaction_with_wallet(&tx, Some(&[input]), None).unwrap();
372+
assert!(res.complete);
373+
374+
let tx = res.transaction().unwrap();
375+
let txid = bitcoincore_rpc::MineableTx::Txid(tx.txid());
376+
cl.send_raw_transaction(&tx).unwrap();
377+
let result = cl.generate_block(&cl.get_new_address(None, None).unwrap(), &[txid]).unwrap();
378+
let tip = cl.get_best_block_hash().unwrap();
379+
assert_eq!(result.hash, tip);
380+
}
381+
280382
fn test_get_best_block_hash(cl: &Client) {
281383
let _ = cl.get_best_block_hash().unwrap();
282384
}

Diff for: json/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,13 @@ pub struct GetAddressInfoResult {
988988
pub label: Option<String>,
989989
}
990990

991+
/// Models the result of "generateblock"
992+
#[derive(Clone, Debug, Deserialize, Serialize)]
993+
pub struct GenerateBlockResult {
994+
/// Hash of the block generated
995+
pub hash: bitcoin::BlockHash,
996+
}
997+
991998
/// Models the result of "getblockchaininfo"
992999
#[derive(Clone, Debug, Deserialize, Serialize)]
9931000
pub struct GetBlockchainInfoResult {

0 commit comments

Comments
 (0)