Skip to content

Commit

Permalink
Merge pull request #69 from BaojunCZ/rc/v0.17.0
Browse files Browse the repository at this point in the history
v0.17.0
  • Loading branch information
BaojunCZ authored Jul 29, 2019
2 parents d992d56 + 67e7c86 commit 1702260
Show file tree
Hide file tree
Showing 16 changed files with 212 additions and 45 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# CHANGELOG

## 0.17.0

Support [ ckb release v0.17.0](https://github.com/nervosnetwork/ckb/releases/tag/v0.17.0)

### Feature

- Add hash_type to Script ([bd9007](https://github.com/BaojunCZ/ckb-sdk-dart/commit/bd900776e2dfdf1c955442f5601feda423e563c8)

- Update address format generator according recent RFC ([83ec45](https://github.com/BaojunCZ/ckb-sdk-dart/commit/83ec45168451f509942984b719eee6818fad32c6)

- Add get_cellbase_output_capacity_details rpc ([f845eb](https://github.com/BaojunCZ/ckb-sdk-dart/commit/f845ebdf8591d87ca72f4d69495480ba68cdbb75)

- Add get_header and get_header_by_number rpcs ([696fb4](https://github.com/BaojunCZ/ckb-sdk-dart/commit/696fb4d3db48c80d7c7c3a1bba11402c28f1752f))

- Add set_ban and get_banned_address rpcs ([2dd87c](https://github.com/BaojunCZ/ckb-sdk-dart/commit/2dd87cf22d12cb44de0f9fbce63b4c4e43e81f43))

## 0.16.0

Support [ ckb release v0.16.0](https://github.com/nervosnetwork/ckb/releases/tag/v0.16.0)
Expand Down
4 changes: 4 additions & 0 deletions lib/ckb_error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ class InvalidNumberOfWitnessesException implements Exception {
String toString() => "Check your inputs size and private key size";
}

class InvalidHashTypeException implements Exception {
String toString() => "Invalid hash type!";
}

class CommonException {
final String message;

Expand Down
2 changes: 2 additions & 0 deletions lib/ckb_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ part 'src/ckb_types/live_cell.dart';
part 'src/ckb_types/lock_hash_index_state.dart';
part 'src/ckb_types/transaction_by_lock_hash.dart';
part 'src/ckb_types/transaction_point.dart';
part 'src/ckb_types/cell_base_output_capacity.dart';
part 'src/ckb_types/banned_address.dart';
2 changes: 1 addition & 1 deletion lib/src/ckb_address/address_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ enum CKBNetwork { Mainnet, Testnet }

const String TYPE1 = "01";

const String BIN_IDX1 = "P2PH";
const String CODE_HASH_IDX = "00";

const String MainNetPrefix = "ckb";
const String TestNetPrefix = "ckt";
Expand Down
45 changes: 23 additions & 22 deletions lib/src/ckb_address/ckb_address.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ class CKBAddress {

CKBAddress(this.network);

String generate(String publicKey) {
// Payload: type(01) | bin-idx("P2PH") | pubkey blake160
String payload = TYPE1 + _binIdx(BIN_IDX1) + blake160(publicKey);
String generateFromPublicKey(String publicKey) {
return generate(blake160(publicKey));
}

String generate(String args) {
// Payload: type(01) | code hash index(00, P2PH) | pubkey blake160
String payload = TYPE1 + CODE_HASH_IDX + remove0x(args);
Uint8List data = hexStringToByteArray(payload);
Bech32Codec bech32codec = Bech32Codec();
return bech32codec.encode(Bech32(_prefix(), _convertBits(data, 8, 5, true)));
Expand All @@ -27,38 +31,35 @@ class CKBAddress {
Bech32 bech32 = parse(address);
String payload = hex.encode(bech32.data);
if (payload.startsWith(TYPE1)) {
return payload.replaceAll(TYPE1 + _binIdx(BIN_IDX1), "");
return payload.replaceAll(TYPE1 + CODE_HASH_IDX, "");
}
return null;
}

Uint8List _convertBits(Uint8List data, int fromBits, int toBits, bool pad) {
int length = pad ? data.length * fromBits ~/ toBits : (data.length * fromBits / toBits).ceil();
int mask = ((1 << toBits) - 1) & 0xff;
Uint8List result = Uint8List(length);
int index = 0;
int accumulator = 0;
int acc = 0;
int bits = 0;
int maxv = (1 << toBits) - 1;
List<int> ret = List<int>();
for (int i = 0; i < data.length; i++) {
int value = data[i];
accumulator = (((accumulator & 0xff) << fromBits) | (value & 0xff));
int b = data[i] & 0xff;
if ((b >> fromBits) > 0) {
throw Exception("Address format exception");
}
acc = (acc << fromBits) | b;
bits += fromBits;
while (bits >= toBits) {
bits -= toBits;
result[index] = (accumulator >> bits) & mask;
++index;
ret.add((acc >> bits) & maxv);
}
}
if (!pad) {
if (bits > 0) {
result[index] = (accumulator << (toBits - bits)) & mask;
}
} else {
if (!(bits < fromBits && ((accumulator << (toBits - bits)) & mask) == 0)) {
throw Exception("Strict mode was used but input couldn't be converted without padding");
}

if (pad && (bits > 0)) {
ret.add((acc << (toBits - bits)) & maxv);
} else if (bits >= fromBits || ((acc << (toBits - bits)) & maxv) != 0) {
throw Exception("Strict mode was used but input couldn't be converted without padding");
}
return result;
return Uint8List.fromList(ret);
}

String _prefix() => network == CKBNetwork.Mainnet ? MainNetPrefix : TestNetPrefix;
Expand Down
34 changes: 34 additions & 0 deletions lib/src/ckb_rpc/ckb_api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,21 @@ class CKBApiClient {
return result == null ? null : TransactionWithStatus.fromJson(result);
}

Future<CellbaseOutputCapacity> getCellbaseOutputCapacityDetails(String blockHash) async {
final result = await _request.requestRpc(ServiceUrl.cellbaseOutputCapacity, [blockHash]);
return result == null ? null : CellbaseOutputCapacity.fromJson(result);
}

Future<Header> getHeader(String blockHash) async {
final result = await _request.requestRpc(ServiceUrl.getHeader, [blockHash]);
return result == null ? null : Header.fromJson(result);
}

Future<Header> getHeaderByNumber(String blockNumber) async {
final result = await _request.requestRpc(ServiceUrl.getHeaderByNumber, [blockNumber]);
return result == null ? null : Header.fromJson(result);
}

//==========================Experiment RPC Methods==================================

Future<String> computeTransactionHash(Transaction transaction) async {
Expand Down Expand Up @@ -139,6 +154,25 @@ class CKBApiClient {
return result == null ? null : NodeInfo.fromJson(result);
}

Future setBan(BannedAddress bannedAddress) async {
await _request.requestRpc(ServiceUrl.setBan, [
bannedAddress.address,
bannedAddress.command,
bannedAddress.banTime,
bannedAddress.absolute,
bannedAddress.reason,
]);
}

Future<List<BannedAddress>> getBannedAddress() async {
final result = await _request.requestRpc(ServiceUrl.getBannerAddresses, []);
return result == null
? null
: (result as List)
?.map((e) => e == null ? null : BannedAddress.fromJson(e as Map<String, dynamic>))
?.toList();
}

//================================Pool RPC Methods===============================

Future<String> sendTransaction(Transaction transaction) async {
Expand Down
5 changes: 5 additions & 0 deletions lib/src/ckb_rpc/service_url.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class ServiceUrl {
static final tipBlockNumber = "get_tip_block_number";
static final tipHeader = "get_tip_header";
static final transaction = "get_transaction";
static final cellbaseOutputCapacity = "get_cellbase_output_capacity_details";
static final getHeader = "get_header";
static final getHeaderByNumber = "get_header_by_number";

//Experiment
static final computeTransactionHash = '_compute_transaction_hash';
Expand All @@ -27,6 +30,8 @@ class ServiceUrl {
//Net
static final getPeers = 'get_peers';
static final localNodeInfo = "local_node_info";
static final setBan = "set_ban";
static final getBannerAddresses = "get_banned_addresses";

//Pool
static final sendTransaction = "send_transaction";
Expand Down
27 changes: 27 additions & 0 deletions lib/src/ckb_types/banned_address.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
part of 'package:ckb_sdk/ckb_types.dart';

class BannedAddress {
String address;
String command;
String banTime;
String absolute;
String reason;

BannedAddress(this.address, this.command, this.banTime, this.absolute, this.reason);

factory BannedAddress.fromJson(Map<String, dynamic> json) => BannedAddress(
json['address'] as String,
json['command'] as String,
json['ban_time'] as String,
json['absolute'] as String,
json['reason'] as String,
);

Map<String, dynamic> toJson() => <String, dynamic>{
'address': address,
'command': command,
'ban_time': banTime,
'absolute': absolute,
'reason': reason,
};
}
8 changes: 0 additions & 8 deletions lib/src/ckb_types/block.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
/*
* @Author: BaojunCZ
* @Date: 2019-01-10 21:18:58
* @LastEditors: your name
* @LastEditTime: 2019-03-01 14:25:40
* @Description: file content
*/

part of 'package:ckb_sdk/ckb_types.dart';

class Block {
Expand Down
27 changes: 27 additions & 0 deletions lib/src/ckb_types/cell_base_output_capacity.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
part of 'package:ckb_sdk/ckb_types.dart';

class CellbaseOutputCapacity {
String primary;
String proposalReward;
String secondary;
String total;
String txFee;

CellbaseOutputCapacity(this.primary, this.proposalReward, this.secondary, this.total, this.txFee);

factory CellbaseOutputCapacity.fromJson(Map<String, dynamic> json) => CellbaseOutputCapacity(
json['primary'] as String,
json['proposal_reward'] as String,
json['secondary'] as String,
json['total'] as String,
json['tx_fee'] as String,
);

Map<String, dynamic> toJson() => <String, dynamic>{
'primary': primary,
'proposal_reward': proposalReward,
'secondary': secondary,
'total': total,
'tx_fee': txFee,
};
}
1 change: 1 addition & 0 deletions lib/src/ckb_types/header.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
part of 'package:ckb_sdk/ckb_types.dart';

class Header {
String dao;
String difficulty;
String hash;
String number;
Expand Down
19 changes: 18 additions & 1 deletion lib/src/ckb_types/script.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
part of 'package:ckb_sdk/ckb_types.dart';

class Script {
static const String DATA = "Data";
static const String TYPE = "Type";

String codeHash;
List<String> args;
String hashType;

Script(this.codeHash, this.args);
Script(this.codeHash, this.args, {this.hashType = DATA});

String get scriptHash {
final Blake2b blake2b = new Blake2b(digestSize: 32);
if (codeHash != null) blake2b.update(hex.decode(remove0x(codeHash)));

switch (hashType) {
case DATA:
blake2b.update(hexStringToByteArray("0"));
break;
case TYPE:
blake2b.update(hexStringToByteArray("1"));
break;
default:
throw new InvalidHashTypeException();
}
args.forEach((arg) {
blake2b.update(hexStringToByteArray(arg));
});
Expand All @@ -19,10 +34,12 @@ class Script {
factory Script.fromJson(Map<String, dynamic> json) => Script(
json['code_hash'] as String,
(json['args'] as List)?.map((e) => e as String)?.toList(),
hashType: json['hash_type'] as String,
);

Map<String, dynamic> toJson() => <String, dynamic>{
'code_hash': codeHash,
'args': args,
'hash_type': hashType,
};
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: ckb_sdk
version: 0.16.0
version: 0.17.0
author: "BaojunCZ<[email protected]>"
homepage: https://github.com/BaojunCZ/ckb-sdk-dart.git
description: Dart SDK for CKB.Nervos test network has not been released yet,so it is very early stage.Be careful when using this library.
Expand Down
20 changes: 10 additions & 10 deletions test/address/address_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ main() {

test('publicKey hash to address TestNet', () {
var ckbAddress = CKBAddress(CKBNetwork.Testnet);
var address =
ckbAddress.generate("390e45945092cbd81192cadd8ef268a398b49f521173d4c135f88893232b5c1af");
expect("ckt1q9gry5zgqnlmxcfvrjrm6m2ck2cmg9zev2rrpnnc3d940f", address);
var address = ckbAddress.generateFromPublicKey(
"0x024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01");
expect("ckt1qyqrdsefa43s6m882pcj53m4gdnj4k440axqswmu83", address);
});

test('publicKey hash to address MainNet', () {
var ckbAddress = CKBAddress(CKBNetwork.Mainnet);
var address =
ckbAddress.generate("0x024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01");
expect("ckb1q9gry5zgxmpjnmtrp4kww5r39frh2sm89tdt2l6vqdd7em", address);
var address = ckbAddress.generateFromPublicKey(
"0x024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01");
expect("ckb1qyqrdsefa43s6m882pcj53m4gdnj4k440axqdt9rtd", address);
});

test('privateKey to address TestNet', () {
var ckbAddress = CKBAddress(CKBNetwork.Testnet);
var address = ckbAddress.generate(bytesToHex(publicKeyFromPrivate(
var address = ckbAddress.generateFromPublicKey(bytesToHex(publicKeyFromPrivate(
hex.decode("e79f3207ea4980b7fed79956d5934249ceac4751a4fae01a0f7c4a96884bc4e3"))));
expect(address, "ckt1q9gry5zgxmpjnmtrp4kww5r39frh2sm89tdt2l6v234ygf");
expect(address, "ckt1qyqrdsefa43s6m882pcj53m4gdnj4k440axqswmu83");
});

test('address parse', () {
Expand All @@ -48,9 +48,9 @@ main() {
expect(hash, payload);
});

test('public key from address', () {
test('blake160 from address', () {
var ckbAddress = CKBAddress(CKBNetwork.Testnet);
String address = "ckt1q9gry5zgxmpjnmtrp4kww5r39frh2sm89tdt2l6v234ygf";
String address = "ckt1qyqrdsefa43s6m882pcj53m4gdnj4k440axqswmu83";
String publicKey = ckbAddress.blake160FromAddress(address);
expect(publicKey, "36c329ed630d6ce750712a477543672adab57f4c");
});
Expand Down
33 changes: 33 additions & 0 deletions test/api/chain_rpc_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,39 @@ main() {
}
});

test("get CellbaseOutputCapacityDetails", () async {
try {
CellbaseOutputCapacity cellbaseOutputCapacity =
await apiClient.getCellbaseOutputCapacityDetails(
'0xac1766e14aa988b41d6ac3fe8216a1ab83f10359ca34478a8c0902069cbb0296');
expect(cellbaseOutputCapacity != null, true);
} catch (error) {
print(error.toString());
expect(true, true);
}
});

test("get header", () async {
try {
Header header = await apiClient
.getHeader("0xac1766e14aa988b41d6ac3fe8216a1ab83f10359ca34478a8c0902069cbb0296");
expect(header != null, true);
} catch (error) {
print(error.toString());
expect(true, true);
}
});

test("get header by blockNumber", () async {
try {
Header header = await apiClient.getHeaderByNumber("1");
expect(header != null, true);
} catch (error) {
print(error.toString());
expect(true, true);
}
});

group("get transaction", () {
test("with right params", () async {
try {
Expand Down
Loading

0 comments on commit 1702260

Please sign in to comment.