@ -13,16 +13,19 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory ;
import java.util.* ;
import java.util.concurrent.atomic.AtomicLong ;
public class SimpleElectrumServerRpc implements ElectrumServerRpc {
private static final Logger log = LoggerFactory . getLogger ( SimpleElectrumServerRpc . class ) ;
private static final int MAX_TARGET_BLOCKS = 25 ;
private final AtomicLong idCounter = new AtomicLong ( ) ;
@Override
public void ping ( Transport transport ) {
try {
JsonRpcClient client = new JsonRpcClient ( transport ) ;
client . createRequest ( ) . method ( "server.ping" ) . id ( 1 ) . executeNullable ( ) ;
client . createRequest ( ) . method ( "server.ping" ) . id ( idCounter . incrementAndGet ( ) ) . executeNullable ( ) ;
} catch ( JsonRpcException | IllegalStateException | IllegalArgumentException e ) {
throw new ElectrumServerRpcException ( "Error pinging server" , e ) ;
}
@ -33,7 +36,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
try {
JsonRpcClient client = new JsonRpcClient ( transport ) ;
//Using 1.4 as the version number as EPS tries to parse this number to a float
return client . createRequest ( ) . returnAsList ( String . class ) . method ( "server.version" ) . id ( 1 ) . params ( clientName , "1.4" ) . execute ( ) ;
return client . createRequest ( ) . returnAsList ( String . class ) . method ( "server.version" ) . id ( idCounter . incrementAndGet ( ) ) . params ( clientName , "1.4" ) . execute ( ) ;
} catch ( JsonRpcException | IllegalStateException | IllegalArgumentException e ) {
throw new ElectrumServerRpcException ( "Error getting server version" , e ) ;
}
@ -43,7 +46,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
public String getServerBanner ( Transport transport ) {
try {
JsonRpcClient client = new JsonRpcClient ( transport ) ;
return client . createRequest ( ) . returnAs ( String . class ) . method ( "server.banner" ) . id ( 1 ) . execute ( ) ;
return client . createRequest ( ) . returnAs ( String . class ) . method ( "server.banner" ) . id ( idCounter . incrementAndGet ( ) ) . execute ( ) ;
} catch ( JsonRpcException | IllegalStateException | IllegalArgumentException e ) {
throw new ElectrumServerRpcException ( "Error getting server banner" , e ) ;
}
@ -53,7 +56,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
public BlockHeaderTip subscribeBlockHeaders ( Transport transport ) {
try {
JsonRpcClient client = new JsonRpcClient ( transport ) ;
return client . createRequest ( ) . returnAs ( BlockHeaderTip . class ) . method ( "blockchain.headers.subscribe" ) . id ( 1 ) . execute ( ) ;
return client . createRequest ( ) . returnAs ( BlockHeaderTip . class ) . method ( "blockchain.headers.subscribe" ) . id ( idCounter . incrementAndGet ( ) ) . execute ( ) ;
} catch ( JsonRpcException | IllegalStateException | IllegalArgumentException e ) {
throw new ElectrumServerRpcException ( "Error subscribing to block headers" , e ) ;
}
@ -67,7 +70,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
for ( String path : pathScriptHashes . keySet ( ) ) {
EventManager . get ( ) . post ( new WalletHistoryStatusEvent ( false , "Loading transactions for " + path ) ) ;
try {
ScriptHashTx [ ] scriptHashTxes = client . createRequest ( ) . returnAs ( ScriptHashTx [ ] . class ) . method ( "blockchain.scripthash.get_history" ) . id ( path ) . params ( pathScriptHashes . get ( path ) ) . execute ( ) ;
ScriptHashTx [ ] scriptHashTxes = client . createRequest ( ) . returnAs ( ScriptHashTx [ ] . class ) . method ( "blockchain.scripthash.get_history" ) . id ( path + "-" + idCounter . incrementAndGet ( ) ) . params ( pathScriptHashes . get ( path ) ) . execute ( ) ;
result . put ( path , scriptHashTxes ) ;
} catch ( JsonRpcException | IllegalStateException | IllegalArgumentException e ) {
if ( failOnError ) {
@ -88,7 +91,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
Map < String , ScriptHashTx [ ] > result = new LinkedHashMap < > ( ) ;
for ( String path : pathScriptHashes . keySet ( ) ) {
try {
ScriptHashTx [ ] scriptHashTxes = client . createRequest ( ) . returnAs ( ScriptHashTx [ ] . class ) . method ( "blockchain.scripthash.get_mempool" ) . id ( path ) . params ( pathScriptHashes . get ( path ) ) . execute ( ) ;
ScriptHashTx [ ] scriptHashTxes = client . createRequest ( ) . returnAs ( ScriptHashTx [ ] . class ) . method ( "blockchain.scripthash.get_mempool" ) . id ( path + "-" + idCounter . incrementAndGet ( ) ) . params ( pathScriptHashes . get ( path ) ) . execute ( ) ;
result . put ( path , scriptHashTxes ) ;
} catch ( JsonRpcException | IllegalStateException | IllegalArgumentException e ) {
if ( failOnError ) {
@ -110,7 +113,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
for ( String path : pathScriptHashes . keySet ( ) ) {
EventManager . get ( ) . post ( new WalletHistoryStatusEvent ( false , "Finding transactions for " + path ) ) ;
try {
String scriptHash = client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.scripthash.subscribe" ) . id ( path ) . params ( pathScriptHashes . get ( path ) ) . executeNullable ( ) ;
String scriptHash = client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.scripthash.subscribe" ) . id ( path + "-" + idCounter . incrementAndGet ( ) ) . params ( pathScriptHashes . get ( path ) ) . executeNullable ( ) ;
result . put ( path , scriptHash ) ;
} catch ( JsonRpcException | IllegalStateException | IllegalArgumentException e ) {
//Even if we have some successes, failure to subscribe for all script hashes will result in outdated wallet view. Don't proceed.
@ -129,7 +132,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
for ( Integer blockHeight : blockHeights ) {
EventManager . get ( ) . post ( new WalletHistoryStatusEvent ( false , "Retrieving block at height " + blockHeight ) ) ;
try {
String blockHeader = client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.block.header" ) . id ( blockHeight ) . params ( blockHeight ) . execute ( ) ;
String blockHeader = client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.block.header" ) . id ( idCounter . incrementAndGet ( ) ) . params ( blockHeight ) . execute ( ) ;
result . put ( blockHeight , blockHeader ) ;
} catch ( IllegalStateException | IllegalArgumentException e ) {
log . warn ( "Failed to retrieve block header for block height: " + blockHeight + " (" + e . getMessage ( ) + ")" ) ;
@ -149,7 +152,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
for ( String txid : txids ) {
EventManager . get ( ) . post ( new WalletHistoryStatusEvent ( false , "Retrieving transaction [" + txid . substring ( 0 , 6 ) + "]" ) ) ;
try {
String rawTxHex = client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.transaction.get" ) . id ( txid ) . params ( txid ) . execute ( ) ;
String rawTxHex = client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.transaction.get" ) . id ( idCounter . incrementAndGet ( ) ) . params ( txid ) . execute ( ) ;
result . put ( txid , rawTxHex ) ;
} catch ( JsonRpcException | IllegalStateException | IllegalArgumentException e ) {
result . put ( txid , Sha256Hash . ZERO_HASH . toString ( ) ) ;
@ -166,7 +169,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
Map < String , VerboseTransaction > result = new LinkedHashMap < > ( ) ;
for ( String txid : txids ) {
try {
VerboseTransaction verboseTransaction = client . createRequest ( ) . returnAs ( VerboseTransaction . class ) . method ( "blockchain.transaction.get" ) . id ( txid ) . params ( txid , true ) . execute ( ) ;
VerboseTransaction verboseTransaction = client . createRequest ( ) . returnAs ( VerboseTransaction . class ) . method ( "blockchain.transaction.get" ) . id ( idCounter . incrementAndGet ( ) ) . params ( txid , true ) . execute ( ) ;
result . put ( txid , verboseTransaction ) ;
} catch ( Exception e ) {
//electrs does not currently support the verbose parameter, so try to fetch an incomplete VerboseTransaction without it
@ -175,13 +178,13 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
log . debug ( "Error retrieving transaction: " + txid + " (" + ( e . getCause ( ) ! = null ? e . getCause ( ) . getMessage ( ) : e . getMessage ( ) ) + ")" ) ;
try {
String rawTxHex = client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.transaction.get" ) . id ( txid ) . params ( txid ) . execute ( ) ;
String rawTxHex = client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.transaction.get" ) . id ( idCounter . incrementAndGet ( ) ) . params ( txid ) . execute ( ) ;
Transaction tx = new Transaction ( Utils . hexToBytes ( rawTxHex ) ) ;
String id = tx . getTxId ( ) . toString ( ) ;
int height = 0 ;
if ( scriptHash ! = null ) {
ScriptHashTx [ ] scriptHashTxes = client . createRequest ( ) . returnAs ( ScriptHashTx [ ] . class ) . method ( "blockchain.scripthash.get_history" ) . id ( id ) . params ( scriptHash ) . execute ( ) ;
ScriptHashTx [ ] scriptHashTxes = client . createRequest ( ) . returnAs ( ScriptHashTx [ ] . class ) . method ( "blockchain.scripthash.get_history" ) . id ( idCounter . incrementAndGet ( ) ) . params ( scriptHash ) . execute ( ) ;
for ( ScriptHashTx scriptHashTx : scriptHashTxes ) {
if ( scriptHashTx . tx_hash . equals ( id ) ) {
height = scriptHashTx . height ;
@ -213,7 +216,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
for ( Integer targetBlock : targetBlocks ) {
if ( targetBlock < = MAX_TARGET_BLOCKS ) {
try {
Double targetBlocksFeeRateBtcKb = client . createRequest ( ) . returnAs ( Double . class ) . method ( "blockchain.estimatefee" ) . id ( targetBlock ) . params ( targetBlock ) . execute ( ) ;
Double targetBlocksFeeRateBtcKb = client . createRequest ( ) . returnAs ( Double . class ) . method ( "blockchain.estimatefee" ) . id ( idCounter . incrementAndGet ( ) ) . params ( targetBlock ) . execute ( ) ;
result . put ( targetBlock , targetBlocksFeeRateBtcKb ) ;
} catch ( IllegalStateException | IllegalArgumentException e ) {
log . warn ( "Failed to retrieve fee rate for target blocks: " + targetBlock + " (" + e . getMessage ( ) + ")" ) ;
@ -233,7 +236,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
public Double getMinimumRelayFee ( Transport transport ) {
try {
JsonRpcClient client = new JsonRpcClient ( transport ) ;
return client . createRequest ( ) . returnAs ( Double . class ) . method ( "blockchain.relayfee" ) . id ( 1 ) . execute ( ) ;
return client . createRequest ( ) . returnAs ( Double . class ) . method ( "blockchain.relayfee" ) . id ( idCounter . incrementAndGet ( ) ) . execute ( ) ;
} catch ( JsonRpcException e ) {
throw new ElectrumServerRpcException ( "Error getting minimum relay fee" , e ) ;
}
@ -243,7 +246,7 @@ public class SimpleElectrumServerRpc implements ElectrumServerRpc {
public String broadcastTransaction ( Transport transport , String txHex ) {
try {
JsonRpcClient client = new JsonRpcClient ( transport ) ;
return client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.transaction.broadcast" ) . id ( 1 ) . params ( txHex ) . execute ( ) ;
return client . createRequest ( ) . returnAs ( String . class ) . method ( "blockchain.transaction.broadcast" ) . id ( idCounter . incrementAndGet ( ) ) . params ( txHex ) . execute ( ) ;
} catch ( IllegalStateException | IllegalArgumentException e ) {
throw new ElectrumServerRpcException ( e . getMessage ( ) , e ) ;
} catch ( JsonRpcException e ) {