Skip to content

Commit 555f7d4

Browse files
committed
Proxy api improvements & fixes
Http get empty response handle Http post implementation New models introduced
1 parent d533851 commit 555f7d4

File tree

12 files changed

+310
-46
lines changed

12 files changed

+310
-46
lines changed

src/main/java/io/api/etherscan/App.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package io.api.etherscan;
22

33
import io.api.etherscan.core.impl.EtherScanApi;
4-
import io.api.etherscan.model.Tx;
5-
import io.api.etherscan.model.TxInternal;
6-
import io.api.etherscan.model.TxToken;
7-
import io.api.etherscan.model.UncleBlock;
4+
import io.api.etherscan.model.*;
85

96
import java.util.List;
107
import java.util.Optional;
@@ -15,6 +12,7 @@
1512
public class App {
1613
public static void main(String[] args) {
1714
EtherScanApi api = new EtherScanApi(args[0]);
15+
Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
1816
List<Tx> txs = api.account().txs("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
1917
List<TxToken> txTokens = api.account().txsToken("0xf261B3A60Ef40eE0B369B0705c1a2c58B02799DF");
2018
List<TxInternal> txInternals = api.account().txsInternal("0x2c1ba59d6f58433fb1eaee7d20b26ed83bda51a3");

src/main/java/io/api/etherscan/core/IProxyApi.java

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.api.etherscan.error.ApiException;
44
import io.api.etherscan.model.proxy.BlockProxy;
5+
import io.api.etherscan.model.proxy.TxInfoProxy;
56
import io.api.etherscan.model.proxy.TxProxy;
67
import org.jetbrains.annotations.NotNull;
78

@@ -17,49 +18,89 @@
1718
*/
1819
public interface IProxyApi {
1920

20-
/** Returns the number of most recent block */
21+
/**
22+
* Returns the number of most recent block
23+
* eth_blockNumber
24+
*/
2125
long blockNoLast();
2226

23-
/** Returns information about a block by block number */
27+
/**
28+
* Returns information about a block by block number
29+
* eth_getBlockByNumber
30+
*/
2431
@NotNull Optional<BlockProxy> block(long blockNo) throws ApiException;
2532

26-
/** Returns information about a uncle by block number */
33+
/**
34+
* Returns information about a uncle by block number
35+
* eth_getUncleByBlockNumberAndIndex
36+
*/
2737
@NotNull Optional<BlockProxy> blockUncle(long blockNo, long index) throws ApiException;
2838

29-
/** Returns the information about a transaction requested by transaction hash */
39+
/**
40+
* Returns the information about a transaction requested by transaction hash
41+
* eth_getTransactionByHash
42+
*/
3043
@NotNull Optional<TxProxy> tx(String txhash) throws ApiException;
3144

32-
/** Returns information about a transaction by block number and transaction index position */
45+
/**
46+
* Returns information about a transaction by block number and transaction index position
47+
* eth_getTransactionByBlockNumberAndIndex
48+
*/
3349
@NotNull Optional<TxProxy> tx(long blockNo, long index) throws ApiException;
3450

35-
/** Returns the number of transactions in a block from a block matching the given block number */
51+
/**
52+
* Returns the number of transactions in a block from a block matching the given block number
53+
* eth_getBlockTransactionCountByNumber
54+
*/
3655
int txCount(long blockNo) throws ApiException;
3756

38-
/** Returns the number of transactions sent from an address */
57+
/**
58+
* Returns the number of transactions sent from an address
59+
* eth_getTransactionCount
60+
*/
3961
int txSendCount(String address) throws ApiException;
4062

41-
//TODO implement
42-
/** Creates new message call transaction or a contract creation for signed transactions */
43-
boolean txSendRaw(String hexEncodedTx) throws ApiException;
63+
/**
64+
* Creates new message call transaction or a contract creation for signed transactions
65+
* eth_sendRawTransaction
66+
*/
67+
@NotNull Optional<String> txSendRaw(String hexEncodedTx) throws ApiException;
68+
69+
/**
70+
* Returns the receipt of a transaction by transaction hash
71+
* eth_getTransactionReceipt
72+
*/
73+
@NotNull Optional<TxInfoProxy> txReceipt(String txhash);
4474

45-
/** Executes a new message call immediately without creating a transaction on the block chain */
46-
@NotNull String call(String address, String data) throws ApiException;
75+
/**
76+
* Executes a new message call immediately without creating a transaction on the block chain
77+
* eth_call
78+
*/
79+
@NotNull Optional<String> call(String address, String data) throws ApiException;
4780

48-
/** Returns code at a given address */
49-
@NotNull String code(String address) throws ApiException;
81+
/**
82+
* Returns code at a given address
83+
* eth_getCode
84+
*/
85+
@NotNull Optional<String> code(String address) throws ApiException;
5086

5187
/**
5288
* (**experimental)
5389
* Returns the value from a storage position at a given address
90+
* eth_getStorageAt
5491
*/
55-
@NotNull String storageAt(String address, long position) throws ApiException;
92+
@NotNull Optional<String> storageAt(String address, long position) throws ApiException;
5693

57-
/** Returns the current price per gas in wei */
94+
/**
95+
* Returns the current price per gas in wei
96+
* eth_gasPrice
97+
*/
5898
@NotNull BigInteger gasPrice() throws ApiException;
5999

60100
/**
61101
* Makes a call or transaction, which won't be added to the blockchain and returns the used gas,
62102
* which can be used for estimating the used gas
103+
* eth_estimateGas
63104
*/
64105
@NotNull BigInteger gasEstimated() throws ApiException;
65106
@NotNull BigInteger gasEstimated(String hexData) throws ApiException;

src/main/java/io/api/etherscan/core/impl/BasicProvider.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
package io.api.etherscan.core.impl;
22

33
import com.google.gson.Gson;
4+
import io.api.etherscan.error.NoResponseException;
45
import io.api.etherscan.error.ParseException;
56
import io.api.etherscan.executor.IHttpExecutor;
67
import io.api.etherscan.manager.IQueueManager;
8+
import io.api.etherscan.util.BasicUtils;
79

810
/**
911
* Base provider for API Implementations
1012
*
11-
* @see EtherScanApi
12-
*
1313
* @author GoodforGod
14+
* @see EtherScanApi
1415
* @since 28.10.2018
1516
*/
1617
abstract class BasicProvider {
@@ -24,6 +25,7 @@ abstract class BasicProvider {
2425
private final String baseUrl;
2526
private final IHttpExecutor executor;
2627
private final IQueueManager queue;
28+
private final Gson gson;
2729

2830
BasicProvider(final IQueueManager queue,
2931
final String module,
@@ -33,11 +35,12 @@ abstract class BasicProvider {
3335
this.module = "&module=" + module;
3436
this.baseUrl = baseUrl;
3537
this.executor = executor;
38+
this.gson = new Gson();
3639
}
3740

3841
private <T> T convert(final String json, final Class<T> tClass) {
3942
try {
40-
return new Gson().fromJson(json, tClass);
43+
return gson.fromJson(json, tClass);
4144
} catch (Exception e) {
4245
throw new ParseException(e.getMessage(), e.getCause());
4346
}
@@ -46,10 +49,24 @@ private <T> T convert(final String json, final Class<T> tClass) {
4649
private String getRequest(final String urlParameters) {
4750
queue.takeTurn();
4851
final String url = baseUrl + module + urlParameters;
49-
return executor.get(url);
52+
final String result = executor.get(url);
53+
if (BasicUtils.isEmpty(result))
54+
throw new NoResponseException("Server returned null value for GET request at URL - " + url);
55+
56+
return result;
57+
}
58+
59+
private String postRequest(final String urlParameters, final String dataToPost) {
60+
queue.takeTurn();
61+
final String url = baseUrl + module + urlParameters;
62+
return executor.post(url, dataToPost);
5063
}
5164

5265
<T> T getRequest(final String urlParameters, final Class<T> tClass) {
5366
return convert(getRequest(urlParameters), tClass);
5467
}
68+
69+
<T> T postRequest(final String urlParameters, final String dataToPost, final Class<T> tClass) {
70+
return convert(postRequest(urlParameters, dataToPost), tClass);
71+
}
5572
}

src/main/java/io/api/etherscan/core/impl/BlockApiProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class BlockApiProvider extends BasicProvider implements IBlockApi {
3535
public Optional<UncleBlock> uncles(long blockNumber) {
3636
final String urlParam = ACT_BLOCK_PARAM + BLOCKNO_PARAM + blockNumber;
3737
final UncleBlockResponseTO response = getRequest(urlParam, UncleBlockResponseTO.class);
38+
3839
BasicUtils.validateTxResponse(response);
3940

4041
return (response.getResult() == null || response.getResult().isEmpty())

src/main/java/io/api/etherscan/core/impl/ProxyApiProvider.java

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
import io.api.etherscan.core.IProxyApi;
44
import io.api.etherscan.error.ApiException;
5+
import io.api.etherscan.error.EtherScanException;
56
import io.api.etherscan.error.InvalidDataHexException;
67
import io.api.etherscan.executor.IHttpExecutor;
78
import io.api.etherscan.manager.IQueueManager;
89
import io.api.etherscan.model.proxy.BlockProxy;
10+
import io.api.etherscan.model.proxy.TxInfoProxy;
911
import io.api.etherscan.model.proxy.TxProxy;
1012
import io.api.etherscan.model.proxy.utility.BlockProxyTO;
1113
import io.api.etherscan.model.proxy.utility.StringProxyTO;
14+
import io.api.etherscan.model.proxy.utility.TxInfoProxyTO;
1215
import io.api.etherscan.model.proxy.utility.TxProxyTO;
1316
import io.api.etherscan.util.BasicUtils;
1417
import org.jetbrains.annotations.NotNull;
@@ -112,7 +115,7 @@ public Optional<TxProxy> tx(final long blockNo, final long index) throws ApiExce
112115
@Override
113116
public int txCount(final long blockNo) throws ApiException {
114117
final long compensatedBlockNo = BasicUtils.compensateMinBlock(blockNo);
115-
final String urlParams = ACT_TX_COUNT_PARAM + TAG_PARAM + compensatedBlockNo;
118+
final String urlParams = ACT_BLOCKTX_COUNT_PARAM + TAG_PARAM + compensatedBlockNo;
116119
final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
117120
return Integer.valueOf(response.getResult());
118121
}
@@ -121,52 +124,73 @@ public int txCount(final long blockNo) throws ApiException {
121124
public int txSendCount(final String address) throws ApiException {
122125
BasicUtils.validateAddress(address);
123126

124-
final String urlParams = ACT_TX_BY_HASH_PARAM + ADDRESS_PARAM + address + TAG_LAST_PARAM;
127+
final String urlParams = ACT_TX_COUNT_PARAM + ADDRESS_PARAM + address + TAG_LAST_PARAM;
125128
final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
126129
return (int) BasicUtils.parseHex(response.getResult());
127130
}
128131

129-
//TODO need postRequest executor implementation
130132
@Override
131-
public boolean txSendRaw(final String hexEncodedTx) throws ApiException {
132-
return false;
133+
@NotNull
134+
public Optional<String> txSendRaw(final String hexEncodedTx) throws ApiException {
135+
if(BasicUtils.isNotHex(hexEncodedTx))
136+
throw new InvalidDataHexException("Data is not encoded in hex format - " + hexEncodedTx);
137+
138+
final String urlParams = ACT_SEND_RAW_TX_PARAM + HEX_PARAM + hexEncodedTx;
139+
final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
140+
if(response.getError() != null)
141+
throw new EtherScanException("Error occurred with code " + response.getError().getCode()
142+
+ " with message " + response.getError().getMessage());
143+
144+
return (BasicUtils.isEmpty(response.getResult()))
145+
? Optional.empty()
146+
: Optional.of(response.getResult());
147+
}
148+
149+
@NotNull
150+
@Override
151+
public Optional<TxInfoProxy> txReceipt(final String txhash) {
152+
BasicUtils.validateTxHash(txhash);
153+
154+
final String urlParams = ACT_TX_RECEIPT_PARAM + TXHASH_PARAM + txhash;
155+
final TxInfoProxyTO response = getRequest(urlParams, TxInfoProxyTO.class);
156+
return Optional.ofNullable(response.getResult());
133157
}
134158

135159
@NotNull
136160
@Override
137-
public String call(final String address, final String data) throws ApiException {
161+
public Optional<String> call(final String address, final String data) throws ApiException {
138162
BasicUtils.validateAddress(address);
139163

140164
final String urlParams = ACT_CALL_PARAM + TO_PARAM + address + DATA_PARAM + data + TAG_LAST_PARAM;
141165
final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
142166
return (BasicUtils.isEmpty(response.getResult()))
143-
? ""
144-
: response.getResult();
167+
? Optional.empty()
168+
: Optional.of(response.getResult());
145169
}
146170

147171
@NotNull
148172
@Override
149-
public String code(final String address) throws ApiException {
173+
public Optional<String> code(final String address) throws ApiException {
150174
BasicUtils.validateAddress(address);
151175

152176
final String urlParams = ACT_CODE_PARAM + ADDRESS_PARAM + address + TAG_LAST_PARAM;
153177
final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
154178
return (BasicUtils.isEmpty(response.getResult()))
155-
? ""
156-
: response.getResult();
179+
? Optional.empty()
180+
: Optional.of(response.getResult());
157181
}
158182

159183
@NotNull
160184
@Override
161-
public String storageAt(final String address, final long position) throws ApiException {
185+
public Optional<String> storageAt(final String address, final long position) throws ApiException {
162186
BasicUtils.validateAddress(address);
163187
final long compPosition = BasicUtils.compensateMinBlock(position);
164188

165189
final String urlParams = ACT_STORAGEAT_PARAM + ADDRESS_PARAM + address + POSITION_PARAM + compPosition + TAG_LAST_PARAM;
166190
final StringProxyTO response = getRequest(urlParams, StringProxyTO.class);
167191
return (BasicUtils.isEmpty(response.getResult()))
168-
? ""
169-
: response.getResult();
192+
? Optional.empty()
193+
: Optional.of(response.getResult());
170194
}
171195

172196
@NotNull
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.api.etherscan.error;
2+
3+
/**
4+
* ! NO DESCRIPTION !
5+
*
6+
* @author GoodforGod
7+
* @since 03.11.2018
8+
*/
9+
public class NoResponseException extends ApiException {
10+
11+
public NoResponseException(String message) {
12+
super(message);
13+
}
14+
}

src/main/java/io/api/etherscan/executor/IHttpExecutor.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.api.etherscan.executor;
22

33
/**
4-
* ! NO DESCRIPTION !
4+
* Http Client interface
55
*
66
* @author GoodforGod
77
* @since 31.10.2018
@@ -15,4 +15,13 @@ public interface IHttpExecutor {
1515
* @return result as string
1616
*/
1717
String get(String url);
18+
19+
/**
20+
* Performs a Http POST request
21+
*
22+
* @param url as string
23+
* @param data to post
24+
* @return result as string
25+
*/
26+
String post(String url, String data);
1827
}

0 commit comments

Comments
 (0)