@@ -320,6 +320,7 @@ public async Task<RPCCapabilities> ScanRPCCapabilitiesAsync(CancellationToken ca
320320 CheckCapabilitiesAsync ( rpc , "scantxoutset" , v => capabilities . SupportScanUTXOSet = v , cancellationToken ) ,
321321 CheckCapabilitiesAsync ( rpc , "signrawtransactionwithkey" , v => capabilities . SupportSignRawTransactionWith = v , cancellationToken ) ,
322322 CheckCapabilitiesAsync ( rpc , "testmempoolaccept" , v => capabilities . SupportTestMempoolAccept = v , cancellationToken ) ,
323+ CheckCapabilitiesAsync ( rpc , "getblockfrompeer" , v => capabilities . CanGetBlockFromPeer = v , cancellationToken ) ,
323324 CheckCapabilitiesAsync ( rpc , "estimatesmartfee" , v => capabilities . SupportEstimateSmartFee = v , cancellationToken ) ,
324325 CheckCapabilitiesAsync ( rpc , "generatetoaddress" , v => capabilities . SupportGenerateToAddress = v , cancellationToken ) ,
325326 CheckSegwitCapabilitiesAsync ( rpc , v => capabilities . SupportSegwit = v , ScriptPubKeyType . Segwit , cancellationToken ) ,
@@ -581,6 +582,32 @@ public async Task<BitcoinAddress> GetNewAddressAsync(CancellationToken cancellat
581582 return BitcoinAddress . Create ( result . Result . ToString ( ) , Network ) ;
582583 }
583584
585+ /// <summary>
586+ /// Attempt to fetch block from a given peer.
587+ /// </summary>
588+ /// <param name="blockHash">The block hash to try to fetch</param>
589+ /// <param name="peerId">The peer to fetch it from (see <see cref="GetPeersInfo"></see> for peer IDs)</param>
590+ /// <param name="cancellationToken"></param>
591+ /// <exception cref="RPCException">Fetching the block wasn't successful, for other reason</exception>
592+ /// <returns>The result of this operation. You can then query it with <see cref="GetBlockAsync(uint256, CancellationToken)"/>. If the result is unknown <see cref="RPCException"></see> is thrown./></returns>
593+ public async Task < GetBlockFromPeerResult > GetBlockFromPeer ( uint256 blockHash , int peerId , CancellationToken cancellationToken = default )
594+ {
595+ if ( blockHash is null )
596+ throw new ArgumentNullException ( nameof ( blockHash ) ) ;
597+ var r = new RPCRequest ( RPCOperations . getblockfrompeer , new object [ ] { blockHash . ToString ( ) , peerId } ) ;
598+ r . ThrowIfRPCError = false ;
599+ var result = await SendCommandAsync ( r , cancellationToken ) . ConfigureAwait ( false ) ;
600+ return result . Error switch
601+ {
602+ null => RPC . GetBlockFromPeerResult . Fetched ,
603+ { Message : "Block already downloaded" } => RPC . GetBlockFromPeerResult . AlreadyDownloaded ,
604+ { Message : "Block header missing" } => RPC . GetBlockFromPeerResult . BlockHeaderMissing ,
605+ { Message : "Peer does not exist" } => RPC . GetBlockFromPeerResult . UnknownPeerId ,
606+ { Message : "In prune mode, only blocks that the node has already synced previously can be fetched from a peer" } => RPC . GetBlockFromPeerResult . NeverSynched ,
607+ { } e => throw new RPCException ( e . Code , e . Message , result )
608+ } ;
609+ }
610+
584611 public async Task < BitcoinAddress > GetNewAddressAsync ( GetNewAddressRequest request , CancellationToken cancellationToken = default )
585612 {
586613 var p = new Dictionary < string , object > ( ) ;
@@ -1095,6 +1122,7 @@ public async Task<PeerInfo[]> GetPeersInfoAsync(CancellationToken cancellationTo
10951122 Address = addressEnpoint ,
10961123 LocalAddress = localEndpoint ,
10971124 Services = ( NodeServices ) services ,
1125+ ServicesNames = ( peer [ "servicesnames" ] as JArray ) ? . Select ( a => a . ToString ( ) ) . ToArray ( ) ,
10981126 LastSend = Utils . UnixTimeToDateTime ( ( uint ) peer [ "lastsend" ] ) ,
10991127 LastReceive = Utils . UnixTimeToDateTime ( ( uint ) peer [ "lastrecv" ] ) ,
11001128 BytesSent = ( long ) peer [ "bytessent" ] ,
@@ -1119,6 +1147,11 @@ public async Task<PeerInfo[]> GetPeersInfoAsync(CancellationToken cancellationTo
11191147 return result ;
11201148 }
11211149
1150+ public Task DisconnectNode ( EndPoint endPoint , CancellationToken cancellationToken = default )
1151+ => SendCommandAsync ( RPCOperations . disconnectnode , cancellationToken , new object [ ] { endPoint . ToString ( ) } ) ;
1152+ public Task DisconnectNode ( int peerId , CancellationToken cancellationToken = default )
1153+ => SendCommandAsync ( RPCOperations . disconnectnode , cancellationToken , new object [ ] { "" , peerId } ) ;
1154+
11221155 public void AddNode ( EndPoint nodeEndPoint , bool onetry = false )
11231156 {
11241157 if ( nodeEndPoint == null )
@@ -2435,6 +2468,7 @@ public NodeServices Services
24352468 {
24362469 get ; internal set ;
24372470 }
2471+ public string [ ] ServicesNames { get ; set ; }
24382472 public DateTimeOffset LastSend
24392473 {
24402474 get ; internal set ;
0 commit comments