Skip to content

Commit

Permalink
fix gradle build failed (#19)
Browse files Browse the repository at this point in the history
* fix gradle build failed

* add json Annotation for Address

* throw  AddressType exeption stack

* add doc about SDK updates

Co-authored-by: PanaW <wangpan@conflux-chain.org>
  • Loading branch information
Pana and PanaW authored Jan 29, 2021
1 parent 8037936 commit a03c185
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 41 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The Conflux Java SDK allows any Java client to interact with a local or remote C
## Docs

* [API](https://conflux-chain.github.io/java-conflux-sdk/index.html)
* [SDK updates for CIP37](./docs/cfx-address.md)
* [changelog](./CHANGELOG.md)

## Conflux Address
Expand Down Expand Up @@ -43,7 +44,7 @@ public class App {
public static void main(String[] args) throws Exception {
String privateKey = "0xxxxxx";
// Initialize a accountManager
AccountManager am = new AccountManager();
AccountManager am = new AccountManager(testNetId);
// import private key
am.imports(privateKey, "123456");
// import a keystore file
Expand Down
13 changes: 9 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ repositories {
// Use jcenter for resolving dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
// mavenCentral()
}

dependencies {
Expand All @@ -24,10 +25,14 @@ dependencies {
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:28.0-jre'

compile 'org.web3j:core:4.6.3'

// Use JUnit test framework
testImplementation 'junit:junit:4.12'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'

compile 'org.web3j:core:4.6.3'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2'
}

test {
useJUnitPlatform()
}
144 changes: 142 additions & 2 deletions docs/cfx-address.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,142 @@
CIP37 address
===
java-sdk support for CIP37 address
===
As a new public chain, Conflux realizes high performance as well as compatibility with Ethereum. Conflux adopts address format compatible with Ethereum addresses, and thus is compatible with Ethereum Virtual Machine (EVM).
The advantage of the compatibility between Conflux and Ethereum is obvious: it reduces the cost and difficulty of cross-chain migration. But there are also some problems. Since the addresses on Conflux and Ethereum are similar, users may loss their assets when performing cross-chain transactions using ShuttleFlow if they transfer to a mistake address, which is a serious problem. To improve user experience and reduce address mistakes when users use cross-chain functions, Conflux introduces a new address format: base32Check in [CIP37](https://github.com/Conflux-Chain/CIPs/blob/master/CIPs/cip-37.md).

### Before CIP37
At first, Conflux adopts the address format similar with Ethereum, which is a hex40 address (hex code with a length of 40 bits). The difference is that Conflux differentiate the addresses with different starts: 0x1 for ordinary individual addresses, 0x8 for smart contracts and 0x0 for in-built contracts.

Only hex40 addresses with these three starts are available on Conflux. Some Ethereum addresses (with a 0x1 start) can be used as Conflux addresses, while a Conflux address has a 1/16 chance of being used as an Ethereum address.

Currently, there are three kinds of addresses:

* Ordinary addresses: `0x1`386b4185a223ef49592233b69291bbe5a80c527
* Smart contract addresses: `0x8`269f0add11b4915d78791470d091d25cff73ee5
* In-built contract addresses: `0x0`888000000000000000000000000000000000002

Because the addresses are not completely compatible on Conflux and Ethereum, users will loss assets when they use a wrong address. Ethereum has introduced a regulation with a checksum in [EIP55](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md) to change the characters meeting the requirement into the upper case in order to prevent transferring to wrong addresses. Conflux also introduces regulations to change checksums.

* Non-chechsum address: 0x1386`b`4185`a`223`ef`49592233b69291bbe5a80`c`527
* Chechsum address: 0x1386`B`4185`A`223`EF`49592233b69291bbe5a80`C`527



### CIP37 Address
In order to solve the problems of mistakenly using wrong addresses, we introduces a brand new base32 checksum address format in [CIP37](https://github.com/Conflux-Chain/CIPs/blob/master/CIPs/cip-37.md). Besides checksum, the new addresses also include information such as network, type.

Old address vs new address:

* hex40 address: `0x1`386b4185a223ef49592233b69291bbe5a80c527
* base32 address: cfx:aak2rra2njvd77ezwjvx04kkds9fzagfe6ku8scz91

The new addresses use customized base32 code address. Currently applied characters are: `abcdefghjkmnprstuvwxyz0123456789` (i, l, o, q removed).

In new format addresses, network types are included. Up to now there are three types: cfx,cfxtest,net[n]

* cfx:aak2rra2njvd77ezwjvx04kkds9fzagfe6ku8scz91
* cfxtest:aak2rra2njvd77ezwjvx04kkds9fzagfe6d5r8e957
* net1921:aak2rra2njvd77ezwjvx04kkds9fzagfe65k87kwdf

Meanwhile, new addresses also include address type information, currently four types (types are usually in upper case):

* user: CFX:TYPE.USER:AAK2RRA2NJVD77EZWJVX04KKDS9FZAGFE6KU8SCZ91
* contract: CFX:TYPE.CONTRACT:ACB2RRA2NJVD77EZWJVX04KKDS9FZAGFE640XW9UAE
* builtin: CFX:TYPE.BUILTIN:AAEJUAAAAAAAAAAAAAAAAAAAAAAAAAAAAJRWUC9JNB
* null: CFX:TYPE.NULL:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0SFBNJM2

The two address formats (hex40 and base32) are convertible to each other. They are the same if converted to byte arrays. However, when converting hex40 addresses (starting with 0x) into base32check addresses, the network ID information is also required.



### Conflux Fullnode RPC
From v1.1.1, Conflux-rust will apply the new address format. If returns include address information, it will be in the new format.

If you use hex40 addresses to call RPC, it will return with an error:
```js
{
"code": -32602,
"message": "Invalid params: Invalid base32 address: zero or multiple prefixes."
}
```

If you use a wrong network type (eg. use a testnet address for the mainnet PRC), it will return with an error:
```js
{
"code": -32602,
"message": "Invalid parameters: address",
"data": "\"network prefix unexpected: ours cfx, got cfxtest\""
}
```



### Address
There was only the validate method in the Address class used for checking the format and type of hex40 addresses.
In v1.0, the method will be moved to `AddressType.validateHexAddress`.

##### Create an instance

```java
import conflux.web3j.types.Address;

// Initializing with the new address format
Address address = new Address("cfx:aajg4wt2mbmbb44sp6szd783ry0jtad5bea80xdy7p");
// Initializing with hex40 address and netID
new Address("0x106d49f8505410eb4e671d51f7d96d2c87807b09", 1);
```

##### Instance method

```java
address.getAddress(); // get a base32 address
// cfx:aajg4wt2mbmbb44sp6szd783ry0jtad5bea80xdy7p
address.getVerboseAddress(); // get a base32 address with type info
// CFX:TYPE.USER:AAJG4WT2MBMBB44SP6SZD783RY0JTAD5BEA80XDY7P
address.getNetworkId(); // get networkId mainnet is 1029, testnet is 1
// 1
address.getType(); // get address type
// user
address.getHexAddress(); // get hex40 address
// 0x106d49f8505410eb4e671d51f7d96d2c87807b09
address.getABIAddress(); // get a org.web3j.abi.datatypes.Address instance
// get a org.web3j.abi.datatypes.Address instance
```

In v1.0, the Address class can be used to instantiate addresses, and the address can be used anywhere it is needed, including:
1. RPC, request parameters and return results
2. Account, AccountManager related methods
3. RawTransaction, TransactionBuilder related methods
4. Call, ContractCall, ERC20, ERC777 related methods

### networkId
When converting hex40 addresses to base32 addresses, networkId is required. The current networkId is the same with the chainId value, 1029 for the mainnet and 1 for the testnet.

##### fullnode
* `cfx_getStatus` method returns with `networkId` field additionally.

##### Interface `Cfx`
Methods to get chainId and networkId from the instance are added:
* `getNetworkId()`
* `getChainId()`

##### AccountManager
AccountManager instantiation requires to send `networkId`.


### Contract Interaction

##### Address configuration in contract method
If address is needed when calling contract method, there are two ways to get address:
1. Create an Address instance, and call `getABIAddress()` method to get ABI encoded address types
```java
import conflux.web3j.types.Address;
Address a = new Address("0x106d49f8505410eb4e671d51f7d96d2c87807b09", 1);
a.getABIAddress()
```
2. If the address is an Ethereum address, ABI encoded address needs to be created manually
```java
import org.web3j.abi.datatypes.Address;
new Address("0x206d49f8505410eb4e671d51f7d96d2c87807b09");
```

When decoding the address returned by the contract, `org.web3j.abi.datatypes.Address` is required, and then set networkId and convert the address to the base32 format if necessary.
48 changes: 24 additions & 24 deletions src/main/java/conflux/web3j/Web3j.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,87 +85,87 @@ public Request<BigInteger, BigIntResponse> getEpochNumber(Epoch... epoch) {
@Override
public Request<BigInteger, BigIntResponse> getBalance(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getBalance", BigIntResponse.class, address.getAddress())
return new Request<>(this.service, "cfx_getBalance", BigIntResponse.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getBalance", BigIntResponse.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getBalance", BigIntResponse.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}

@Override
public Request<Optional<String>, StringNullableResponse> getAdmin(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getAdmin", StringNullableResponse.class, address.getAddress())
return new Request<>(this.service, "cfx_getAdmin", StringNullableResponse.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getAdmin", StringNullableResponse.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getAdmin", StringNullableResponse.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}

@Override
public Request<SponsorInfo, SponsorInfo.Response> getSponsorInfo(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getSponsorInfo", SponsorInfo.Response.class, address.getAddress())
return new Request<>(this.service, "cfx_getSponsorInfo", SponsorInfo.Response.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getSponsorInfo", SponsorInfo.Response.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getSponsorInfo", SponsorInfo.Response.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}

@Override
public Request<BigInteger, BigIntResponse> getStakingBalance(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getStakingBalance", BigIntResponse.class, address.getAddress())
return new Request<>(this.service, "cfx_getStakingBalance", BigIntResponse.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getStakingBalance", BigIntResponse.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getStakingBalance", BigIntResponse.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}

@Override
public Request<BigInteger, BigIntResponse> getCollateralForStorage(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getCollateralForStorage", BigIntResponse.class, address.getAddress())
return new Request<>(this.service, "cfx_getCollateralForStorage", BigIntResponse.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getCollateralForStorage", BigIntResponse.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getCollateralForStorage", BigIntResponse.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}

@Override
public Request<String, StringResponse> getCode(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getCode", StringResponse.class, address.getAddress())
return new Request<>(this.service, "cfx_getCode", StringResponse.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getCode", StringResponse.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getCode", StringResponse.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}

@Override
public Request<Optional<String>, StringNullableResponse> getStorageAt(Address address, String pos, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getStorageAt", StringNullableResponse.class, address.getAddress(), pos)
return new Request<>(this.service, "cfx_getStorageAt", StringNullableResponse.class, address, pos)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getStorageAt", StringNullableResponse.class, address.getAddress(), pos, epoch[0].getValue())
return new Request<>(this.service, "cfx_getStorageAt", StringNullableResponse.class, address, pos, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}

@Override
public Request<Optional<StorageRoot>, StorageRoot.Response> getStorageRoot(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getStorageRoot", StorageRoot.Response.class, address.getAddress())
return new Request<>(this.service, "cfx_getStorageRoot", StorageRoot.Response.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getStorageRoot", StorageRoot.Response.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getStorageRoot", StorageRoot.Response.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}
Expand Down Expand Up @@ -203,10 +203,10 @@ public Request<String, StringResponse> getBestBlockHash() {
@Override
public Request<BigInteger, BigIntResponse> getNonce(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getNextNonce", BigIntResponse.class, address.getAddress())
return new Request<>(this.service, "cfx_getNextNonce", BigIntResponse.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getNextNonce", BigIntResponse.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getNextNonce", BigIntResponse.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}
Expand Down Expand Up @@ -272,10 +272,10 @@ public Request<Optional<Receipt>, Receipt.Response> getTransactionReceipt(String
@Override
public Request<AccountInfo, AccountInfo.Response> getAccount(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getAccount", AccountInfo.Response.class, address.getAddress())
return new Request<>(this.service, "cfx_getAccount", AccountInfo.Response.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getAccount", AccountInfo.Response.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getAccount", AccountInfo.Response.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}
Expand Down Expand Up @@ -341,21 +341,21 @@ public Request<String, StringResponse> getClientVersion() {
@Override
public Request<List<DepositInfo>, DepositInfo.ListResponse> getDepositList(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getDepositList", DepositInfo.ListResponse.class, address.getAddress())
return new Request<>(this.service, "cfx_getDepositList", DepositInfo.ListResponse.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getDepositList", DepositInfo.ListResponse.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getDepositList", DepositInfo.ListResponse.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}

@Override
public Request<List<VoteStakeInfo>, VoteStakeInfo.ListResponse> getVoteList(Address address, Epoch... epoch) {
if (epoch.length == 0) {
return new Request<>(this.service, "cfx_getVoteList", VoteStakeInfo.ListResponse.class, address.getAddress())
return new Request<>(this.service, "cfx_getVoteList", VoteStakeInfo.ListResponse.class, address)
.withRetry(this.retry, this.intervalMillis);
} else {
return new Request<>(this.service, "cfx_getVoteList", VoteStakeInfo.ListResponse.class, address.getAddress(), epoch[0].getValue())
return new Request<>(this.service, "cfx_getVoteList", VoteStakeInfo.ListResponse.class, address, epoch[0].getValue())
.withRetry(this.retry, this.intervalMillis);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/conflux/web3j/request/LogFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class LogFilter {
private Epoch fromEpoch;
private Epoch toEpoch;
private List<String> blockHashes;
private List<String> address;
private List<Address> address;
private List<List<String>> topics;
private Long limit;

Expand Down Expand Up @@ -39,12 +39,12 @@ public void setBlockHashes(List<String> blockHashes) {
this.blockHashes = blockHashes;
}

public List<String> getAddress() {
public List<Address> getAddress() {
return address;
}

public void setAddress(List<Address> address) {
this.address = address.stream().map(a -> a.getAddress()).collect(Collectors.toList());
this.address = address;
}

public List<List<String>> getTopics() {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/conflux/web3j/types/Address.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package conflux.web3j.types;

import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.io.BaseEncoding;
import com.google.common.primitives.Bytes;
import conflux.web3j.crypto.ConfluxBase32;
Expand Down Expand Up @@ -38,6 +39,7 @@ public Address(byte[] addressBuffer, int netId) throws AddressException {
this.hexAddress = "0x" + BaseEncoding.base16().encode(addressBuffer).toLowerCase();
}

@JsonValue
public String getAddress() {
return address;
}
Expand Down
Loading

0 comments on commit a03c185

Please sign in to comment.