Skip to content

Commit 2e281a6

Browse files
committed
minter 1.2-ready, updated tests, updated readme
1 parent 1b7bac5 commit 2e281a6

File tree

75 files changed

+1522
-986
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1522
-986
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
gradle/wrapper/gradle-wrapper.jar
1010
src/main/java/network/minter/blockchain/samples
1111
src/test/java/network/minter/blockchain/repos/SendTest.java
12+
src/test/java/network/minter/blockchain/utils/LocalTest.java

README.md

Lines changed: 62 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ project build.gradle
2424
```groovy
2525
2626
ext {
27-
minterBlockchainSDK = "0.13.1"
27+
minterBlockchainSDK = "1.0.0"
2828
}
2929
3030
dependencies {
@@ -41,41 +41,48 @@ dependencies {
4141

4242
Use our nodes
4343
```java
44-
MinterBlockChainApi.initialize();
44+
MinterBlockChainSDK.initialize();
4545
```
4646

4747
Or it's HIGHLY RECOMMENDED to use you own node instead of Minter's.
4848
```java
49-
MinterBlockChainApi.initialize("https://your-node.local");
49+
MinterBlockChainSDK.initialize("https://your-node.local");
5050
```
5151

5252
### 2. Creating and signing transactions
5353

5454
Transactions API uses **Builder** pattern, so it so easy to handle it.
5555

56-
All transactions requires a valid **nonce** value. Nonce - is a number of transaction. To get valid transaction number, you should get current number via `BlockChainAccountRepository#getTransactionCount` and increment it:
57-
5856
```java
59-
// init object with your Minter address
60-
MinterAddress myAddress = new MinterAddress("Mxccc3fc91a3d47dc1ee26d62611a09831f0214d62");
61-
62-
// get account repository from SDK singleton object
63-
BlockChainAccountRepository repo = MinterBlockChainApi.getInstance().account();
64-
65-
// send request
66-
repo.getTransactionCount(myAddress).enqueue(new Callback<BCResult<CountableData>>() {
67-
@Override
68-
public void onResponse(Call<BCResult<CountableData>> call, Response<BCResult<CountableData>> response) {
69-
BigInteger txCount = response.body().result.count;
70-
71-
// use this incremented value as nonce to your transaction
72-
BigInteger nonce = txCount.add(new BigInteger("1"));
57+
import io.reactivex.Scheduler;
58+
import io.reactivex.schedulers.Schedulers;
59+
import network.minter.blockchain.MinterBlockChainSDK;
60+
import network.minter.blockchain.repo.NodeTransactionRepository;
61+
class MyClass {
62+
63+
void myMethod() {
64+
Transaction tx = new Transaction.Builder(new BigInteger("1"))
65+
.setBlockchainId(BlockchainID.MainNet)
66+
.setGasCoinId(DEFAULT_COIN_ID)
67+
.sendCoin()
68+
.setCoinId(DEFAULT_COIN_ID)
69+
.setValue("0.012345")
70+
.setTo(toAddress)
71+
.build();
72+
73+
TransactionSign sign = tx.signSingle(privateKey);
74+
75+
NodeTransactionRepository txRepo = MinterBlockChainSDK.getInstance().transactions();
76+
txRepo.sendTransaction(sign)
77+
.observeOn(Schedulers.io())
78+
.subscribeOn(Scheduler.io())
79+
.subscribe(sendResult -> {
80+
System.out.println(sendResult.txHash.toString());
81+
}, throwable -> {
82+
// handle error
83+
});
7384
}
74-
75-
@Override
76-
public void onFailure(Call<BCResult<CountableData>> call, Throwable t) {
77-
}
78-
})
85+
}
7986
```
8087

8188
#### 2.1 Create "Send" transaction
@@ -98,14 +105,16 @@ final PrivateKey privateKey = PrivateKey.fromMnemonic("your phrase must contains
98105
Create transaction builder and build transaction:
99106
```java
100107
Transaction tx = new Transaction.Builder(nonce)
108+
// by default it depends on what sdk build type you used: with or without suffix "-testnet"
109+
.setBlockchainId(BlockchainID.MainNet)
101110
// optional: available for all transactions, but not useful for some transactions
102-
.setGasCoin("MNT")
111+
.setGasCoinId(DEFAULT_COIN_ID)
103112
// here you should select what transaction you are trying to create, builder will select exact type
104113
.sendCoin()
105-
// required: coin to send
106-
.setCoin(coin)
107-
// required: value to send
108-
.setValue("10")
114+
// required: coin to send represented by it's ID
115+
.setCoinId(DEFAULT_COIN_ID)
116+
// value to send
117+
.setValue("0.012345")
109118
// required: recipient address
110119
.setTo(toAddress)
111120
// finally, build object
@@ -115,40 +124,33 @@ Transaction tx = new Transaction.Builder(nonce)
115124
Sign transaction using your private key
116125
```java
117126
TransactionSign sign = tx.sign(privateKey);
118-
119-
// get transaction hash - this hash you'll send to blockchain
120-
String signedTransaction = sign.getTxSign();
121127
```
122128

123-
124-
So, it's easy, isn't? :)
125-
126129
For more transaction types see `OperationType` and class `Transaction.Builder`
127130

128131
Now we'll send transaction to blockchain.
129132

130133
#### 2.2 Send "send" transaction to the Minter blockchain
131134

132-
To send transaction to blockchain, we need to get `BlockChainAccountRepository` from `MinterBlockChainApi`
135+
To send transaction to blockchain, we need to get `NodeTransactionRepository` from `MinterBlockChainSDK`
133136

134137
```java
135-
BlockChainAccountRepository accountRepo = MinterBlockChainApi.getInstance().account();
138+
NodeTransactionRepository accountRepo = MinterBlockChainSDK.getInstance().transactions();
136139
```
137140

138141
To send transaction, you just need to call http request
139142
```java
140143
TransactionSign sign = ...
141-
accountRepo.sendTransaction(sign).enqueue(new Callback<BCResult<TransactionSendResult>>() {
142-
@Override
143-
public void onResponse(Call<BCResult<TransactionSendResult>> call, Response<BCResult<TransactionSendResult>> response) {
144-
// handle send result
145-
}
146144

147-
@Override
148-
public void onFailure(Call<BCResult<TransactionSendResult>> call, Throwable t) {
149-
// handle send error
150-
}
151-
})
145+
NodeTransactionRepository txRepo = MinterBlockChainSDK.getInstance().transactions();
146+
txRepo.sendTransaction(sign)
147+
.observeOn(Schedulers.io())
148+
.subscribeOn(Scheduler.io())
149+
.subscribe(sendResult -> {
150+
System.out.println(sendResult.txHash.toString());
151+
}, throwable -> {
152+
// handle error
153+
});
152154
```
153155

154156
That's all!
@@ -159,10 +161,21 @@ That's all!
159161
Javadoc available in code and in *.jar file at the bintray
160162

161163
## Build
162-
TODO
164+
To create local artifacts that you can find in your home `~/.m2` directory, just run:
165+
```bash
166+
bash project_root/publish_local.sh
167+
```
163168

164169
## Tests
165-
TODO
170+
171+
To run unit tests, you must build bip39 and secp256k1 with host target
172+
See: [bip39](https://github.com/edwardstock/bip3x) and [secp256k1-java](https://github.com/edwardstock/native-secp256k1-java)
173+
174+
All these test can be runned only with testnet configuration, don't use `gradlew test` directly
175+
```bash
176+
cd project_root
177+
./gradlew testNetTestDebugUnitTest -PnativeLibPath=/path/to/native/libs
178+
```
166179

167180
## Changelog
168181

RELEASE.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# Release notes
22

33
## 1.0.0
4-
- **BREAKING CHANGES**
5-
- Now communication with node api works with RxJava3
6-
- Base API response now in root of json, so BcResult<T> is just NodeResult and each response object inherits this class
4+
- **BREAKING CHANGES**
5+
- Renamed `MinterBlockChainApi` to `MinterBlockChainSDK`
6+
- Now communication with node api works with RxJava2
7+
- Base API response now in root of json, so BcResult<T> is just NodeResult and each response object inherits this class
8+
- Added `synchronized` blocks to methods uses native secp256k1 context
9+
- `CheckTransaction#sign()` now returns `MinterCheck` instead of `TransactionSign`
10+
- Added `CheckTransaction#validatePassword()` method to verify check password validity offline
711

812

913
## 0.13.1

build.gradle

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ buildscript {
3131
mavenLocal()
3232
}
3333
dependencies {
34-
classpath 'com.android.tools.build:gradle:4.0.1'
34+
classpath 'com.android.tools.build:gradle:4.1.0'
3535
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
3636
}
3737
}
@@ -61,9 +61,8 @@ version = '1.0.0'
6161

6262
ext {
6363
minterMinSdk = 16
64-
minterMaxSdk = 29
65-
minterBuildTools = "29.0.3"
66-
minterLibSupport = "28.0.0"
64+
minterMaxSdk = 30
65+
minterBuildTools = "30.0.2"
6766
minterCoreVers = "1.0.0"
6867

6968

@@ -168,15 +167,23 @@ android {
168167
// can't use name starts with 'test'
169168
netMain {
170169
dimension "env"
171-
buildConfigField "String", "BASE_NODE_URL", '"https://minter-node.apps.minter.network"'
170+
buildConfigField "String", "BASE_NODE_URL", '"https://minter-node.apps.minter.network/"'
171+
buildConfigField "String", "BASE_NODE_VERSION", '"v2"'
172172
buildConfigField "network.minter.blockchain.models.operational.BlockchainID", "BLOCKCHAIN_ID", "network.minter.blockchain.models.operational.BlockchainID.MainNet"
173173
}
174174
netTest {
175175
dimension "env"
176-
buildConfigField "String", "BASE_NODE_URL", '"https://minter-node-1.testnet.minter.network"'
176+
buildConfigField "String", "BASE_NODE_URL", '"https://node-api.testnet.minter.network/"'
177+
buildConfigField "String", "BASE_NODE_VERSION", '"v2"'
177178
buildConfigField "network.minter.blockchain.models.operational.BlockchainID", "BLOCKCHAIN_ID", "network.minter.blockchain.models.operational.BlockchainID.TestNet"
179+
buildConfigField "String", "QA_MNEMONIC", getProperty("minter_qa_mnemonic")
180+
buildConfigField "String", "TESTNET_MNEMONIC", getProperty("minter_testnet_mnemonic")
178181
}
179182
}
183+
184+
libraryVariants.all { variant ->
185+
variant.buildConfigField "String", "VERSION_NAME", '"' + version + '"'
186+
}
180187
}
181188

182189
dependencies {
@@ -188,12 +195,13 @@ dependencies {
188195
compileOnly 'com.google.code.findbugs:jsr305:3.0.2'
189196

190197
// network and rxjava
198+
implementation 'io.reactivex.rxjava2:rxjava:2.2.17'
199+
191200
implementation 'com.squareup.okhttp3:okhttp:4.8.1'
192201
implementation 'com.squareup.okhttp3:logging-interceptor:4.8.1'
193202
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
194203
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
195-
implementation 'io.reactivex.rxjava3:rxjava:3.0.5'
196-
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
204+
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
197205

198206
implementation 'org.parceler:parceler-api:1.1.13'
199207
annotationProcessor 'org.parceler:parceler:1.1.13'
@@ -206,8 +214,8 @@ dependencies {
206214
// testing
207215
testImplementation 'junit:junit:4.13'
208216
androidTestImplementation 'androidx.annotation:annotation:1.1.0'
209-
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
210-
androidTestImplementation 'androidx.test:rules:1.2.0'
217+
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
218+
androidTestImplementation 'androidx.test:rules:1.3.0'
211219
androidTestImplementation 'com.squareup.retrofit2:converter-gson:2.9.0'
212220
androidTestImplementation 'com.google.code.gson:gson:2.8.6'
213221
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2424
# THE SOFTWARE.
2525
#
26-
android.enableJetifier=true
26+
android.enableJetifier=false
2727
android.useAndroidX=true
2828
bintray_user=edwardstock
2929
bintray_license_name=MIT

gradle/wrapper/gradle-wrapper.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
# THE SOFTWARE.
2525
#
2626

27-
#Wed Feb 26 14:06:05 MSK 2020
27+
#Fri Oct 16 17:29:05 MSK 2020
2828
distributionBase=GRADLE_USER_HOME
2929
distributionPath=wrapper/dists
3030
zipStoreBase=GRADLE_USER_HOME
3131
zipStorePath=wrapper/dists
32-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
32+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip

src/main/java/network/minter/blockchain/MinterBlockChainSDK.java

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@
2828

2929
import com.google.gson.GsonBuilder;
3030

31+
import org.jetbrains.annotations.NotNull;
32+
33+
import java.io.IOException;
3134
import java.math.BigInteger;
3235

3336
import javax.annotation.Nonnull;
3437

35-
import io.reactivex.rxjava3.schedulers.Schedulers;
38+
import io.reactivex.schedulers.Schedulers;
3639
import network.minter.blockchain.repo.NodeAddressRepository;
3740
import network.minter.blockchain.repo.NodeBlockRepository;
3841
import network.minter.blockchain.repo.NodeCoinRepository;
@@ -53,18 +56,20 @@
5356
import network.minter.core.internal.common.Acceptor;
5457
import network.minter.core.internal.log.Mint;
5558
import network.minter.core.internal.log.TimberLogger;
59+
import okhttp3.Interceptor;
5660
import okhttp3.Request;
5761
import okhttp3.Response;
5862
import okhttp3.logging.HttpLoggingInterceptor;
5963
import retrofit2.Retrofit;
60-
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
64+
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
65+
6166

6267
/**
6368
* minter-android-blockchain. 2018
6469
* @author Eduard Maximovich <edward.vstock@gmail.com>
6570
*/
6671
public class MinterBlockChainSDK {
67-
private final static String BASE_NODE_URL = BuildConfig.BASE_NODE_URL;
72+
private final static String BASE_NODE_URL = BuildConfig.BASE_NODE_URL + BuildConfig.BASE_NODE_VERSION + "/";
6873
private static MinterBlockChainSDK INSTANCE;
6974
private final ApiService.Builder mApiService;
7075
private NodeAddressRepository mAccountRepository;
@@ -84,23 +89,13 @@ private MinterBlockChainSDK(@Nonnull String baseNodeApiUrl) {
8489
mApiService.setRetrofitClientConfig(new Acceptor<Retrofit.Builder>() {
8590
@Override
8691
public void accept(Retrofit.Builder builder) {
87-
builder.addCallAdapterFactory(RxJava3CallAdapterFactory.createWithScheduler(Schedulers.io()));
92+
builder.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()));
8893
}
8994
});
9095
mApiService.addHeader("Content-Type", "application/json");
9196
mApiService.addHeader("X-Minter-Client-Name", "MinterAndroid");
9297
mApiService.addHeader("X-Minter-Client-Version", BuildConfig.VERSION_NAME);
93-
mApiService.addHttpInterceptor(chain -> {
94-
Request request = chain.request();
95-
Response response = chain.proceed(request);
96-
if (response.body() != null && response.body().contentType() != null && response.body().contentType().toString().toLowerCase().equals("application/json")) {
97-
Response.Builder b = response.newBuilder();
98-
b.code(200);
99-
100-
return b.build();
101-
}
102-
return response;
103-
});
98+
mApiService.addHttpInterceptor(new ResponseErrorToResultInterceptor());
10499
}
105100

106101
public static void initialize() {
@@ -146,6 +141,10 @@ public static void initialize(boolean debug) {
146141
initialize(BASE_NODE_URL, debug, new TimberLogger());
147142
}
148143

144+
public static void initialize(boolean debug, Mint.Leaf logger) {
145+
initialize(BASE_NODE_URL, debug, logger);
146+
}
147+
149148
public static void initialize(String baseNodeApiUrl) {
150149
initialize(baseNodeApiUrl, false, new TimberLogger());
151150
}
@@ -227,4 +226,24 @@ public NodeCoinRepository coin() {
227226

228227
return mCoinRepository;
229228
}
229+
230+
/**
231+
* This class convert any HTTP error that contains valid json response to successful NodeResult response.
232+
* It was made to help handle error messages from service and avoid manual exception extraction error body and un-json it
233+
*/
234+
public static class ResponseErrorToResultInterceptor implements Interceptor {
235+
@NotNull
236+
@Override
237+
public Response intercept(@NotNull Chain chain) throws IOException {
238+
Request request = chain.request();
239+
Response response = chain.proceed(request);
240+
if (response.body() != null && response.body().contentType() != null && response.body().contentType().toString().toLowerCase().startsWith("application/json")) {
241+
Response.Builder b = response.newBuilder();
242+
b.code(200);
243+
244+
return b.build();
245+
}
246+
return response;
247+
}
248+
}
230249
}

0 commit comments

Comments
 (0)