Skip to content

Commit 2969dc1

Browse files
authoredNov 1, 2021
Merge pull request #12 from GoodforGod/dev
[1.1.1]
2 parents 5030e1c + cd2aad3 commit 2969dc1

24 files changed

+217
-167
lines changed
 

‎.github/workflows/gradle.yml

+25-22
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@ on:
44
push:
55
branches:
66
- master
7-
schedule:
8-
- cron: "0 12 1 * *"
97
pull_request:
108
branches:
11-
- master
12-
- dev
9+
- master
10+
- dev
1311

1412
jobs:
1513
build:
@@ -20,21 +18,26 @@ jobs:
2018
name: Java ${{ matrix.java }} setup
2119

2220
steps:
23-
- uses: actions/checkout@v1
24-
- name: Set up JDK
25-
uses: actions/setup-java@v1
26-
27-
with:
28-
java-version: ${{ matrix.java }}
29-
30-
- name: Build with Gradle
31-
run: ./gradlew build jacocoTestReport
32-
env:
33-
API_KEY: ${{ secrets.API_KEY }}
34-
35-
- name: Analyze with SonarQube
36-
run: ./gradlew sonarqube
37-
env:
38-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39-
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
40-
API_KEY: ${{ secrets.API_KEY }}
21+
- uses: actions/checkout@v1
22+
- name: Set up JDK
23+
uses: actions/setup-java@v1
24+
25+
with:
26+
java-version: ${{ matrix.java }}
27+
28+
- name: Build
29+
run: ./gradlew classes
30+
31+
- name: Codestyle
32+
run: ./gradlew spotlessCheck
33+
34+
- name: Test
35+
run: ./gradlew test jacocoTestReport
36+
env:
37+
API_KEY: ${{ secrets.API_KEY }}
38+
39+
- name: SonarQube
40+
run: ./gradlew sonarqube
41+
env:
42+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

‎README.md

+25-18
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,23 @@
1111
Library supports all available EtherScan *API* calls for all available *Ethereum Networks* for *etherscan.io*
1212

1313
## Dependency :rocket:
14+
15+
**Gradle**
16+
```groovy
17+
dependencies {
18+
compile "com.github.goodforgod:java-etherscan-api:1.1.1"
19+
}
20+
```
21+
1422
**Maven**
1523
```xml
1624
<dependency>
1725
<groupId>com.github.goodforgod</groupId>
1826
<artifactId>java-etherscan-api</artifactId>
19-
<version>1.1.0</version>
27+
<version>1.1.1</version>
2028
</dependency>
2129
```
2230

23-
**Gradle**
24-
```groovy
25-
dependencies {
26-
compile 'com.github.goodforgod:java-etherscan-api:1.1.0'
27-
}
28-
```
29-
3031
## Content
3132
- [Ethereum Networks](#mainnet-and-testnets)
3233
- [Custom HttpClient](#custom-httpclient)
@@ -42,6 +43,7 @@ dependencies {
4243
- [Version History](#version-history)
4344

4445
## Mainnet and Testnets
46+
4547
API support Ethereum: *[MAINNET](https://etherscan.io),
4648
[ROPSTEN](https://ropsten.etherscan.io),
4749
[KOVAN](https://kovan.etherscan.io),
@@ -88,14 +90,18 @@ EtherScanApi api = new EtherScanApi("YourApiKey");
8890
Below are examples for each API category.
8991

9092
### Account Api
93+
9194
**Get Ether Balance for a single Address**
95+
9296
```java
9397
EtherScanApi api = new EtherScanApi();
9498
Balance balance = api.account().balance("0x8d4426f94e42f721C7116E81d6688cd935cB3b4F");
9599
```
96100

97101
### Block Api
102+
98103
**Get uncles block for block height**
104+
99105
```java
100106
EtherScanApi api = new EtherScanApi();
101107
Optional<UncleBlock> uncles = api.block().uncles(200000);
@@ -109,7 +115,9 @@ Abi abi = api.contract().contractAbi("0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413
109115
```
110116

111117
### Logs Api
118+
112119
**Get event logs for single topic**
120+
113121
```java
114122
EtherScanApi api = new EtherScanApi();
115123
LogQuery query = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c")
@@ -119,6 +127,7 @@ List<Log> logs = api.logs().logs(query);
119127
```
120128

121129
**Get event logs for 3 topics with respectful operations**
130+
122131
```java
123132
EtherScanApi api = new EtherScanApi();
124133
LogQuery query = LogQueryBuilder.with("0x33990122638b9132ca29c723bdf037f1a891a70c", 379224, 400000)
@@ -134,47 +143,45 @@ List<Log> logs = api.logs().logs(query);
134143
```
135144

136145
### Proxy Api
146+
137147
**Get tx detailds with proxy endpoint**
148+
138149
```java
139150
EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET);
140151
Optional<TxProxy> tx = api.proxy().tx("0x1e2910a262b1008d0616a0beb24c1a491d78771baa54a33e66065e03b1f46bc1");
141152
```
142153

143154
**Get block info with proxy endpoint**
155+
144156
```java
145157
EtherScanApi api = new EtherScanApi(EthNetwork.MAINNET);
146158
Optional<BlockProxy> block = api.proxy().block(15215);
147159
```
148160

149161
### Stats Api
162+
150163
**Statistic about last price**
164+
151165
```java
152166
EtherScanApi api = new EtherScanApi();
153167
Price price = api.stats().lastPrice();
154168
```
155169

156170
### Transaction Api
171+
157172
**Request receipt status for tx**
173+
158174
```java
159175
EtherScanApi api = new EtherScanApi();
160176
Optional<Boolean> status = api.txs().receiptStatus("0x513c1ba0bebf66436b5fed86ab668452b7805593c05073eb2d51d3a52f480a76");
161177
```
162178

163179
### Token Api
180+
164181
You can read about token API [here](https://etherscan.io/apis#tokens)
165182

166183
Token API methods migrated to [Account](#account-api) & [Stats](#stats-api) respectfully.
167184

168-
## Version History
169-
170-
**1.1.0** - Improved error handling, QueueManager improved, Gradle 6.7 instead of Maven, GitHub CI, Sonarcloud analyzer, dependencies updated.
171-
172-
**1.0.2** - Minor http client improvements.
173-
174-
**1.0.1** - Gorli & TOBALABA networks support.
175-
176-
**1.0.0** - Initial project with all API functionality, for all available networks, with tests coverage for all cases.
177-
178185
## License
179186

180187
This project licensed under the MIT - see the [LICENSE](LICENSE) file for details.

‎build.gradle

+53-56
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,57 @@
11
plugins {
2-
id 'jacoco'
3-
id 'java-library'
4-
id 'maven-publish'
2+
id "jacoco"
3+
id "java-library"
4+
id "maven-publish"
55

6-
id 'org.sonarqube' version '3.1.1'
7-
id 'com.diffplug.spotless' version '5.11.0'
6+
id "org.sonarqube" version "3.3"
7+
id "com.diffplug.spotless" version "5.14.3"
88
}
99

1010
repositories {
1111
mavenLocal()
1212
mavenCentral()
13-
jcenter()
1413
}
1514

1615
group = groupId
1716
version = artifactVersion
1817

19-
sourceCompatibility = 1.8
20-
targetCompatibility = 1.8
18+
sourceCompatibility = JavaVersion.VERSION_1_8
19+
targetCompatibility = JavaVersion.VERSION_1_8
2120

2221
spotless {
2322
java {
24-
encoding 'UTF-8'
23+
encoding "UTF-8"
2524
removeUnusedImports()
2625
eclipse().configFile "${projectDir}/config/codestyle.xml"
2726
}
2827
}
2928

3029
sonarqube {
3130
properties {
32-
property 'sonar.host.url', 'https://sonarcloud.io'
33-
property 'sonar.organization', 'goodforgod'
34-
property 'sonar.projectKey', 'GoodforGod_java-etherscan-api'
31+
property "sonar.host.url", "https://sonarcloud.io"
32+
property "sonar.organization", "goodforgod"
33+
property "sonar.projectKey", "GoodforGod_java-etherscan-api"
3534
}
3635
}
3736

3837
dependencies {
39-
implementation 'org.jetbrains:annotations:20.1.0'
40-
implementation 'com.google.code.gson:gson:2.8.6'
38+
implementation "org.jetbrains:annotations:22.0.0"
39+
implementation "com.google.code.gson:gson:2.8.8"
4140

42-
testImplementation 'junit:junit:4.13.1'
41+
testImplementation "junit:junit:4.13.1"
4342
}
4443

4544
test {
46-
failFast = true
47-
4845
useJUnit()
4946
testLogging {
50-
events "passed", "skipped", "failed"
51-
exceptionFormat "full"
47+
events("passed", "skipped", "failed")
48+
exceptionFormat("full")
5249
}
53-
}
5450

55-
tasks.withType(JavaCompile) {
56-
options.encoding = 'UTF-8'
57-
options.incremental = true
58-
options.fork = true
59-
}
60-
61-
tasks.withType(Test) {
62-
reports.html.enabled = false
63-
reports.junitXml.enabled = false
64-
}
65-
66-
java {
67-
withJavadocJar()
68-
withSourcesJar()
51+
reports {
52+
html.enabled(false)
53+
junitXml.enabled(false)
54+
}
6955
}
7056

7157
publishing {
@@ -74,27 +60,27 @@ publishing {
7460
from components.java
7561

7662
pom {
77-
name = 'Java Etherscan API'
78-
url = 'https://github.com/GoodforGod/java-etherscan-api'
79-
description = 'Library is a wrapper for EtherScan API.'
63+
name = "Java Etherscan API"
64+
url = "https://github.com/GoodforGod/java-etherscan-api"
65+
description = "Library is a wrapper for EtherScan API."
8066

8167
license {
82-
name = 'MIT License'
83-
url = 'https://github.com/GoodforGod/java-etherscan-api/blob/master/LICENSE'
84-
distribution = 'repo'
68+
name = "MIT License"
69+
url = "https://github.com/GoodforGod/java-etherscan-api/blob/master/LICENSE"
70+
distribution = "repo"
8571
}
8672

8773
developer {
88-
id = 'GoodforGod'
89-
name = 'Anton Kurako'
90-
email = 'goodforgod.dev@gmail.com'
91-
url = 'https://github.com/GoodforGod'
74+
id = "GoodforGod"
75+
name = "Anton Kurako"
76+
email = "goodforgod.dev@gmail.com"
77+
url = "https://github.com/GoodforGod"
9278
}
9379

9480
scm {
95-
connection = 'scm:git:git://github.com/GoodforGod/java-etherscan-api.git'
96-
developerConnection = 'scm:git:ssh://GoodforGod/java-etherscan-api.git'
97-
url = 'https://github.com/GoodforGod/java-etherscan-api/tree/master'
81+
connection = "scm:git:git://github.com/GoodforGod/java-etherscan-api.git"
82+
developerConnection = "scm:git:ssh://GoodforGod/java-etherscan-api.git"
83+
url = "https://github.com/GoodforGod/java-etherscan-api/tree/master"
9884
}
9985
}
10086
}
@@ -103,7 +89,7 @@ publishing {
10389
maven {
10490
def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2"
10591
def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
106-
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
92+
url = version.endsWith("SNAPSHOT") ? snapshotsRepoUrl : releasesRepoUrl
10793
credentials {
10894
username System.getenv("OSS_USERNAME")
10995
password System.getenv("OSS_PASSWORD")
@@ -112,6 +98,17 @@ publishing {
11298
}
11399
}
114100

101+
java {
102+
withJavadocJar()
103+
withSourcesJar()
104+
}
105+
106+
tasks.withType(JavaCompile) {
107+
options.encoding("UTF-8")
108+
options.incremental(true)
109+
options.fork = true
110+
}
111+
115112
check.dependsOn jacocoTestReport
116113
jacocoTestReport {
117114
reports {
@@ -120,16 +117,16 @@ jacocoTestReport {
120117
}
121118
}
122119

120+
javadoc {
121+
options.encoding = "UTF-8"
122+
if (JavaVersion.current().isJava9Compatible()) {
123+
options.addBooleanOption("html5", true)
124+
}
125+
}
126+
123127
if (project.hasProperty("signing.keyId")) {
124-
apply plugin: 'signing'
128+
apply plugin: "signing"
125129
signing {
126130
sign publishing.publications.mavenJava
127131
}
128132
}
129-
130-
javadoc {
131-
options.encoding = "UTF-8"
132-
if (JavaVersion.current().isJava9Compatible()) {
133-
options.addBooleanOption('html5', true)
134-
}
135-
}

‎config/codestyle.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
7575
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
7676
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
77-
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
77+
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/>
7878
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
7979
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_if_empty"/>
8080
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>

‎gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
groupId=com.github.goodforgod
22
artifactId=java-etherscan-api
3-
artifactVersion=1.1.0
3+
artifactVersion=1.1.1
44
buildNumber=1
55

66

‎gradle/wrapper/gradle-wrapper.jar

333 Bytes
Binary file not shown.
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

‎gradlew

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ case "`uname`" in
7272
Darwin* )
7373
darwin=true
7474
;;
75-
MINGW* )
75+
MSYS* | MINGW* )
7676
msys=true
7777
;;
7878
NONSTOP* )

‎src/main/java/io/api/etherscan/core/IAccountApi.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public interface IAccountApi {
3636
TokenBalance balance(String address, String contract) throws ApiException;
3737

3838
/**
39-
* Maximum 20 address for single batch request If address MORE THAN 20, then
40-
* there will be more than 1 request performed
39+
* Maximum 20 address for single batch request If address MORE THAN 20, then there will be more than
40+
* 1 request performed
4141
*
4242
* @param addresses addresses to get balances for
4343
* @return list of balances

‎src/main/java/io/api/etherscan/core/ILogsApi.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
public interface ILogsApi {
1717

1818
/**
19-
* alternative to the native eth_getLogs Read at EtherScan API description for
20-
* full info!
19+
* alternative to the native eth_getLogs Read at EtherScan API description for full info!
2120
*
2221
* @param query build log query
2322
* @return logs according to query

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

+14-19
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ public interface IProxyApi {
3636
Optional<BlockProxy> block(long blockNo) throws ApiException;
3737

3838
/**
39-
* Returns information about a uncle by block number
40-
* eth_getUncleByBlockNumberAndIndex
39+
* Returns information about a uncle by block number eth_getUncleByBlockNumberAndIndex
4140
*
4241
* @param blockNo block number from 0 to last
4342
* @param index uncle block index
@@ -59,8 +58,8 @@ public interface IProxyApi {
5958
Optional<TxProxy> tx(String txhash) throws ApiException;
6059

6160
/**
62-
* Returns information about a transaction by block number and transaction index
63-
* position eth_getTransactionByBlockNumberAndIndex
61+
* Returns information about a transaction by block number and transaction index position
62+
* eth_getTransactionByBlockNumberAndIndex
6463
*
6564
* @param blockNo block number from 0 to last
6665
* @param index tx index in block
@@ -71,8 +70,8 @@ public interface IProxyApi {
7170
Optional<TxProxy> tx(long blockNo, long index) throws ApiException;
7271

7372
/**
74-
* Returns the number of transactions in a block from a block matching the given
75-
* block number eth_getBlockTransactionCountByNumber
73+
* Returns the number of transactions in a block from a block matching the given block number
74+
* eth_getBlockTransactionCountByNumber
7675
*
7776
* @param blockNo block number from 0 to last
7877
* @return transaction amount in block
@@ -81,8 +80,7 @@ public interface IProxyApi {
8180
int txCount(long blockNo) throws ApiException;
8281

8382
/**
84-
* Returns the number of transactions sent from an address
85-
* eth_getTransactionCount
83+
* Returns the number of transactions sent from an address eth_getTransactionCount
8684
*
8785
* @param address eth address
8886
* @return transactions send amount from address
@@ -91,8 +89,8 @@ public interface IProxyApi {
9189
int txSendCount(String address) throws ApiException;
9290

9391
/**
94-
* Creates new message call transaction or a contract creation for signed
95-
* transactions eth_sendRawTransaction
92+
* Creates new message call transaction or a contract creation for signed transactions
93+
* eth_sendRawTransaction
9694
*
9795
* @param hexEncodedTx encoded hex data to send
9896
* @return optional string response
@@ -102,8 +100,7 @@ public interface IProxyApi {
102100
Optional<String> txSendRaw(String hexEncodedTx) throws ApiException;
103101

104102
/**
105-
* Returns the receipt of a transaction by transaction hash
106-
* eth_getTransactionReceipt
103+
* Returns the receipt of a transaction by transaction hash eth_getTransactionReceipt
107104
*
108105
* @param txhash transaction hash
109106
* @return optional tx receipt
@@ -113,8 +110,8 @@ public interface IProxyApi {
113110
Optional<ReceiptProxy> txReceipt(String txhash) throws ApiException;
114111

115112
/**
116-
* Executes a new message call immediately without creating a transaction on the
117-
* block chain eth_call
113+
* Executes a new message call immediately without creating a transaction on the block chain
114+
* eth_call
118115
*
119116
* @param address to call
120117
* @param data data to call address
@@ -135,8 +132,7 @@ public interface IProxyApi {
135132
Optional<String> code(String address) throws ApiException;
136133

137134
/**
138-
* (**experimental) Returns the value from a storage position at a given address
139-
* eth_getStorageAt
135+
* (**experimental) Returns the value from a storage position at a given address eth_getStorageAt
140136
*
141137
* @param address to get storage
142138
* @param position storage position
@@ -156,9 +152,8 @@ public interface IProxyApi {
156152
BigInteger gasPrice() throws ApiException;
157153

158154
/**
159-
* Makes a call or transaction, which won't be added to the blockchain and
160-
* returns the used gas, which can be used for estimating the used gas
161-
* eth_estimateGas
155+
* Makes a call or transaction, which won't be added to the blockchain and returns the used gas,
156+
* which can be used for estimating the used gas eth_estimateGas
162157
*
163158
* @param hexData data to calc gas usage for
164159
* @return estimated gas usage

‎src/main/java/io/api/etherscan/core/ITransactionApi.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
public interface ITransactionApi {
1616

1717
/**
18-
* Check Contract Execution Status (if there was an error during contract
19-
* execution)
18+
* Check Contract Execution Status (if there was an error during contract execution)
2019
*
2120
* @param txhash transaction hash
2221
* @return optional status result
@@ -26,8 +25,7 @@ public interface ITransactionApi {
2625
Optional<Status> execStatus(String txhash) throws ApiException;
2726

2827
/**
29-
* Check Transaction Receipt Status (Only applicable for Post Byzantium fork
30-
* transactions)
28+
* Check Transaction Receipt Status (Only applicable for Post Byzantium fork transactions)
3129
*
3230
* @param txhash transaction hash
3331
* @return 0 = Fail, 1 = Pass, empty value for pre-byzantium fork

‎src/main/java/io/api/etherscan/core/impl/EtherScanApi.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@
2020
* @author GoodforGod
2121
* @since 28.10.2018
2222
*/
23-
public class EtherScanApi {
23+
public class EtherScanApi implements AutoCloseable {
2424

2525
private static final Supplier<IHttpExecutor> DEFAULT_SUPPLIER = HttpExecutor::new;
2626

2727
public static final String DEFAULT_KEY = "YourApiKeyToken";
2828

29+
private final IQueueManager queueManager;
2930
private final IAccountApi account;
3031
private final IBlockApi block;
3132
private final IContractApi contract;
@@ -87,6 +88,7 @@ public EtherScanApi(final String apiKey,
8788
final String ending = EthNetwork.TOBALABA.equals(network) ? "com" : "io";
8889
final String baseUrl = "https://" + network.getDomain() + ".etherscan." + ending + "/api" + "?apikey=" + apiKey;
8990

91+
this.queueManager = queue;
9092
this.account = new AccountApiProvider(queue, baseUrl, executor);
9193
this.block = new BlockApiProvider(queue, baseUrl, executor);
9294
this.contract = new ContractApiProvider(queue, baseUrl, executor);
@@ -130,4 +132,9 @@ public IProxyApi proxy() {
130132
public IStatisticApi stats() {
131133
return stats;
132134
}
135+
136+
@Override
137+
public void close() throws Exception {
138+
queueManager.close();
139+
}
133140
}

‎src/main/java/io/api/etherscan/manager/IQueueManager.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package io.api.etherscan.manager;
22

33
/**
4-
* Queue manager to support API limits (EtherScan 5request\sec limit) Managers
5-
* grants turn if the limit is not exhausted And resets queue each set period
4+
* Queue manager to support API limits (EtherScan 5request\sec limit) Managers grants turn if the
5+
* limit is not exhausted And resets queue each set period
66
*
77
* @author GoodforGod
88
* @since 30.10.2018
99
*/
10-
public interface IQueueManager {
10+
public interface IQueueManager extends AutoCloseable {
1111

1212
/**
1313
* Waits in queue for chance to take turn

‎src/main/java/io/api/etherscan/manager/impl/FakeQueueManager.java

+5
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ public void takeTurn() {
1515
// no limit or await provided for fake impl so rate limit exception will be
1616
// thrown if too many calls
1717
}
18+
19+
@Override
20+
public void close() {
21+
// do nothing
22+
}
1823
}

‎src/main/java/io/api/etherscan/manager/impl/QueueManager.java

+30-6
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,53 @@
1212
* @author GoodforGod
1313
* @since 30.10.2018
1414
*/
15-
public class QueueManager implements IQueueManager {
15+
public class QueueManager implements IQueueManager, AutoCloseable {
1616

1717
public static final QueueManager DEFAULT_KEY_QUEUE = new QueueManager(1, 7);
18-
public static final QueueManager PERSONAL_KEY_QUEUE = new QueueManager(2, 1);
18+
public static final QueueManager PERSONAL_KEY_QUEUE = new QueueManager(5, 1100L, 1100L, 5);
1919

20+
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
2021
private final Semaphore semaphore;
22+
private final long queueResetTimeInMillis;
2123

2224
public QueueManager(int size, int resetInSec) {
2325
this(size, resetInSec, resetInSec);
2426
}
2527

2628
public QueueManager(int size, int queueResetTimeInSec, int delayInSec) {
27-
this.semaphore = new Semaphore(size);
28-
Executors.newSingleThreadScheduledExecutor()
29-
.scheduleAtFixedRate(releaseLocks(size), delayInSec, queueResetTimeInSec, TimeUnit.SECONDS);
29+
this(size, queueResetTimeInSec, delayInSec, size);
3030
}
3131

32+
public QueueManager(int size, int queueResetTimeInSec, int delayInSec, int initialSize) {
33+
this(size,
34+
(long) queueResetTimeInSec * 1000,
35+
(long) delayInSec * 1000,
36+
initialSize);
37+
}
38+
39+
public QueueManager(int size, long queueResetTimeInMillis, long delayInMillis, int initialSize) {
40+
this.queueResetTimeInMillis = queueResetTimeInMillis;
41+
this.semaphore = new Semaphore(initialSize);
42+
this.executorService.scheduleAtFixedRate(releaseLocks(size), delayInMillis, queueResetTimeInMillis,
43+
TimeUnit.MILLISECONDS);
44+
}
45+
46+
@SuppressWarnings("java:S899")
3247
@Override
3348
public void takeTurn() {
34-
semaphore.acquireUninterruptibly();
49+
try {
50+
semaphore.tryAcquire(queueResetTimeInMillis, TimeUnit.MILLISECONDS);
51+
} catch (InterruptedException e) {
52+
Thread.currentThread().interrupt();
53+
}
3554
}
3655

3756
private Runnable releaseLocks(int toRelease) {
3857
return () -> semaphore.release(toRelease);
3958
}
59+
60+
@Override
61+
public void close() {
62+
executorService.shutdown();
63+
}
4064
}

‎src/main/java/io/api/etherscan/model/Log.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,10 @@ public LocalDateTime getTimeStamp() {
6868
}
6969

7070
/**
71-
* Return the "timeStamp" field of the event record as a long-int representing
72-
* the milliseconds since the Unix epoch (1970-01-01 00:00:00).
71+
* Return the "timeStamp" field of the event record as a long-int representing the milliseconds
72+
* since the Unix epoch (1970-01-01 00:00:00).
7373
*
74-
* @return milliseconds between Unix epoch and `timeStamp`. If field is empty or
75-
* null, returns null
74+
* @return milliseconds between Unix epoch and `timeStamp`. If field is empty or null, returns null
7675
*/
7776
public Long getTimeStampAsMillis() {
7877
if (BasicUtils.isEmpty(timeStamp)) {

‎src/test/java/io/api/ApiRunner.java

+20-14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.api.etherscan.core.impl.EtherScanApi;
44
import io.api.etherscan.manager.impl.QueueManager;
55
import io.api.etherscan.model.EthNetwork;
6+
import org.junit.AfterClass;
67
import org.junit.Assert;
78

89
public class ApiRunner extends Assert {
@@ -11,26 +12,23 @@ public class ApiRunner extends Assert {
1112
private static final EtherScanApi apiRopsten;
1213
private static final EtherScanApi apiRinkeby;
1314
private static final EtherScanApi apiKovan;
14-
private static final String key;
15+
private static final String apiKey;
1516

1617
static {
17-
final String apiKey = System.getenv("API_KEY");
18-
key = (apiKey == null || apiKey.isEmpty())
18+
final String key = System.getenv("API_KEY");
19+
apiKey = (key == null || key.isEmpty())
1920
? EtherScanApi.DEFAULT_KEY
20-
: apiKey;
21+
: key;
2122

22-
final QueueManager queue = key.equals(EtherScanApi.DEFAULT_KEY)
23-
? QueueManager.DEFAULT_KEY_QUEUE
24-
: new QueueManager(1, 2);
25-
26-
api = new EtherScanApi(key, EthNetwork.MAINNET, queue);
27-
apiRopsten = new EtherScanApi(key, EthNetwork.ROPSTEN, queue);
28-
apiRinkeby = new EtherScanApi(key, EthNetwork.RINKEBY, queue);
29-
apiKovan = new EtherScanApi(key, EthNetwork.KOVAN, queue);
23+
final QueueManager queueManager = new QueueManager(1, 1200L, 1200L, 0);
24+
api = new EtherScanApi(ApiRunner.apiKey, EthNetwork.MAINNET, queueManager);
25+
apiKovan = new EtherScanApi(ApiRunner.apiKey, EthNetwork.KOVAN, queueManager);
26+
apiRopsten = new EtherScanApi(ApiRunner.apiKey, EthNetwork.ROPSTEN, queueManager);
27+
apiRinkeby = new EtherScanApi(ApiRunner.apiKey, EthNetwork.RINKEBY, queueManager);
3028
}
3129

32-
public static String getKey() {
33-
return key;
30+
public static String getApiKey() {
31+
return apiKey;
3432
}
3533

3634
public static EtherScanApi getApi() {
@@ -48,4 +46,12 @@ public static EtherScanApi getApiRinkeby() {
4846
public static EtherScanApi getApiKovan() {
4947
return apiKovan;
5048
}
49+
50+
@AfterClass
51+
public static void cleanup() throws Exception {
52+
api.close();
53+
apiRopsten.close();
54+
apiRinkeby.close();
55+
apiKovan.close();
56+
}
5157
}

‎src/test/java/io/api/etherscan/EtherScanApiTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public void noTimeoutUnlimitedAwait() {
7979
public void timeout() throws InterruptedException {
8080
TimeUnit.SECONDS.sleep(5);
8181
Supplier<IHttpExecutor> supplier = () -> new HttpExecutor(300, 300);
82-
EtherScanApi api = new EtherScanApi(getKey(), EthNetwork.KOVAN, supplier);
82+
EtherScanApi api = new EtherScanApi(getApiKey(), EthNetwork.KOVAN, supplier);
8383
List<Block> blocks = api.account().minedBlocks("0x0010f94b296A852aAac52EA6c5Ac72e03afD032D");
8484
assertNotNull(blocks);
8585
}

‎src/test/java/io/api/etherscan/proxy/ProxyBlockApiTest.java

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package io.api.etherscan.proxy;
22

33
import io.api.ApiRunner;
4+
import io.api.etherscan.core.impl.EtherScanApi;
5+
import io.api.etherscan.manager.impl.QueueManager;
6+
import io.api.etherscan.model.EthNetwork;
47
import io.api.etherscan.model.proxy.BlockProxy;
58
import org.junit.Test;
69

@@ -14,9 +17,16 @@
1417
*/
1518
public class ProxyBlockApiTest extends ApiRunner {
1619

20+
private final EtherScanApi api;
21+
22+
public ProxyBlockApiTest() {
23+
final QueueManager queueManager = new QueueManager(1, 5100L, 5100L, 0);
24+
this.api = new EtherScanApi(getApiKey(), EthNetwork.MAINNET, queueManager);
25+
}
26+
1727
@Test
1828
public void correct() {
19-
Optional<BlockProxy> block = getApi().proxy().block(5120);
29+
Optional<BlockProxy> block = api.proxy().block(5120);
2030
assertTrue(block.isPresent());
2131
BlockProxy proxy = block.get();
2232
assertNotNull(proxy.getHash());
@@ -49,13 +59,13 @@ public void correct() {
4959

5060
@Test
5161
public void correctParamWithEmptyExpectedResult() {
52-
Optional<BlockProxy> block = getApi().proxy().block(99999999999L);
62+
Optional<BlockProxy> block = api.proxy().block(99999999999L);
5363
assertFalse(block.isPresent());
5464
}
5565

5666
@Test
5767
public void correctParamNegativeNo() {
58-
Optional<BlockProxy> block = getApi().proxy().block(-1);
68+
Optional<BlockProxy> block = api.proxy().block(-1);
5969
assertTrue(block.isPresent());
6070
assertNotNull(block.get().getHash());
6171
}

‎src/test/java/io/api/etherscan/proxy/ProxyCallApiTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ public void correctParamWithEmptyExpectedResult() {
4141
Optional<String> call = getApi().proxy().call("0xAEEF16DB4855E25702F8237E8f403FddcaF931C0",
4242
"0x70a08231000000000000000000000000e16359506c028e51f16be38986ec5746251e9724");
4343
assertTrue(call.isPresent());
44-
assertFalse(BasicUtils.isNotHex(call.get()));
44+
assertFalse(call.get(), BasicUtils.isNotHex(call.get()));
4545
}
4646
}

‎src/test/java/io/api/etherscan/proxy/ProxyCodeApiTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ public class ProxyCodeApiTest extends ApiRunner {
1919
public void correct() {
2020
Optional<String> call = getApi().proxy().code("0xf75e354c5edc8efed9b59ee9f67a80845ade7d0c");
2121
assertTrue(call.isPresent());
22-
assertFalse(BasicUtils.isNotHex(call.get()));
22+
assertFalse(call.get(), BasicUtils.isNotHex(call.get()));
2323
}
2424

2525
@Test(expected = InvalidAddressException.class)
2626
public void invalidParamWithError() {
27-
Optional<String> call = getApi().proxy().code("0f75e354c5edc8efed9b59ee9f67a80845ade7d0c");
27+
getApi().proxy().code("0f75e354c5edc8efed9b59ee9f67a80845ade7d0c");
2828
}
2929

3030
@Test
3131
public void correctParamWithEmptyExpectedResult() {
3232
Optional<String> call = getApi().proxy().code("0xf15e354c5edc8efed9b59ee9f67a80845ade7d0c");
3333
assertTrue(call.isPresent());
34-
assertFalse(BasicUtils.isNotHex(call.get()));
34+
assertFalse(call.get(), BasicUtils.isNotHex(call.get()));
3535
}
3636
}

‎src/test/java/io/api/etherscan/proxy/ProxyStorageApiTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ public void correct() {
2424

2525
@Test(expected = InvalidAddressException.class)
2626
public void invalidParamWithError() {
27-
Optional<String> call = getApi().proxy().storageAt("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 0);
27+
getApi().proxy().storageAt("0xe03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 0);
2828
}
2929

3030
@Test
3131
public void correctParamWithEmptyExpectedResult() {
32-
Optional<String> call = getApi().proxy().storageAt("0x6e03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 100);
32+
final Optional<String> call = getApi().proxy().storageAt("0x6e03d9cce9d60f3e9f2597e13cd4c54c55330cfd", 10000);
3333
assertFalse(call.isPresent());
3434
}
3535
}

‎src/test/java/io/api/etherscan/proxy/ProxyTxCountApiTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ public void invalidParamWithError() {
3232
@Test
3333
public void correctParamWithEmptyExpectedResultBlockNoExist() {
3434
int count = getApi().proxy().txCount(99999999999L);
35-
assertEquals(0, count);
35+
assertNotEquals(1, count);
3636
}
3737

3838
@Test
3939
public void correctParamWithEmptyExpectedResult() {
4040
int count = getApi().proxy().txSendCount("0x1e03d9cce9d60f3e9f2597e13cd4c54c55330cfd");
41-
assertEquals(0, count);
41+
assertNotEquals(1, count);
4242
}
4343
}

0 commit comments

Comments
 (0)
Please sign in to comment.