Skip to content

Commit

Permalink
Merge pull request #377 from nervosnetwork/rc/v0.38.1
Browse files Browse the repository at this point in the history
Rc/v0.38.1
  • Loading branch information
duanyytop authored Dec 16, 2020
2 parents e8f5803 + 61867ce commit d1830ee
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 45 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [v0.38.1](https://github.com/nervosnetwork/ckb-sdk-java/compare/v0.38.0...v0.38.1) (2020-12-16)

### Feature

* Add anyone_can_pay short address([5585ad1](https://github.com/nervosnetwork/ckb-sdk-java/commit/5585ad159c329cc079c1170f3c2224d4e95abb99))
* Add note of indexer rpc deprecated([e6f91a9](https://github.com/nervosnetwork/ckb-sdk-java/commit/e6f91a99295928c641e5d566a70a4ad57dc2dc7f))

### BugFix

* Update interface RpcCallback public([b3f6b61](https://github.com/nervosnetwork/ckb-sdk-java/commit/b3f6b61e155aef3aa22e201408287ca4d253685e))

# [v0.38.0](https://github.com/nervosnetwork/ckb-sdk-java/compare/v0.37.1...v0.38.0) (2020-11-23)

Bump version to v0.38.0
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Java SDK for Nervos [CKB](https://github.com/nervosnetwork/ckb).

The ckb-sdk-java is still under development and **NOT** production ready. You should get familiar with CKB transaction structure and RPC before using it.

**Note: All RPC methods in the indexer module have been deprecated since CKB version `v0.36.0` and they will be removed in the near future.
As a temporary solution, you can set `enable_deprecated_rpc = true` in `ckb.toml`. We strongly recommend migrating to [ckb-indexer](https://github.com/nervosnetwork/ckb-indexer) as soon as possible.
You can refer to the [examples](https://github.com/nervosnetwork/ckb-sdk-java/tree/develop/example/src/main/java/org/nervos/ckb) of [ckb-indexer](https://github.com/nervosnetwork/ckb-indexer) in this project.**

### Prerequisites

* Java 8
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ allprojects {
targetCompatibility = 1.8

group 'org.nervos.ckb'
version '0.38.0'
version '0.38.1'
apply plugin: 'java'

repositories {
Expand Down Expand Up @@ -112,7 +112,7 @@ configure(subprojects.findAll { it.name != 'tests' }) {
publications {
mavenJava(MavenPublication) {
groupId 'org.nervos.ckb'
version '0.38.0'
version '0.38.1'
from components.java
}
}
Expand Down
2 changes: 1 addition & 1 deletion ckb/src/main/java/org/nervos/ckb/service/RpcCallback.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.nervos.ckb.service;

/** Copyright © 2019 Nervos Foundation. All rights reserved. */
interface RpcCallback<T> {
public interface RpcCallback<T> {

void onFailure(String errorMessage);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ class AddressBaseOperator {

static final String CODE_HASH_IDX_BLAKE160 = "00";
static final String CODE_HASH_IDX_MULTISIG = "01";
static final String CODE_HASH_IDX_ANYONE_CAN_PAY = "02";

static final String SECP_BLAKE160_CODE_HASH =
"9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8";
static final String MULTISIG_CODE_HASH =
"5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8";
static final String ACP_MAINNET_CODE_HASH =
"d369597ff47f29fbc0d47d2e3775370d1250b85140c670e4718af712983a2354";
static final String ACP_TESTNET_CODE_HASH =
"3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356";

static byte[] convertBits(List<Byte> data, int fromBits, int toBits, boolean pad)
throws AddressFormatException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,56 @@
package org.nervos.ckb.utils.address;

import java.util.Arrays;
import java.util.List;
import org.nervos.ckb.address.Network;
import org.nervos.ckb.exceptions.AddressFormatException;
import org.nervos.ckb.type.Script;
import org.nervos.ckb.utils.Bech32;
import org.nervos.ckb.utils.Numeric;

/** Copyright © 2019 Nervos Foundation. All rights reserved. */
public class AddressGenerator extends AddressBaseOperator {
private static final List<String> codeHashes =
Arrays.asList(
SECP_BLAKE160_CODE_HASH,
MULTISIG_CODE_HASH,
ACP_MAINNET_CODE_HASH,
ACP_TESTNET_CODE_HASH);

public static String generate(Network network, Script script) {
if (Script.TYPE.equals(script.hashType) && Numeric.cleanHexPrefix(script.args).length() == 40) {
if (SECP_BLAKE160_CODE_HASH.equals(Numeric.cleanHexPrefix(script.codeHash))) {
// Payload: type(01) | code hash index(00, P2PH) | args
String payload = TYPE_SHORT + CODE_HASH_IDX_BLAKE160 + Numeric.cleanHexPrefix(script.args);
byte[] data = Numeric.hexStringToByteArray(payload);
return Bech32.encode(
prefix(network),
convertBits(com.google.common.primitives.Bytes.asList(data), 8, 5, true));
} else if (MULTISIG_CODE_HASH.equals(Numeric.cleanHexPrefix(script.codeHash))) {
// Payload: type(01) | code hash index(01, multi-sig) | args
String payload = TYPE_SHORT + CODE_HASH_IDX_MULTISIG + Numeric.cleanHexPrefix(script.args);
byte[] data = Numeric.hexStringToByteArray(payload);
return Bech32.encode(
prefix(network),
convertBits(com.google.common.primitives.Bytes.asList(data), 8, 5, true));
} else {
return generateFullAddress(network, script);
}
String codeHash = Numeric.cleanHexPrefix(script.codeHash);
String args = Numeric.cleanHexPrefix(script.args);
if (Script.TYPE.equals(script.hashType)
&& args.length() >= 40
&& args.length() <= 44
&& codeHashes.contains(codeHash)) {
return generateShortAddress(network, codeHash, args);
}
return generateFullAddress(network, script);
}

private static String generateShortAddress(Network network, String codeHash, String args) {
// Payload: type(01) | code hash index(00, P2PH / 01, multi-sig / 02, anyone_can_pay) | args
String codeHashIndex = "";
if (ACP_MAINNET_CODE_HASH.equals(codeHash) || ACP_TESTNET_CODE_HASH.equals(codeHash)) {
codeHashIndex = CODE_HASH_IDX_ANYONE_CAN_PAY;
} else if (args.length() == 40) {
if (SECP_BLAKE160_CODE_HASH.equals(codeHash)) {
codeHashIndex = CODE_HASH_IDX_BLAKE160;
} else if (MULTISIG_CODE_HASH.equals(codeHash)) {
codeHashIndex = CODE_HASH_IDX_MULTISIG;
}
}
if (codeHashIndex.isEmpty()) {
throw new AddressFormatException("Code hash index of address format error");
}

String payload = TYPE_SHORT + codeHashIndex + args;
byte[] data = Numeric.hexStringToByteArray(payload);
return Bech32.encode(
prefix(network), convertBits(com.google.common.primitives.Bytes.asList(data), 8, 5, true));
}

public static String generateFullAddress(Network network, Script script) {
String type = Script.TYPE.equals(script.hashType) ? TYPE_FULL_TYPE : TYPE_FULL_DATA;
// Payload: type(02/04) | code hash | args
Expand Down
43 changes: 24 additions & 19 deletions ckb/src/main/java/org/nervos/ckb/utils/address/AddressParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,33 @@ public static AddressParseResult parse(String address) throws AddressFormatExcep
throw new AddressFormatException("Address bech32 decode fail");
}
String type = payload.substring(0, 2);
Network network = parseNetwork(address);
if (TYPE_SHORT.equals(type)) {
String codeHashIndex = payload.substring(2, 4);
String args = Numeric.prependHexPrefix(payload.substring(4));
if (Numeric.cleanHexPrefix(args).length() / 2 != 20) {
if (!codeHashIndex.equals(CODE_HASH_IDX_ANYONE_CAN_PAY)
&& Numeric.cleanHexPrefix(args).length() / 2 != 20) {
throw new AddressFormatException("Short address args byte length must be equal to 20");
}
if (CODE_HASH_IDX_BLAKE160.equals(codeHashIndex)) {
return new AddressParseResult(
parseNetwork(address),
new Script(Numeric.prependHexPrefix(SECP_BLAKE160_CODE_HASH), args, Script.TYPE),
AddressParseResult.Type.SHORT);
} else if (CODE_HASH_IDX_MULTISIG.equals(codeHashIndex)) {
return new AddressParseResult(
parseNetwork(address),
new Script(Numeric.prependHexPrefix(MULTISIG_CODE_HASH), args, Script.TYPE),
AddressParseResult.Type.SHORT);
} else {
throw new AddressFormatException("Short address code hash index must be 00 or 01");
switch (codeHashIndex) {
case CODE_HASH_IDX_BLAKE160:
return new AddressParseResult(
network,
new Script(Numeric.prependHexPrefix(SECP_BLAKE160_CODE_HASH), args, Script.TYPE),
AddressParseResult.Type.SHORT);
case CODE_HASH_IDX_MULTISIG:
return new AddressParseResult(
network,
new Script(Numeric.prependHexPrefix(MULTISIG_CODE_HASH), args, Script.TYPE),
AddressParseResult.Type.SHORT);
case CODE_HASH_IDX_ANYONE_CAN_PAY:
String codeHash =
Numeric.prependHexPrefix(
network == Network.MAINNET ? ACP_MAINNET_CODE_HASH : ACP_TESTNET_CODE_HASH);
return new AddressParseResult(
network, new Script(codeHash, args, Script.TYPE), AddressParseResult.Type.SHORT);
default:
throw new AddressFormatException("Short address code hash index must be 00, 01 or 02");
}
}

Expand All @@ -53,14 +62,10 @@ public static AddressParseResult parse(String address) throws AddressFormatExcep
String args = Numeric.prependHexPrefix(payload.substring(66));
if (TYPE_FULL_DATA.equals(type)) {
return new AddressParseResult(
parseNetwork(address),
new Script(codeHash, args, Script.DATA),
AddressParseResult.Type.FULL);
network, new Script(codeHash, args, Script.DATA), AddressParseResult.Type.FULL);
} else if (TYPE_FULL_TYPE.equals(type)) {
return new AddressParseResult(
parseNetwork(address),
new Script(codeHash, args, Script.TYPE),
AddressParseResult.Type.FULL);
network, new Script(codeHash, args, Script.TYPE), AddressParseResult.Type.FULL);
}
throw new AddressFormatException("Full address type must be 02 or 04");
}
Expand Down
22 changes: 22 additions & 0 deletions ckb/src/test/java/utils/AddressGeneratorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,28 @@ void testMultiSigShortMainnetAddressGenerate() {
Assertions.assertEquals("ckb1qyqlqn8vsj7r0a5rvya76tey9jd2rdnca8lq2sg8su", address);
}

@Test
void testACPShortTestnetAddressGenerate() {
Script acpShortScript =
new Script(
"0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
"0x81312ae06eeb0504b737e6bcfa5397be35a928de",
Script.TYPE);
String address = AddressGenerator.generate(Network.TESTNET, acpShortScript);
Assertions.assertEquals("ckt1qypgzvf2uphwkpgykum7d0862wtmuddf9r0qnzefn9", address);
}

@Test
void testACPShortMainnetAddressGenerate() {
Script acpShortScript =
new Script(
"0xd369597ff47f29fbc0d47d2e3775370d1250b85140c670e4718af712983a2354",
"0x81312ae06eeb0504b737e6bcfa5397be35a928de",
Script.TYPE);
String address = AddressGenerator.generate(Network.MAINNET, acpShortScript);
Assertions.assertEquals("ckb1qypgzvf2uphwkpgykum7d0862wtmuddf9r0qw88kle", address);
}

@Test
void testTypeFullTestnetAddressGenerate() {
Script typeFullScript =
Expand Down
32 changes: 31 additions & 1 deletion ckb/src/test/java/utils/AddressParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,36 @@ void testMultiSigShortMainnetAddressParse() {
Assertions.assertEquals(multiSigShortScript.hashType, addressParseResult.script.hashType);
}

@Test
void testACPShortTestnetAddressParse() {
String address = "ckt1qypgzvf2uphwkpgykum7d0862wtmuddf9r0qnzefn9";
Script multiSigShortScript =
new Script(
"0x3419a1c09eb2567f6552ee7a8ecffd64155cffe0f1796e6e61ec088d740c1356",
"0x81312ae06eeb0504b737e6bcfa5397be35a928de",
Script.TYPE);
AddressParseResult addressParseResult = AddressParser.parse(address);
Assertions.assertEquals(Network.TESTNET, addressParseResult.network);
Assertions.assertEquals(multiSigShortScript.args, addressParseResult.script.args);
Assertions.assertEquals(multiSigShortScript.codeHash, addressParseResult.script.codeHash);
Assertions.assertEquals(multiSigShortScript.hashType, addressParseResult.script.hashType);
}

@Test
void testACPShortMainnetAddressParse() {
String address = "ckb1qypgzvf2uphwkpgykum7d0862wtmuddf9r0qw88kle";
Script multiSigShortScript =
new Script(
"0xd369597ff47f29fbc0d47d2e3775370d1250b85140c670e4718af712983a2354",
"0x81312ae06eeb0504b737e6bcfa5397be35a928de",
Script.TYPE);
AddressParseResult addressParseResult = AddressParser.parse(address);
Assertions.assertEquals(Network.MAINNET, addressParseResult.network);
Assertions.assertEquals(multiSigShortScript.args, addressParseResult.script.args);
Assertions.assertEquals(multiSigShortScript.codeHash, addressParseResult.script.codeHash);
Assertions.assertEquals(multiSigShortScript.hashType, addressParseResult.script.hashType);
}

@Test
void testTypeFullTestnetAddressParse() {
String address =
Expand Down Expand Up @@ -180,7 +210,7 @@ public void execute() throws Throwable {
}
});
Assertions.assertTrue(
exception.getMessage().contains("Short address code hash index must be 00 or 01"));
exception.getMessage().contains("Short address code hash index must be 00, 01 or 02"));
}

@Test
Expand Down
16 changes: 13 additions & 3 deletions utils/src/main/java/org/nervos/ckb/address/AddressUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class AddressUtils {
private static final String TYPE = "01"; // short address format
private static final String CODE_HASH_IDX_BLAKE160 = "00";
private static final String CODE_HASH_IDX_MULTISIG = "01";
private static final String CODE_HASH_IDX_ACP = "02";

private Network network;
private CodeHashType codeHashType;
Expand All @@ -34,16 +35,25 @@ public AddressUtils(Network network) {
this.codeHashType = CodeHashType.BLAKE160;
}

private String getCodeHashIdx() {
return codeHashType == CodeHashType.BLAKE160 ? CODE_HASH_IDX_BLAKE160 : CODE_HASH_IDX_MULTISIG;
private String getCodeHashIdx() throws AddressFormatException {
switch (codeHashType) {
case BLAKE160:
return CODE_HASH_IDX_BLAKE160;
case MULTISIG:
return CODE_HASH_IDX_MULTISIG;
case ANYONE_CAN_APY:
return CODE_HASH_IDX_ACP;
default:
throw new AddressFormatException("Code hash index error");
}
}

public String generateFromPublicKey(String publicKey) throws AddressFormatException {
return generate(Hash.blake160(publicKey));
}

public String generate(String args) throws AddressFormatException {
// Payload: type(01) | code hash index(00, P2PH /01, multi sig) | args
// Payload: type(01) | code hash index(00, P2PH /01, multi sig /02, ACP) | args
String payload = TYPE + getCodeHashIdx() + Numeric.cleanHexPrefix(args);
byte[] data = Numeric.hexStringToByteArray(payload);
return Bech32.encode(prefix(), convertBits(Bytes.asList(data), 8, 5, true));
Expand Down
3 changes: 2 additions & 1 deletion utils/src/main/java/org/nervos/ckb/address/CodeHashType.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
/** Copyright © 2019 Nervos Foundation. All rights reserved. */
public enum CodeHashType {
BLAKE160,
MULTISIG
MULTISIG,
ANYONE_CAN_APY
}
27 changes: 27 additions & 0 deletions utils/src/test/java/org/nervos/ckb/address/AddressTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,33 @@ public void testArgToAddressTestnet() throws AddressFormatException {
Assertions.assertEquals(expected, actual);
}

@Test
public void testArgToAddressTestnet1() throws AddressFormatException {
String expected = "ckt1qypgzvf2uphwkpgykum7d0862wtmuddf9r0qnzefn9";
String args = "0x81312ae06eeb0504b737e6bcfa5397be35a928de";
AddressUtils utils = new AddressUtils(Network.TESTNET, CodeHashType.ANYONE_CAN_APY);
String actual = utils.generate(args);
Assertions.assertEquals(expected, actual);
}

@Test
public void testArgToAddressMainnet() throws AddressFormatException {
String expected = "ckb1qypgzvf2uphwkpgykum7d0862wtmuddf9r0qw88kle";
String args = "0x81312ae06eeb0504b737e6bcfa5397be35a928de";
AddressUtils utils = new AddressUtils(Network.MAINNET, CodeHashType.ANYONE_CAN_APY);
String actual = utils.generate(args);
Assertions.assertEquals(expected, actual);
}

@Test
public void testArgToAddressMainnet1() throws AddressFormatException {
String expected = "ckb1qyqrdsefa43s6m882pcj53m4gdnj4k440axqdt9rtd";
String args = "36c329ed630d6ce750712a477543672adab57f4c";
AddressUtils utils = new AddressUtils(Network.MAINNET, CodeHashType.BLAKE160);
String actual = utils.generate(args);
Assertions.assertEquals(expected, actual);
}

@Test
public void testPublicKeyHashToAddressTestnet() {
AddressUtils utils = new AddressUtils(Network.TESTNET);
Expand Down

0 comments on commit d1830ee

Please sign in to comment.