diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml index bafbc25..aa783d6 100644 --- a/.github/workflows/rust.yaml +++ b/.github/workflows/rust.yaml @@ -178,6 +178,7 @@ jobs: matrix: feature: [ + "28_0", "27_1", "27_0", "26_2", diff --git a/client/src/client_sync/mod.rs b/client/src/client_sync/mod.rs index f24b2e4..4b59254 100644 --- a/client/src/client_sync/mod.rs +++ b/client/src/client_sync/mod.rs @@ -14,6 +14,7 @@ pub mod v24; pub mod v25; pub mod v26; pub mod v27; +pub mod v28; use std::fs::File; use std::io::{BufRead, BufReader}; diff --git a/client/src/client_sync/v28.rs b/client/src/client_sync/v28.rs new file mode 100644 index 0000000..dab6ff7 --- /dev/null +++ b/client/src/client_sync/v28.rs @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! A JSON-RPC client for testing against Bitcoin Core `v28`. +//! +//! We ignore option arguments unless they effect the shape of the returned JSON data. + +use bitcoin::address::{Address, NetworkChecked}; +use bitcoin::{Amount, Block, BlockHash, Txid}; + +use crate::client_sync::{handle_defaults, into_json}; +use crate::json::v28::*; + +crate::define_jsonrpc_minreq_client!("v28"); + +// == Blockchain == +crate::impl_client_v17__getblockchaininfo!(); +crate::impl_client_v17__getbestblockhash!(); +crate::impl_client_v17__getblock!(); +crate::impl_client_v17__gettxout!(); + +// == Control == +crate::impl_client_v17__stop!(); + +// == Generating == +crate::impl_client_v17__generatetoaddress!(); + +// == Network == +crate::impl_client_v17__getnetworkinfo!(); +crate::impl_client_check_expected_server_version!({ [280000] }); + +// == Rawtransactions == +crate::impl_client_v17__sendrawtransaction!(); + +// == Wallet == +crate::impl_client_v17__createwallet!(); +crate::impl_client_v22__unloadwallet!(); +crate::impl_client_v22__loadwallet!(); +crate::impl_client_v17__getbalance!(); +crate::impl_client_v19__getbalances!(); +crate::impl_client_v17__getnewaddress!(); +crate::impl_client_v17__sendtoaddress!(); +crate::impl_client_v17__gettransaction!(); + +pub use crate::client_sync::v23::AddressType; diff --git a/contrib/run_bitcoind.sh b/contrib/run_bitcoind.sh index 5d10b21..2501775 100755 --- a/contrib/run_bitcoind.sh +++ b/contrib/run_bitcoind.sh @@ -23,6 +23,7 @@ COMMAND - stop Kill all bitcoind nodes using 'pkill bitcoind'. KNOWN_VERSION + - v28 Bitcoin Core v28.0 - v27 Bitcoin Core v27.1 - v26 Bitcoin Core v26.2 - v25 Bitcoin Core v25.2 @@ -49,6 +50,7 @@ main() { case $cmd in all) + start "v28" # 28.0 start "v27" # 27.1 start "v26" # 26.2 start "v25" # 25.2 @@ -84,6 +86,11 @@ start() { local version="$1" case $version in + v28) + local version_number="28.0" + local version_id="280" + ;; + v27) local version_number="27.1" local version_id="271" diff --git a/integration_test/Cargo.toml b/integration_test/Cargo.toml index 4cebd5d..8f4ef5c 100644 --- a/integration_test/Cargo.toml +++ b/integration_test/Cargo.toml @@ -13,6 +13,7 @@ edition = "2021" [features] # Enable the same feature in `bitcoind` and the version feature here. # All minor releases (but only the latest patch release). +"28_0" = ["v28", "bitcoind/28_0"] "27_1" = ["v27", "bitcoind/27_1"] "27_0" = ["v27", "bitcoind/27_0"] "26_2" = ["v26", "bitcoind/26_2"] @@ -37,6 +38,7 @@ edition = "2021" "0_17_1" = ["v17", "bitcoind/0_17_1"] # Each minor version is tested with the same client. +"v28" = [] "v27" = [] "v26" = [] "v25" = [] diff --git a/integration_test/tests/v28_api.rs b/integration_test/tests/v28_api.rs new file mode 100644 index 0000000..40a9f75 --- /dev/null +++ b/integration_test/tests/v28_api.rs @@ -0,0 +1,57 @@ +//! Test the JSON-RPC API against `bitcoind v28.0`. + +#![cfg(feature = "v28")] + +use integration_test::*; + +// == Blockchain == +mod blockchain { + use super::*; + + impl_test_v17__getblockchaininfo!(); + impl_test_v17__getbestblockhash!(); + impl_test_v17__getblock_verbosity_0!(); + impl_test_v17__getblock_verbosity_1!(); +} + +// == Control == +mod control { + use super::*; + + impl_test_v17__stop!(); +} + +// == Generating == +mod generating { + use super::*; + + impl_test_v17__generatetoaddress!(); +} + +// == Network == +mod network { + use super::*; + + impl_test_v17__getnetworkinfo!(); +} + +// == Rawtransactions == +mod raw_transactions { + use super::*; + + impl_test_v17__sendrawtransaction!(); +} + +// == Wallet == +mod wallet { + use super::*; + + impl_test_v17__createwallet!(); + impl_test_v17__loadwallet!(); + + impl_test_v17__getnewaddress!(); + impl_test_v17__getbalance!(); + impl_test_v19__getbalances!(); + impl_test_v17__sendtoaddress!(); + impl_test_v17__gettransaction!(); +} diff --git a/json/src/lib.rs b/json/src/lib.rs index da9ff7d..93974df 100644 --- a/json/src/lib.rs +++ b/json/src/lib.rs @@ -19,6 +19,7 @@ pub mod v24; pub mod v25; pub mod v26; pub mod v27; +pub mod v28; // JSON types that model _all_ `bitcoind` versions. pub mod model; @@ -82,4 +83,3 @@ fn btc_per_kb(btc_per_kb: f64) -> Result, ParseAmountError> { Ok(rate) } - diff --git a/json/src/model/blockchain.rs b/json/src/model/blockchain.rs index a49b545..422531c 100644 --- a/json/src/model/blockchain.rs +++ b/json/src/model/blockchain.rs @@ -97,7 +97,7 @@ pub struct GetBlockchainInfo { /// Status of softforks in progress, maps softfork name -> [`Softfork`]. pub softforks: BTreeMap, /// Any network and blockchain warnings. - pub warnings: String, + pub warnings: Vec, } /// Status of softfork. diff --git a/json/src/model/network.rs b/json/src/model/network.rs index c29683d..77cdd99 100644 --- a/json/src/model/network.rs +++ b/json/src/model/network.rs @@ -36,7 +36,7 @@ pub struct GetNetworkInfo { /// List of local addresses. pub local_addresses: Vec, /// Any network and blockchain warnings. - pub warnings: String, + pub warnings: Vec, } /// Part of the result of the JSON-RPC method `getnetworkinfo` (information per network). diff --git a/json/src/v17/blockchain.rs b/json/src/v17/blockchain.rs index 91f6890..7c11c6e 100644 --- a/json/src/v17/blockchain.rs +++ b/json/src/v17/blockchain.rs @@ -346,7 +346,7 @@ impl GetBlockchainInfo { automatic_pruning: self.automatic_pruning, prune_target_size, softforks, - warnings: self.warnings, + warnings: vec![self.warnings], }) } } diff --git a/json/src/v17/mod.rs b/json/src/v17/mod.rs index 60e0778..f858929 100644 --- a/json/src/v17/mod.rs +++ b/json/src/v17/mod.rs @@ -182,8 +182,8 @@ pub use self::{ generating::{Generate, GenerateToAddress}, network::{ AddedNode, AddedNodeAddress, Banned, GetAddedNodeInfo, GetNetTotals, GetNetworkInfo, - GetNetworkInfoAddress, GetNetworkInfoNetwork, GetPeerInfo, ListBanned, PeerInfo, - UploadTarget, + GetNetworkInfoAddress, GetNetworkInfoError, GetNetworkInfoNetwork, GetPeerInfo, ListBanned, + PeerInfo, UploadTarget, }, raw_transactions::SendRawTransaction, wallet::{ diff --git a/json/src/v17/network.rs b/json/src/v17/network.rs index 33d7fc0..8e516a2 100644 --- a/json/src/v17/network.rs +++ b/json/src/v17/network.rs @@ -177,7 +177,7 @@ impl GetNetworkInfo { relay_fee, incremental_fee, local_addresses: self.local_addresses.into_iter().map(|a| a.into_model()).collect(), - warnings: self.warnings, + warnings: vec![self.warnings], }) } } diff --git a/json/src/v19/blockchain.rs b/json/src/v19/blockchain.rs index 9be010f..b48888f 100644 --- a/json/src/v19/blockchain.rs +++ b/json/src/v19/blockchain.rs @@ -171,7 +171,7 @@ impl GetBlockchainInfo { automatic_pruning: self.automatic_pruning, prune_target_size, softforks, - warnings: self.warnings, + warnings: vec![self.warnings], }) } } diff --git a/json/src/v19/mod.rs b/json/src/v19/mod.rs index 7b1db75..8cdbd98 100644 --- a/json/src/v19/mod.rs +++ b/json/src/v19/mod.rs @@ -160,8 +160,8 @@ mod wallet; #[doc(inline)] pub use self::{ blockchain::{ - Bip9SoftforkInfo, Bip9SoftforkStatistics, Bip9SoftforkStatus, GetBlockchainInfo, Softfork, - SoftforkType, + Bip9SoftforkInfo, Bip9SoftforkStatistics, Bip9SoftforkStatus, GetBlockchainInfo, + GetBlockchainInfoError, Softfork, SoftforkType, }, wallet::{GetBalances, GetBalancesMine, GetBalancesWatchOnly}, }; diff --git a/json/src/v28/blockchain.rs b/json/src/v28/blockchain.rs new file mode 100644 index 0000000..4c27f82 --- /dev/null +++ b/json/src/v28/blockchain.rs @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! The JSON-RPC API for Bitcoin Core v28.0 - blockchain. +//! +//! Types for methods found under the `== Blockchain ==` section of the API docs. + +use std::collections::BTreeMap; + +use bitcoin::{BlockHash, Network, Work}; +use serde::{Deserialize, Serialize}; + +use super::{GetBlockchainInfoError, Softfork}; +use crate::model; + +#[rustfmt::skip] // Keep public re-exports separate. + +/// Result of JSON-RPC method `getblockchaininfo`. +/// +/// Method call: `getblockchaininfo` +/// +/// > Returns an object containing various state info regarding blockchain processing. +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct GetBlockchainInfo { + /// Current network name as defined in BIP70 (main, test, signet, regtest). + pub chain: String, + /// The current number of blocks processed in the server. + pub blocks: i64, + /// The current number of headers we have validated. + pub headers: i64, + /// The hash of the currently best block. + #[serde(rename = "bestblockhash")] + pub best_block_hash: String, + /// The current difficulty. + pub difficulty: f64, + /// Median time for the current best block. + #[serde(rename = "mediantime")] + pub median_time: i64, + /// Estimate of verification progress (between 0 and 1). + #[serde(rename = "verificationprogress")] + pub verification_progress: f64, + /// Estimate of whether this node is in Initial Block Download (IBD) mode. + #[serde(rename = "initialblockdownload")] + pub initial_block_download: bool, + /// Total amount of work in active chain, in hexadecimal. + #[serde(rename = "chainwork")] + pub chain_work: String, + /// The estimated size of the block and undo files on disk. + pub size_on_disk: u64, + /// If the blocks are subject to pruning. + pub pruned: bool, + /// Lowest-height complete block stored (only present if pruning is enabled). + #[serde(rename = "pruneheight")] + pub prune_height: Option, + /// Whether automatic pruning is enabled (only present if pruning is enabled). + pub automatic_pruning: Option, + /// The target size used by pruning (only present if automatic pruning is enabled). + pub prune_target_size: Option, + /// Status of softforks in progress, maps softfork name -> [`Softfork`]. + #[serde(default)] + pub softforks: BTreeMap, + /// Any network and blockchain warnings. + pub warnings: Vec, +} + +impl GetBlockchainInfo { + /// Converts version specific type to a version in-specific, more strongly typed type. + pub fn into_model(self) -> Result { + use GetBlockchainInfoError as E; + + let chain = Network::from_core_arg(&self.chain).map_err(E::Chain)?; + let best_block_hash = + self.best_block_hash.parse::().map_err(E::BestBlockHash)?; + let chain_work = Work::from_unprefixed_hex(&self.chain_work).map_err(E::ChainWork)?; + let prune_height = + self.prune_height.map(|h| crate::to_u32(h, "prune_height")).transpose()?; + let prune_target_size = + self.prune_target_size.map(|h| crate::to_u32(h, "prune_target_size")).transpose()?; + let softforks = BTreeMap::new(); // TODO: Handle softforks stuff. + + Ok(model::GetBlockchainInfo { + chain, + blocks: crate::to_u32(self.blocks, "blocks")?, + headers: crate::to_u32(self.headers, "headers")?, + best_block_hash, + difficulty: self.difficulty, + median_time: crate::to_u32(self.median_time, "median_time")?, + verification_progress: self.verification_progress, + initial_block_download: self.initial_block_download, + chain_work, + size_on_disk: self.size_on_disk, + pruned: self.pruned, + prune_height, + automatic_pruning: self.automatic_pruning, + prune_target_size, + softforks, + warnings: self.warnings, + }) + } +} diff --git a/json/src/v28/mod.rs b/json/src/v28/mod.rs new file mode 100644 index 0000000..10101a6 --- /dev/null +++ b/json/src/v28/mod.rs @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Structs with standard types. +//! +//! These structs model the types returned by the JSON-RPC API and use stdlib types (or custom +//! types) and are specific to a specific to Bitcoin Core `v26`. +//! +//! **== Blockchain ==** +//! - [ ] `dumptxoutset "path"` +//! - [x] `getbestblockhash` +//! - [x] `getblock "blockhash" ( verbosity )` +//! - [x] `getblockchaininfo` +//! - [ ] `getblockcount` +//! - [ ] `getblockfilter "blockhash" ( "filtertype" )` +//! - [ ] `getblockfrompeer "blockhash" peer_id` +//! - [ ] `getblockhash height` +//! - [ ] `getblockheader "blockhash" ( verbose )` +//! - [ ] `getblockstats hash_or_height ( stats )` +//! - [ ] `getchainstates` +//! - [ ] `getchaintips` +//! - [ ] `getchaintxstats ( nblocks "blockhash" )` +//! - [ ] `getdeploymentinfo ( "blockhash" )` +//! - [ ] `getdifficulty` +//! - [ ] `getmempoolancestors "txid" ( verbose )` +//! - [ ] `getmempooldescendants "txid" ( verbose )` +//! - [ ] `getmempoolentry "txid"` +//! - [ ] `getmempoolinfo` +//! - [ ] `getrawmempool ( verbose mempool_sequence )` +//! - [ ] `gettxout "txid" n ( include_mempool )` +//! - [ ] `gettxoutproof ["txid",...] ( "blockhash" )` +//! - [ ] `gettxoutsetinfo ( "hash_type" hash_or_height use_index )` +//! - [ ] `gettxspendingprevout [{"txid":"hex","vout":n},...]` +//! - [ ] `importmempool "filepath" ( options )` +//! - [ ] `loadtxoutset "path"` +//! - [ ] `preciousblock "blockhash"` +//! - [ ] `pruneblockchain height` +//! - [ ] `savemempool` +//! - [ ] `scanblocks "action" ( [scanobjects,...] start_height stop_height "filtertype" options )` +//! - [ ] `scantxoutset "action" ( [scanobjects,...] )` +//! - [ ] `verifychain ( checklevel nblocks )` +//! - [ ] `verifytxoutproof "proof"` +//! +//! **== Control ==** +//! - [ ] `getmemoryinfo ( "mode" )` +//! - [ ] `getrpcinfo` +//! - [ ] `help ( "command" )` +//! - [ ] `logging ( ["include_category",...] ["exclude_category",...] )` +//! - [x] `stop` +//! - [ ] `uptime` +//! +//! **== Mining ==** +//! - [ ] `getblocktemplate {"mode":"str","capabilities":["str",...],"rules":["segwit","str",...],"longpollid":"str","data":"hex"}` +//! - [ ] `getmininginfo` +//! - [ ] `getnetworkhashps ( nblocks height )` +//! - [ ] `getprioritisedtransactions` +//! - [ ] `prioritisetransaction "txid" ( dummy ) fee_delta` +//! - [ ] `submitblock "hexdata" ( "dummy" )` +//! - [ ] `submitheader "hexdata"` +//! - [ ] `//!` +//! - [ ] `//! **== Network ==**` +//! - [ ] `addnode "node" "command" ( v2transport )` +//! - [ ] `clearbanned` +//! - [ ] `disconnectnode ( "address" nodeid )` +//! - [ ] `getaddednodeinfo ( "node" )` +//! - [ ] `getaddrmaninfo` +//! - [ ] `getconnectioncount` +//! - [ ] `getnettotals` +//! - [ ] `getnetworkinfo` +//! - [ ] `getnodeaddresses ( count "network" )` +//! - [ ] `getpeerinfo` +//! - [ ] `listbanned` +//! - [ ] `ping` +//! - [ ] `setban "subnet" "command" ( bantime absolute )` +//! - [ ] `setnetworkactive state` +//! +//! **== Rawtransactions ==** +//! - [ ] `analyzepsbt "psbt"` +//! - [ ] `combinepsbt ["psbt",...]` +//! - [ ] `combinerawtransaction ["hexstring",...]` +//! - [ ] `converttopsbt "hexstring" ( permitsigdata iswitness )` +//! - [ ] `createpsbt [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount,...},{"data":"hex"},...] ( locktime replaceable )` +//! - [ ] `createrawtransaction [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount,...},{"data":"hex"},...] ( locktime replaceable )` +//! - [ ] `decodepsbt "psbt"` +//! - [ ] `decoderawtransaction "hexstring" ( iswitness )` +//! - [ ] `decodescript "hexstring"` +//! - [ ] `descriptorprocesspsbt "psbt" ["",{"desc":"str","range":n or [n,n]},...] ( "sighashtype" bip32derivs finalize )` +//! - [ ] `finalizepsbt "psbt" ( extract )` +//! - [ ] `fundrawtransaction "hexstring" ( options iswitness )` +//! - [ ] `getrawtransaction "txid" ( verbosity "blockhash" )` +//! - [ ] `joinpsbts ["psbt",...]` +//! - [ ] `sendrawtransaction "hexstring" ( maxfeerate maxburnamount )` +//! - [ ] `signrawtransactionwithkey "hexstring" ["privatekey",...] ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","witnessScript":"hex","amount":amount},...] "sighashtype" )` +//! - [ ] `submitpackage ["rawtx",...] ( maxfeerate maxburnamount )` +//! - [ ] `testmempoolaccept ["rawtx",...] ( maxfeerate )` +//! - [ ] `utxoupdatepsbt "psbt" ( ["",{"desc":"str","range":n or [n,n]},...] )` +//! +//! **== Signer ==** +//! - [ ] `enumeratesigners` +//! +//! **== Util ==** +//! - [ ] `createmultisig nrequired ["key",...] ( "address_type" )` +//! - [ ] `deriveaddresses "descriptor" ( range )` +//! - [ ] `estimatesmartfee conf_target ( "estimate_mode" )` +//! - [ ] `getdescriptorinfo "descriptor"` +//! - [ ] `getindexinfo ( "index_name" )` +//! - [ ] `signmessagewithprivkey "privkey" "message"` +//! - [ ] `validateaddress "address"` +//! - [ ] `verifymessage "address" "signature" "message"` +//! +//! **== Wallet ==** +//! - [ ] `abandontransaction "txid"` +//! - [ ] `abortrescan` +//! - [ ] `addmultisigaddress nrequired ["key",...] ( "label" "address_type" )` +//! - [ ] `backupwallet "destination"` +//! - [ ] `bumpfee "txid" ( options )` +//! - [x] `createwallet "wallet_name" ( disable_private_keys blank "passphrase" avoid_reuse descriptors load_on_startup external_signer )` +//! - [ ] `createwalletdescriptor "type" ( {"internal":bool,"hdkey":"str",...} )` +//! - [ ] `dumpprivkey "address"` +//! - [ ] `dumpwallet "filename"` +//! - [ ] `encryptwallet "passphrase"` +//! - [ ] `getaddressesbylabel "label"` +//! - [ ] `getaddressinfo "address"` +//! - [x] `getbalance ( "dummy" minconf include_watchonly avoid_reuse )` +//! - [x] `getbalances` +//! - [ ] `gethdkeys ( {"active_only":bool,"private":bool,...} )` +//! - [x] `getnewaddress ( "label" "address_type" )` +//! - [ ] `getrawchangeaddress ( "address_type" )` +//! - [ ] `getreceivedbyaddress "address" ( minconf include_immature_coinbase )` +//! - [ ] `getreceivedbylabel "label" ( minconf include_immature_coinbase )` +//! - [x] `gettransaction "txid" ( include_watchonly verbose )` +//! - [ ] `getunconfirmedbalance` +//! - [ ] `getwalletinfo` +//! - [ ] `importaddress "address" ( "label" rescan p2sh )` +//! - [ ] `importdescriptors requests` +//! - [ ] `importmulti requests ( options )` +//! - [ ] `importprivkey "privkey" ( "label" rescan )` +//! - [ ] `importprunedfunds "rawtransaction" "txoutproof"` +//! - [ ] `importpubkey "pubkey" ( "label" rescan )` +//! - [ ] `importwallet "filename"` +//! - [ ] `keypoolrefill ( newsize )` +//! - [ ] `listaddressgroupings` +//! - [ ] `listdescriptors ( private )` +//! - [ ] `listlabels ( "purpose" )` +//! - [ ] `listlockunspent` +//! - [ ] `listreceivedbyaddress ( minconf include_empty include_watchonly "address_filter" include_immature_coinbase )` +//! - [ ] `listreceivedbylabel ( minconf include_empty include_watchonly include_immature_coinbase )` +//! - [ ] `listsinceblock ( "blockhash" target_confirmations include_watchonly include_removed include_change "label" )` +//! - [ ] `listtransactions ( "label" count skip include_watchonly )` +//! - [ ] `listunspent ( minconf maxconf ["address",...] include_unsafe query_options )` +//! - [ ] `listwalletdir` +//! - [ ] `listwallets` +//! - [x] `loadwallet "filename" ( load_on_startup )` +//! - [ ] `lockunspent unlock ( [{"txid":"hex","vout":n},...] persistent )` +//! - [ ] `migratewallet ( "wallet_name" "passphrase" )` +//! - [ ] `newkeypool` +//! - [ ] `psbtbumpfee "txid" ( options )` +//! - [ ] `removeprunedfunds "txid"` +//! - [ ] `rescanblockchain ( start_height stop_height )` +//! - [ ] `restorewallet "wallet_name" "backup_file" ( load_on_startup )` +//! - [ ] `send [{"address":amount,...},{"data":"hex"},...] ( conf_target "estimate_mode" fee_rate options )` +//! - [ ] `sendall ["address",{"address":amount,...},...] ( conf_target "estimate_mode" fee_rate options )` +//! - [ ] `sendmany ( "" ) {"address":amount,...} ( minconf "comment" ["address",...] replaceable conf_target "estimate_mode" fee_rate verbose )` +//! - [x] `sendtoaddress "address" amount ( "comment" "comment_to" subtractfeefromamount replaceable conf_target "estimate_mode" avoid_reuse fee_rate verbose )` +//! - [ ] `sethdseed ( newkeypool "seed" )` +//! - [ ] `setlabel "address" "label"` +//! - [ ] `settxfee amount` +//! - [ ] `setwalletflag "flag" ( value )` +//! - [ ] `signmessage "address" "message"` +//! - [ ] `signrawtransactionwithwallet "hexstring" ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","witnessScript":"hex","amount":amount},...] "sighashtype" )` +//! - [ ] `simulaterawtransaction ( ["rawtx",...] {"include_watchonly":bool,...} )` +//! - [ ] `unloadwallet ( "wallet_name" load_on_startup )` +//! - [ ] `upgradewallet ( version )` +//! - [ ] `walletcreatefundedpsbt ( [{"txid":"hex","vout":n,"sequence":n,"weight":n},...] ) [{"address":amount,...},{"data":"hex"},...] ( locktime options bip32derivs )` +//! - [ ] `walletdisplayaddress "address"` +//! - [ ] `walletlock` +//! - [ ] `walletpassphrase "passphrase" timeout` +//! - [ ] `walletpassphrasechange "oldpassphrase" "newpassphrase"` +//! - [ ] `walletprocesspsbt "psbt" ( sign "sighashtype" bip32derivs finalize )` +//! +//! **== Zmq ==** +//! - [ ] `getzmqnotifications` + +mod blockchain; +mod network; + +#[doc(inline)] +pub use self::blockchain::GetBlockchainInfo; +#[doc(inline)] +pub use self::network::GetNetworkInfo; +#[doc(inline)] +pub use crate::{ + v17::{ + GenerateToAddress, GetBalance, GetBestBlockHash, GetBlockVerbosityOne, + GetBlockVerbosityZero, GetNetworkInfoAddress, GetNetworkInfoError, GetNetworkInfoNetwork, + GetNewAddress, GetTransaction, GetTransactionDetail, GetTransactionDetailCategory, + GetTxOut, SendRawTransaction, + }, + v19::{ + Bip9SoftforkInfo, Bip9SoftforkStatistics, Bip9SoftforkStatus, GetBalances, GetBalancesMine, + GetBalancesWatchOnly, GetBlockchainInfoError, Softfork, SoftforkType, + }, + v22::{SendToAddress, UnloadWallet}, + v25::{CreateWallet, LoadWallet}, +}; diff --git a/json/src/v28/network.rs b/json/src/v28/network.rs new file mode 100644 index 0000000..f02d122 --- /dev/null +++ b/json/src/v28/network.rs @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! The JSON-RPC API for Bitcoin Core v28.0 - network. +//! +//! Types for methods found under the `== Network ==` section of the API docs. +use serde::{Deserialize, Serialize}; + +use super::{GetNetworkInfoAddress, GetNetworkInfoError, GetNetworkInfoNetwork}; +use crate::model; + +/// Result of the JSON-RPC method `getnetworkinfo`. +/// +/// > getnetworkinfo +/// +/// > Returns an object containing various state info regarding P2P networking. +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct GetNetworkInfo { + /// The server version. + pub version: usize, + /// The server subversion string. + pub subversion: String, + /// The protocol version. + #[serde(rename = "protocolversion")] + pub protocol_version: usize, + /// The services we offer to the network (hex string). + #[serde(rename = "localservices")] + pub local_services: String, + /// `true` if transaction relay is requested from peers. + #[serde(rename = "localrelay")] + pub local_relay: bool, + /// The time offset. + #[serde(rename = "timeoffset")] + pub time_offset: isize, + /// The total number of connections. + pub connections: usize, + /// Whether p2p networking is enabled. + #[serde(rename = "networkactive")] + pub network_active: bool, + /// Information per network. + pub networks: Vec, + /// Minimum relay fee rate for transactions in BTC/kB. + #[serde(rename = "relayfee")] + pub relay_fee: f64, + /// Minimum fee rate increment for mempool limiting or replacement in BTC/kB. + #[serde(rename = "incrementalfee")] + pub incremental_fee: f64, + /// List of local addresses. + #[serde(rename = "localaddresses")] + pub local_addresses: Vec, + /// Any network and blockchain warnings. + pub warnings: Vec, +} + +impl GetNetworkInfo { + /// Converts version specific type to a version in-specific, more strongly typed type. + pub fn into_model(self) -> Result { + use GetNetworkInfoError as E; + + let relay_fee = crate::btc_per_kb(self.relay_fee).map_err(E::RelayFee)?; + let incremental_fee = crate::btc_per_kb(self.incremental_fee).map_err(E::IncrementalFee)?; + + Ok(model::GetNetworkInfo { + version: self.version, + subversion: self.subversion, + protocol_version: self.protocol_version, + local_services: self.local_services, + local_relay: self.local_relay, + time_offset: self.time_offset, + connections: self.connections, + network_active: self.network_active, + networks: self.networks.into_iter().map(|n| n.into_model()).collect(), + relay_fee, + incremental_fee, + local_addresses: self.local_addresses.into_iter().map(|a| a.into_model()).collect(), + warnings: self.warnings, + }) + } +} diff --git a/json/src/v28/rpc-api.txt b/json/src/v28/rpc-api.txt new file mode 100644 index 0000000..4c3cad9 --- /dev/null +++ b/json/src/v28/rpc-api.txt @@ -0,0 +1,174 @@ +== Blockchain == +dumptxoutset "path" +getbestblockhash +getblock "blockhash" ( verbosity ) +getblockchaininfo +getblockcount +getblockfilter "blockhash" ( "filtertype" ) +getblockfrompeer "blockhash" peer_id +getblockhash height +getblockheader "blockhash" ( verbose ) +getblockstats hash_or_height ( stats ) +getchainstates +getchaintips +getchaintxstats ( nblocks "blockhash" ) +getdeploymentinfo ( "blockhash" ) +getdifficulty +getmempoolancestors "txid" ( verbose ) +getmempooldescendants "txid" ( verbose ) +getmempoolentry "txid" +getmempoolinfo +getrawmempool ( verbose mempool_sequence ) +gettxout "txid" n ( include_mempool ) +gettxoutproof ["txid",...] ( "blockhash" ) +gettxoutsetinfo ( "hash_type" hash_or_height use_index ) +gettxspendingprevout [{"txid":"hex","vout":n},...] +importmempool "filepath" ( options ) +loadtxoutset "path" +preciousblock "blockhash" +pruneblockchain height +savemempool +scanblocks "action" ( [scanobjects,...] start_height stop_height "filtertype" options ) +scantxoutset "action" ( [scanobjects,...] ) +verifychain ( checklevel nblocks ) +verifytxoutproof "proof" + +== Control == +getmemoryinfo ( "mode" ) +getrpcinfo +help ( "command" ) +logging ( ["include_category",...] ["exclude_category",...] ) +stop +uptime + +== Mining == +getblocktemplate {"mode":"str","capabilities":["str",...],"rules":["segwit","str",...],"longpollid":"str","data":"hex"} +getmininginfo +getnetworkhashps ( nblocks height ) +getprioritisedtransactions +prioritisetransaction "txid" ( dummy ) fee_delta +submitblock "hexdata" ( "dummy" ) +submitheader "hexdata" + +== Network == +addnode "node" "command" ( v2transport ) +clearbanned +disconnectnode ( "address" nodeid ) +getaddednodeinfo ( "node" ) +getaddrmaninfo +getconnectioncount +getnettotals +getnetworkinfo +getnodeaddresses ( count "network" ) +getpeerinfo +listbanned +ping +setban "subnet" "command" ( bantime absolute ) +setnetworkactive state + +== Rawtransactions == +analyzepsbt "psbt" +combinepsbt ["psbt",...] +combinerawtransaction ["hexstring",...] +converttopsbt "hexstring" ( permitsigdata iswitness ) +createpsbt [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount,...},{"data":"hex"},...] ( locktime replaceable ) +createrawtransaction [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount,...},{"data":"hex"},...] ( locktime replaceable ) +decodepsbt "psbt" +decoderawtransaction "hexstring" ( iswitness ) +decodescript "hexstring" +descriptorprocesspsbt "psbt" ["",{"desc":"str","range":n or [n,n]},...] ( "sighashtype" bip32derivs finalize ) +finalizepsbt "psbt" ( extract ) +fundrawtransaction "hexstring" ( options iswitness ) +getrawtransaction "txid" ( verbosity "blockhash" ) +joinpsbts ["psbt",...] +sendrawtransaction "hexstring" ( maxfeerate maxburnamount ) +signrawtransactionwithkey "hexstring" ["privatekey",...] ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","witnessScript":"hex","amount":amount},...] "sighashtype" ) +submitpackage ["rawtx",...] ( maxfeerate maxburnamount ) +testmempoolaccept ["rawtx",...] ( maxfeerate ) +utxoupdatepsbt "psbt" ( ["",{"desc":"str","range":n or [n,n]},...] ) + +== Signer == +enumeratesigners + +== Util == +createmultisig nrequired ["key",...] ( "address_type" ) +deriveaddresses "descriptor" ( range ) +estimatesmartfee conf_target ( "estimate_mode" ) +getdescriptorinfo "descriptor" +getindexinfo ( "index_name" ) +signmessagewithprivkey "privkey" "message" +validateaddress "address" +verifymessage "address" "signature" "message" + +== Wallet == +abandontransaction "txid" +abortrescan +addmultisigaddress nrequired ["key",...] ( "label" "address_type" ) +backupwallet "destination" +bumpfee "txid" ( options ) +createwallet "wallet_name" ( disable_private_keys blank "passphrase" avoid_reuse descriptors load_on_startup external_signer ) +createwalletdescriptor "type" ( {"internal":bool,"hdkey":"str",...} ) +dumpprivkey "address" +dumpwallet "filename" +encryptwallet "passphrase" +getaddressesbylabel "label" +getaddressinfo "address" +getbalance ( "dummy" minconf include_watchonly avoid_reuse ) +getbalances +gethdkeys ( {"active_only":bool,"private":bool,...} ) +getnewaddress ( "label" "address_type" ) +getrawchangeaddress ( "address_type" ) +getreceivedbyaddress "address" ( minconf include_immature_coinbase ) +getreceivedbylabel "label" ( minconf include_immature_coinbase ) +gettransaction "txid" ( include_watchonly verbose ) +getunconfirmedbalance +getwalletinfo +importaddress "address" ( "label" rescan p2sh ) +importdescriptors requests +importmulti requests ( options ) +importprivkey "privkey" ( "label" rescan ) +importprunedfunds "rawtransaction" "txoutproof" +importpubkey "pubkey" ( "label" rescan ) +importwallet "filename" +keypoolrefill ( newsize ) +listaddressgroupings +listdescriptors ( private ) +listlabels ( "purpose" ) +listlockunspent +listreceivedbyaddress ( minconf include_empty include_watchonly "address_filter" include_immature_coinbase ) +listreceivedbylabel ( minconf include_empty include_watchonly include_immature_coinbase ) +listsinceblock ( "blockhash" target_confirmations include_watchonly include_removed include_change "label" ) +listtransactions ( "label" count skip include_watchonly ) +listunspent ( minconf maxconf ["address",...] include_unsafe query_options ) +listwalletdir +listwallets +loadwallet "filename" ( load_on_startup ) +lockunspent unlock ( [{"txid":"hex","vout":n},...] persistent ) +migratewallet ( "wallet_name" "passphrase" ) +newkeypool +psbtbumpfee "txid" ( options ) +removeprunedfunds "txid" +rescanblockchain ( start_height stop_height ) +restorewallet "wallet_name" "backup_file" ( load_on_startup ) +send [{"address":amount,...},{"data":"hex"},...] ( conf_target "estimate_mode" fee_rate options ) +sendall ["address",{"address":amount,...},...] ( conf_target "estimate_mode" fee_rate options ) +sendmany ( "" ) {"address":amount,...} ( minconf "comment" ["address",...] replaceable conf_target "estimate_mode" fee_rate verbose ) +sendtoaddress "address" amount ( "comment" "comment_to" subtractfeefromamount replaceable conf_target "estimate_mode" avoid_reuse fee_rate verbose ) +sethdseed ( newkeypool "seed" ) +setlabel "address" "label" +settxfee amount +setwalletflag "flag" ( value ) +signmessage "address" "message" +signrawtransactionwithwallet "hexstring" ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","witnessScript":"hex","amount":amount},...] "sighashtype" ) +simulaterawtransaction ( ["rawtx",...] {"include_watchonly":bool,...} ) +unloadwallet ( "wallet_name" load_on_startup ) +upgradewallet ( version ) +walletcreatefundedpsbt ( [{"txid":"hex","vout":n,"sequence":n,"weight":n},...] ) [{"address":amount,...},{"data":"hex"},...] ( locktime options bip32derivs ) +walletdisplayaddress "address" +walletlock +walletpassphrase "passphrase" timeout +walletpassphrasechange "oldpassphrase" "newpassphrase" +walletprocesspsbt "psbt" ( sign "sighashtype" bip32derivs finalize ) + +== Zmq == +getzmqnotifications diff --git a/regtest/Cargo.toml b/regtest/Cargo.toml index d4a411c..1ad19d8 100644 --- a/regtest/Cargo.toml +++ b/regtest/Cargo.toml @@ -35,13 +35,14 @@ anyhow = "1.0.66" # Please note, in this crate the version features are mutally exclusive. # -# - `cargo test --all-features` is the same as `cargo test --features=v27_1` -# - `cargo test --no-default-features` uses `v27_1` also. +# - `cargo test --all-features` is the same as `cargo test --features=v28_0` +# - `cargo test --no-default-features` uses `v28_0` also. [features] # download is not supposed to be used directly only through selecting one of the version feature "download" = ["bitcoin_hashes", "flate2", "tar", "minreq", "zip"] # We support all minor releases (but only the latest patch release). +"28_0" = ["download", "27_1"] "27_1" = ["download", "27_0"] "27_0" = ["download", "26_2"] "26_2" = ["download", "26_1"] diff --git a/regtest/sha256/bitcoin-core-28.0-SHA256SUMS b/regtest/sha256/bitcoin-core-28.0-SHA256SUMS new file mode 100644 index 0000000..1b32774 --- /dev/null +++ b/regtest/sha256/bitcoin-core-28.0-SHA256SUMS @@ -0,0 +1,25 @@ +919a346c3fab1408734d0849069a2cecdac441f3f7f6a611ef442c4caa534f31 bitcoin-28.0-aarch64-linux-gnu-debug.tar.gz +7fa582d99a25c354d23e371a5848bd9e6a79702870f9cbbf1292b86e647d0f4e bitcoin-28.0-aarch64-linux-gnu.tar.gz +a7a7be3eb075ea6757455e4bc721a29c243884acddcdb503d6363458dbd3f2c3 bitcoin-28.0-arm-linux-gnueabihf-debug.tar.gz +e004b7910bedd6dd18b6c52b4eef398d55971da666487a82cd48708d2879727e bitcoin-28.0-arm-linux-gnueabihf.tar.gz +cb5935484998a74eda6b8caa699be844567b2942de9e723a875debbbc01a53c1 bitcoin-28.0-arm64-apple-darwin.zip +7d6d488f82c29284ce59f71b4d19d0850fb7c88f6ea8a0298ad44ab578c2d866 bitcoin-28.0-arm64-apple-darwin-unsigned.tar.gz +6f9e9751574689e02cd99f68285100f13f1e68c11cc226ab01c9f7885946f8b4 bitcoin-28.0-arm64-apple-darwin-unsigned.zip +c8108f30dfcc7ddffab33f5647d745414ef9d3298bfe67d243fe9b9cb4df4c12 bitcoin-28.0-arm64-apple-darwin.tar.gz +198516b630219b4a4032690e864e3e21dc2385d0e5905f98f02c1b1acf2525cd bitcoin-28.0-codesignatures-28.0.tar.gz +700ae2d1e204602eb07f2779a6e6669893bc96c0dca290593f80ff8e102ff37f bitcoin-28.0.tar.gz +76f2ebf0fdc7bf852d2cd991302a19b178d12521796715d63ed8bb7a5b479062 bitcoin-28.0-powerpc64-linux-gnu-debug.tar.gz +756df50d8f0c2a3d4111389a7be5f4849e0f5014dd5bfcbc37a8c3aaaa54907b bitcoin-28.0-powerpc64-linux-gnu.tar.gz +a868a41534b4db317cca8d070beddcfdf0e8435cf368bd2438027294e8e993d5 bitcoin-28.0-riscv64-linux-gnu-debug.tar.gz +6ee1a520b638132a16725020146abea045db418ce91c02493f02f541cd53062a bitcoin-28.0-riscv64-linux-gnu.tar.gz +04c39cec7ed4c56da11811b382db85e6c211d0e12eb6e5bdf2701eba9de292e7 bitcoin-28.0-x86_64-apple-darwin.zip +cfa72f45b9b6f08a80f5dfe4fba4e392b66e9a9972f7fbe66c4139fd0e0b83eb bitcoin-28.0-x86_64-apple-darwin-unsigned.tar.gz +0b0f583bc50fbd186bad00fc3b9c55036f566e4552e4cad5bb6292f8ebdabda4 bitcoin-28.0-x86_64-apple-darwin-unsigned.zip +77e931bbaaf47771a10c376230bf53223f5380864bad3568efc7f4d02e40a0f7 bitcoin-28.0-x86_64-apple-darwin.tar.gz +f19502b406ce1fc20f60b21705f0418f345fdf6a0118196af23563697a0505f4 bitcoin-28.0-x86_64-linux-gnu-debug.tar.gz +7fe294b02b25b51acb8e8e0a0eb5af6bbafa7cd0c5b0e5fcbb61263104a82fbc bitcoin-28.0-x86_64-linux-gnu.tar.gz +b59ddff8564413d433ce8bdac37ad65332e5e6b143573da08ff427be839d3b41 bitcoin-28.0-win64-setup.exe +8990def2e611323d4c7a8cf17187a138dca64f98fc0ecebda0a3e999dbdd083d bitcoin-28.0-win64-debug.zip +d8170c342ac049fab953f87841cbbba6c0e3f277703ddc29c678b6ab93dae966 bitcoin-28.0-win64-setup-unsigned.exe +8ec39e7bf66ea419ea79e5f1b7bee1b03a28b51ddd1daa6e167bff6abac0a5d2 bitcoin-28.0-win64-unsigned.tar.gz +85282f4ec1bcb0cfe8db0f195e8e0f6fb77cfbe89242a81fff2bc2e9292f7acf bitcoin-28.0-win64.zip diff --git a/regtest/src/client_versions.rs b/regtest/src/client_versions.rs index 82c40be..b17af3c 100644 --- a/regtest/src/client_versions.rs +++ b/regtest/src/client_versions.rs @@ -6,7 +6,11 @@ /// up to handle such oddity. /// -#[cfg(feature = "27_1")] +#[cfg(feature = "28_0")] +#[allow(unused_imports)] // Not all users need the json types. +pub use bitcoind_json_rpc_client::{client_sync::v28::{Client, AddressType}, json::v28 as json}; + +#[cfg(all(feature = "27_1", not(feature = "28_0")))] #[allow(unused_imports)] // Not all users need the json types. pub use bitcoind_json_rpc_client::{client_sync::v27::{Client, AddressType}, json::v27 as json}; @@ -91,6 +95,6 @@ pub use bitcoind_json_rpc_client::{client_sync::v18::{Client, AddressType}, json pub use bitcoind_json_rpc_client::{client_sync::v17::{Client, AddressType}, json::v17 as json}; // To make --no-default-features work we have to re-export a the types, use most recent version same as we do for all features. -#[cfg(all(not(feature = "27_1"), not(feature = "27_0"), not(feature = "26_2"), not(feature = "26_1"), not(feature = "26_0"), not(feature = "25_2"), not(feature = "25_1"), not(feature = "25_0"), not(feature = "24_2"),not(feature = "24_1"), not(feature = "24_0_1"), not(feature = "23_2"), not(feature = "23_1"), not(feature = "23_0"), not(feature = "22_1"), not(feature = "22_0"), not(feature = "0_21_2"), not(feature = "0_20_2"), not(feature = "0_19_1"), not(feature = "0_18_1"), not(feature = "0_17_1")))] +#[cfg(all(not(feature = "28_0"), not(feature = "27_1"), not(feature = "27_0"), not(feature = "26_2"), not(feature = "26_1"), not(feature = "26_0"), not(feature = "25_2"), not(feature = "25_1"), not(feature = "25_0"), not(feature = "24_2"),not(feature = "24_1"), not(feature = "24_0_1"), not(feature = "23_2"), not(feature = "23_1"), not(feature = "23_0"), not(feature = "22_1"), not(feature = "22_0"), not(feature = "0_21_2"), not(feature = "0_20_2"), not(feature = "0_19_1"), not(feature = "0_18_1"), not(feature = "0_17_1")))] #[allow(unused_imports)] // Not all users need the json types. -pub use bitcoind_json_rpc_client::{client_sync::v27::{Client, AddressType}, json::v27 as json}; +pub use bitcoind_json_rpc_client::{client_sync::v28::{Client, AddressType}, json::v28 as json}; diff --git a/regtest/src/versions.rs b/regtest/src/versions.rs index 33cedfd..ad5d894 100644 --- a/regtest/src/versions.rs +++ b/regtest/src/versions.rs @@ -1,4 +1,7 @@ -#[cfg(feature = "27_1")] +#[cfg(feature = "28_0")] +pub const VERSION: &str = "28.0"; + +#[cfg(all(feature = "27_1", not(feature = "28_0")))] pub const VERSION: &str = "27.1"; #[cfg(all(feature = "27_0", not(feature = "27_1")))] @@ -62,6 +65,6 @@ pub const VERSION: &str = "0.18.1"; pub const VERSION: &str = "0.17.1"; // To make --no-default-features work we have to enable some feature, use most recent version same as for default. -#[cfg(all(not(feature = "27_1"), not(feature = "27_0"), not(feature = "26_2"), not(feature = "26_1"), not(feature = "26_0"), not(feature = "25_2"), not(feature = "25_1"), not(feature = "25_0"), not(feature = "24_2"),not(feature = "24_1"), not(feature = "24_0_1"), not(feature = "23_2"), not(feature = "23_1"), not(feature = "23_0"), not(feature = "22_1"), not(feature = "22_0"), not(feature = "0_21_2"), not(feature = "0_20_2"), not(feature = "0_19_1"), not(feature = "0_18_1"), not(feature = "0_17_1")))] +#[cfg(all(not(feature = "28_0"), not(feature = "27_1"), not(feature = "27_0"), not(feature = "26_2"), not(feature = "26_1"), not(feature = "26_0"), not(feature = "25_2"), not(feature = "25_1"), not(feature = "25_0"), not(feature = "24_2"),not(feature = "24_1"), not(feature = "24_0_1"), not(feature = "23_2"), not(feature = "23_1"), not(feature = "23_0"), not(feature = "22_1"), not(feature = "22_0"), not(feature = "0_21_2"), not(feature = "0_20_2"), not(feature = "0_19_1"), not(feature = "0_18_1"), not(feature = "0_17_1")))] #[allow(dead_code)] // for --no-default-features -pub const VERSION: &str = "27.1"; +pub const VERSION: &str = "28.0";