From 853c0906952df82286f32b4d42e0697fdf66d073 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Jan 2023 16:10:12 +0000 Subject: [PATCH 01/29] chore(deps): bump gson from 2.9.1 to 2.10.1 Bumps [gson](https://github.com/google/gson) from 2.9.1 to 2.10.1. - [Release notes](https://github.com/google/gson/releases) - [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/gson/compare/gson-parent-2.9.1...gson-parent-2.10.1) --- updated-dependencies: - dependency-name: com.google.code.gson:gson dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5e7dbd9b..a40a34df 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext.bouncycastleVersion = '1.65' ext.rxjavaVersion = '2.2.21' - ext.gsonVersion = '2.9.1' + ext.gsonVersion = '2.10.1' ext.okhttpVersion = '4.10.0' ext.loggingOkhttpVersion = '4.10.0' ext.slf4jVersion = '2.0.0' From cb541e7a20fc53b0f18c8d78336b26f4ac6a9954 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Jan 2023 16:10:20 +0000 Subject: [PATCH 02/29] chore(deps): bump junitVersion from 5.9.0 to 5.9.2 Bumps `junitVersion` from 5.9.0 to 5.9.2. Updates `junit-jupiter-api` from 5.9.0 to 5.9.2 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.2) Updates `junit-jupiter-engine` from 5.9.0 to 5.9.2 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.2) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- ckb-indexer/build.gradle | 4 ++-- ckb-mercury-sdk/build.gradle | 4 ++-- light-client/build.gradle | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index a40a34df..3ecd1846 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { ext.loggingOkhttpVersion = '4.10.0' ext.slf4jVersion = '2.0.0' ext.guavaVersion = '31.1-jre' - ext.junitVersion = '5.9.0' + ext.junitVersion = '5.9.2' repositories { jcenter() diff --git a/ckb-indexer/build.gradle b/ckb-indexer/build.gradle index 9adc9fcd..f04bf0ff 100644 --- a/ckb-indexer/build.gradle +++ b/ckb-indexer/build.gradle @@ -3,8 +3,8 @@ description 'SDK for CKB indexer' dependencies { compile project(":core") - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2' // Enable use of the JUnitPlatform Runner within the IDE testImplementation("org.junit.platform:junit-platform-runner:1.9.0") diff --git a/ckb-mercury-sdk/build.gradle b/ckb-mercury-sdk/build.gradle index 3fba88f2..1cac7872 100644 --- a/ckb-mercury-sdk/build.gradle +++ b/ckb-mercury-sdk/build.gradle @@ -4,8 +4,8 @@ dependencies { compile project(":core") compile project(":ckb-indexer") testImplementation project(":ckb") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.0") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") // Enable use of the JUnitPlatform Runner within the IDE testImplementation("org.junit.platform:junit-platform-runner:1.9.0") } diff --git a/light-client/build.gradle b/light-client/build.gradle index affbfdef..f488adaf 100644 --- a/light-client/build.gradle +++ b/light-client/build.gradle @@ -11,8 +11,8 @@ repositories { dependencies { implementation project(":ckb-indexer") - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2' } test { From bad2ded3ede7db61b3f8cb26e8c14fd8b3c57ff5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Jan 2023 16:10:22 +0000 Subject: [PATCH 03/29] chore(deps): bump junit-platform-runner from 1.9.0 to 1.9.2 Bumps [junit-platform-runner](https://github.com/junit-team/junit5) from 1.9.0 to 1.9.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/commits) --- updated-dependencies: - dependency-name: org.junit.platform:junit-platform-runner dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- ckb-indexer/build.gradle | 2 +- ckb-mercury-sdk/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ckb-indexer/build.gradle b/ckb-indexer/build.gradle index f04bf0ff..27e52507 100644 --- a/ckb-indexer/build.gradle +++ b/ckb-indexer/build.gradle @@ -7,7 +7,7 @@ dependencies { testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2' // Enable use of the JUnitPlatform Runner within the IDE - testImplementation("org.junit.platform:junit-platform-runner:1.9.0") + testImplementation("org.junit.platform:junit-platform-runner:1.9.2") } test { diff --git a/ckb-mercury-sdk/build.gradle b/ckb-mercury-sdk/build.gradle index 1cac7872..fab57842 100644 --- a/ckb-mercury-sdk/build.gradle +++ b/ckb-mercury-sdk/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") // Enable use of the JUnitPlatform Runner within the IDE - testImplementation("org.junit.platform:junit-platform-runner:1.9.0") + testImplementation("org.junit.platform:junit-platform-runner:1.9.2") } test { From ba262fb01956a6a2cb30d7ff88345ca54a2be508 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:56:30 +0000 Subject: [PATCH 04/29] chore(deps): bump com.github.johnrengelman.shadow from 6.1.0 to 8.1.1 Bumps com.github.johnrengelman.shadow from 6.1.0 to 8.1.1. --- updated-dependencies: - dependency-name: com.github.johnrengelman.shadow dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3ecd1846..0519a3d3 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ buildscript { } plugins { - id 'com.github.johnrengelman.shadow' version '6.1.0' + id 'com.github.johnrengelman.shadow' version '8.1.1' id 'java' id 'com.jfrog.bintray' version '1.8.5' } From a6819b329e83cabcc294aa7e60ff66d38dac492d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:56:33 +0000 Subject: [PATCH 05/29] chore(deps): bump org.slf4j:slf4j-api from 2.0.0 to 2.0.7 Bumps [org.slf4j:slf4j-api](https://github.com/qos-ch/slf4j) from 2.0.0 to 2.0.7. - [Release notes](https://github.com/qos-ch/slf4j/releases) - [Commits](https://github.com/qos-ch/slf4j/commits) --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0519a3d3..46b835b5 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { ext.gsonVersion = '2.10.1' ext.okhttpVersion = '4.10.0' ext.loggingOkhttpVersion = '4.10.0' - ext.slf4jVersion = '2.0.0' + ext.slf4jVersion = '2.0.7' ext.guavaVersion = '31.1-jre' ext.junitVersion = '5.9.2' From 4e8a72f7660aac11e27a94e4cca45c7bd26ba2b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 16:56:57 +0000 Subject: [PATCH 06/29] chore(deps): bump com.squareup.okhttp3:okhttp from 4.10.0 to 4.11.0 Bumps [com.squareup.okhttp3:okhttp](https://github.com/square/okhttp) from 4.10.0 to 4.11.0. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.10.0...parent-4.11.0) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:okhttp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 46b835b5..87734295 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { ext.bouncycastleVersion = '1.65' ext.rxjavaVersion = '2.2.21' ext.gsonVersion = '2.10.1' - ext.okhttpVersion = '4.10.0' + ext.okhttpVersion = '4.11.0' ext.loggingOkhttpVersion = '4.10.0' ext.slf4jVersion = '2.0.7' ext.guavaVersion = '31.1-jre' From ebdb81ea6623826e3a776617dc32e8e7eada5d77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 16:57:00 +0000 Subject: [PATCH 07/29] chore(deps): bump com.squareup.okhttp3:logging-interceptor Bumps [com.squareup.okhttp3:logging-interceptor](https://github.com/square/okhttp) from 4.10.0 to 4.11.0. - [Release notes](https://github.com/square/okhttp/releases) - [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okhttp/compare/parent-4.10.0...parent-4.11.0) --- updated-dependencies: - dependency-name: com.squareup.okhttp3:logging-interceptor dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 46b835b5..4fba1ccc 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { ext.rxjavaVersion = '2.2.21' ext.gsonVersion = '2.10.1' ext.okhttpVersion = '4.10.0' - ext.loggingOkhttpVersion = '4.10.0' + ext.loggingOkhttpVersion = '4.11.0' ext.slf4jVersion = '2.0.7' ext.guavaVersion = '31.1-jre' ext.junitVersion = '5.9.2' From 2d0b09832efc5a2a9374b1df79ffdbc0e0cfb9bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 16:56:32 +0000 Subject: [PATCH 08/29] chore(deps): bump junitVersion from 5.9.2 to 5.9.3 Bumps `junitVersion` from 5.9.2 to 5.9.3. Updates `org.junit.jupiter:junit-jupiter-api` from 5.9.2 to 5.9.3 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.2...r5.9.3) Updates `org.junit.jupiter:junit-jupiter-engine` from 5.9.2 to 5.9.3 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.2...r5.9.3) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- ckb-indexer/build.gradle | 4 ++-- ckb-mercury-sdk/build.gradle | 4 ++-- light-client/build.gradle | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 10b66c7b..e1b7c104 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { ext.loggingOkhttpVersion = '4.11.0' ext.slf4jVersion = '2.0.7' ext.guavaVersion = '31.1-jre' - ext.junitVersion = '5.9.2' + ext.junitVersion = '5.9.3' repositories { jcenter() diff --git a/ckb-indexer/build.gradle b/ckb-indexer/build.gradle index 27e52507..df723804 100644 --- a/ckb-indexer/build.gradle +++ b/ckb-indexer/build.gradle @@ -3,8 +3,8 @@ description 'SDK for CKB indexer' dependencies { compile project(":core") - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.3' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3' // Enable use of the JUnitPlatform Runner within the IDE testImplementation("org.junit.platform:junit-platform-runner:1.9.2") diff --git a/ckb-mercury-sdk/build.gradle b/ckb-mercury-sdk/build.gradle index fab57842..53d333fd 100644 --- a/ckb-mercury-sdk/build.gradle +++ b/ckb-mercury-sdk/build.gradle @@ -4,8 +4,8 @@ dependencies { compile project(":core") compile project(":ckb-indexer") testImplementation project(":ckb") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.3") // Enable use of the JUnitPlatform Runner within the IDE testImplementation("org.junit.platform:junit-platform-runner:1.9.2") } diff --git a/light-client/build.gradle b/light-client/build.gradle index f488adaf..7e34d2cc 100644 --- a/light-client/build.gradle +++ b/light-client/build.gradle @@ -11,8 +11,8 @@ repositories { dependencies { implementation project(":ckb-indexer") - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.3' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3' } test { From f6fadd92bb93bbbd21d3a5b1a11298258cff6414 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 16:56:34 +0000 Subject: [PATCH 09/29] chore(deps): bump org.junit.platform:junit-platform-runner Bumps [org.junit.platform:junit-platform-runner](https://github.com/junit-team/junit5) from 1.9.2 to 1.9.3. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/commits) --- updated-dependencies: - dependency-name: org.junit.platform:junit-platform-runner dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- ckb-indexer/build.gradle | 2 +- ckb-mercury-sdk/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ckb-indexer/build.gradle b/ckb-indexer/build.gradle index df723804..101cb00c 100644 --- a/ckb-indexer/build.gradle +++ b/ckb-indexer/build.gradle @@ -7,7 +7,7 @@ dependencies { testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3' // Enable use of the JUnitPlatform Runner within the IDE - testImplementation("org.junit.platform:junit-platform-runner:1.9.2") + testImplementation("org.junit.platform:junit-platform-runner:1.9.3") } test { diff --git a/ckb-mercury-sdk/build.gradle b/ckb-mercury-sdk/build.gradle index 53d333fd..7c423464 100644 --- a/ckb-mercury-sdk/build.gradle +++ b/ckb-mercury-sdk/build.gradle @@ -7,7 +7,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.3") // Enable use of the JUnitPlatform Runner within the IDE - testImplementation("org.junit.platform:junit-platform-runner:1.9.2") + testImplementation("org.junit.platform:junit-platform-runner:1.9.3") } test { From 27e22c5a7adba1f841c7eed3d3fa57323361e503 Mon Sep 17 00:00:00 2001 From: Liu Chuankai Date: Thu, 11 May 2023 19:48:39 +0800 Subject: [PATCH 10/29] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Make=20dao=20handle?= =?UTF-8?q?r=20get=20correct=20withdraw=20block=20hash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/nervos/ckb/transaction/handler/DaoScriptHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/handler/DaoScriptHandler.java b/ckb/src/main/java/org/nervos/ckb/transaction/handler/DaoScriptHandler.java index f5fc2213..61da0e1d 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/handler/DaoScriptHandler.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/handler/DaoScriptHandler.java @@ -108,6 +108,7 @@ public ClaimInfo(Api api, OutPoint withdrawOutpoint) { this.withdrawOutpoint = withdrawOutpoint; try { TransactionWithStatus txWithStatus = api.getTransaction(withdrawOutpoint.txHash); + byte[] withdrawBlockHash = txWithStatus.txStatus.blockHash; Transaction withdrawTx = txWithStatus.transaction; byte[] depositBlockHash = null; for (int i = 0; i < withdrawTx.inputs.size(); i++) { @@ -123,7 +124,6 @@ public ClaimInfo(Api api, OutPoint withdrawOutpoint) { if (depositBlockHash == null) { throw new RuntimeException("Can find deposit cell"); } - byte[] withdrawBlockHash = txWithStatus.txStatus.blockHash; depositBlockHeader = api.getHeader(depositBlockHash); withdrawBlockHeader = api.getHeader(withdrawBlockHash); } catch (IOException e) { From 4279ed516b035d7fafa56501c4d1377596010a70 Mon Sep 17 00:00:00 2001 From: Liu Chuankai Date: Thu, 18 May 2023 14:29:39 +0800 Subject: [PATCH 11/29] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20support=20type=20i?= =?UTF-8?q?d=20handler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AbstractTransactionBuilder.java | 50 ++++++++++--- .../transaction/CkbTransactionBuilder.java | 56 +++++++-------- .../transaction/SudtTransactionBuilder.java | 26 ++----- .../TransactionBuilderConfiguration.java | 1 + .../transaction/handler/ScriptHandler.java | 2 + .../ckb/transaction/handler/TypIdHandler.java | 71 +++++++++++++++++++ .../CkbTransactionBuilderTest.java | 25 +++++++ .../java/org/nervos/ckb/sign/ScriptGroup.java | 21 ++++-- 8 files changed, 188 insertions(+), 64 deletions(-) create mode 100644 ckb/src/main/java/org/nervos/ckb/transaction/handler/TypIdHandler.java diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/AbstractTransactionBuilder.java b/ckb/src/main/java/org/nervos/ckb/transaction/AbstractTransactionBuilder.java index a21c65e2..690fd526 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/AbstractTransactionBuilder.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/AbstractTransactionBuilder.java @@ -1,16 +1,11 @@ package org.nervos.ckb.transaction; +import org.nervos.ckb.sign.ScriptGroup; import org.nervos.ckb.sign.TransactionWithScriptGroups; -import org.nervos.ckb.type.CellDep; -import org.nervos.ckb.type.Transaction; -import org.nervos.ckb.type.TransactionInput; -import org.nervos.ckb.type.WitnessArgs; +import org.nervos.ckb.type.*; import org.nervos.ckb.utils.Calculator; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; +import java.util.*; public abstract class AbstractTransactionBuilder { protected int changeOutputIndex = -1; @@ -47,7 +42,7 @@ public int setHeaderDep(byte[] headerDep) { } public void addCellDeps(List cellDeps) { - for (CellDep cellDep: cellDeps) { + for (CellDep cellDep : cellDeps) { addCellDep(cellDep); } } @@ -98,5 +93,42 @@ public TransactionWithScriptGroups build() { return build((Object) null); } + public CellOutput getOutput(int i) { + try { + return this.tx.outputs.get(i); + } catch (IndexOutOfBoundsException e) { + return null; + } + } + + public CellInput getInput(int i) { + try { + return this.tx.inputs.get(i); + } catch (IndexOutOfBoundsException e) { + return null; + } + } + + public Map rebuildScriptGroups(Map scriptGroupMap) { + Map ret = new HashMap<>(); + for (Map.Entry entry : scriptGroupMap.entrySet()) { + Script key = entry.getKey(); + ScriptGroup old_group = entry.getValue(); + if (ScriptType.LOCK == old_group.getGroupType()) { + ret.put(key, old_group); + continue; + } + if (!old_group.getInputIndices().isEmpty()) { + ScriptGroup new_group = ret.computeIfAbsent(key, ScriptGroup::new_type); + new_group.getInputIndices().addAll(old_group.getInputIndices()); + } + for (int idx : old_group.getOutputIndices()) { + Script type = this.tx.outputs.get(idx).type; + ScriptGroup new_group = ret.computeIfAbsent(type, ScriptGroup::new_type); + new_group.getOutputIndices().add(idx); + } + } + return ret; + } abstract TransactionWithScriptGroups build(Object... contexts); } diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java b/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java index 8aa085ae..e12c325d 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java @@ -79,16 +79,10 @@ public TransactionWithScriptGroups build(Object... contexts) { outputsCapacity += output.capacity; Script type = output.type; if (type != null) { - ScriptGroup scriptGroup = scriptGroupMap.get(type); - if (scriptGroup == null) { - scriptGroup = new ScriptGroup(); - scriptGroup.setScript(type); - scriptGroup.setGroupType(ScriptType.TYPE); - scriptGroupMap.put(type, scriptGroup); - } + ScriptGroup scriptGroup = scriptGroupMap.computeIfAbsent(type, ScriptGroup::new_type); scriptGroup.getOutputIndices().add(i); - for (ScriptHandler handler: configuration.getScriptHandlers()) { - for (Object context: contexts) { + for (ScriptHandler handler : configuration.getScriptHandlers()) { + for (Object context : contexts) { handler.buildTransaction(this, scriptGroup, context); } } @@ -107,33 +101,21 @@ public TransactionWithScriptGroups build(Object... contexts) { inputIndex += 1; Script lock = input.output.lock; - ScriptGroup scriptGroup = scriptGroupMap.get(lock); - if (scriptGroup == null) { - scriptGroup = new ScriptGroup(); - scriptGroup.setScript(lock); - scriptGroup.setGroupType(ScriptType.LOCK); - scriptGroupMap.put(lock, scriptGroup); - } + ScriptGroup scriptGroup = scriptGroupMap.computeIfAbsent(lock, ScriptGroup::new_lock); scriptGroup.getInputIndices().add(inputIndex); // add cellDeps and set witness placeholder - for (ScriptHandler handler: configuration.getScriptHandlers()) { - for (Object context: contexts) { + for (ScriptHandler handler : configuration.getScriptHandlers()) { + for (Object context : contexts) { handler.buildTransaction(this, scriptGroup, context); } } Script type = input.output.type; if (type != null) { - scriptGroup = scriptGroupMap.get(type); - if (scriptGroup == null) { - scriptGroup = new ScriptGroup(); - scriptGroup.setScript(type); - scriptGroup.setGroupType(ScriptType.TYPE); - scriptGroupMap.put(type, scriptGroup); - } + scriptGroup = scriptGroupMap.computeIfAbsent(type, ScriptGroup::new_type); scriptGroup.getInputIndices().add(inputIndex); - for (ScriptHandler handler: configuration.getScriptHandlers()) { - for (Object context: contexts) { + for (ScriptHandler handler : configuration.getScriptHandlers()) { + for (Object context : contexts) { handler.buildTransaction(this, scriptGroup, context); } } @@ -152,15 +134,33 @@ public TransactionWithScriptGroups build(Object... contexts) { } } + postBuild(scriptGroupMap); if (!enoughCapacity) { throw new IllegalStateException("No enough capacity"); } return TransactionWithScriptGroups.builder() .setTxView(tx) - .setScriptGroups(new ArrayList<>(scriptGroupMap.values())) + .setScriptGroups(new ArrayList<>(rebuildScriptGroups(scriptGroupMap).values())) .build(); } + public void postBuild(Map scriptGroupMap) { + for (Map.Entry entry : scriptGroupMap.entrySet()) { + ScriptGroup old_group = entry.getValue(); + if (ScriptType.LOCK == old_group.getGroupType()) { + continue; + } + for (int idx : old_group.getOutputIndices()) { + for (ScriptHandler handler : configuration.getScriptHandlers()) { + for (Object context : configuration.getScriptHandlers()) { + if (handler.postBuild(idx, this, context)) { + break; + }; + } + } + } + } + } int transactionInputsIndex = 0; public TransactionInput next() { diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/SudtTransactionBuilder.java b/ckb/src/main/java/org/nervos/ckb/transaction/SudtTransactionBuilder.java index 86e28b68..0024773d 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/SudtTransactionBuilder.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/SudtTransactionBuilder.java @@ -138,13 +138,7 @@ public TransactionWithScriptGroups build(Object... contexts) { } Script type = output.type; if (type != null) { - ScriptGroup scriptGroup = scriptGroupMap.get(type); - if (scriptGroup == null) { - scriptGroup = new ScriptGroup(); - scriptGroup.setScript(type); - scriptGroup.setGroupType(ScriptType.TYPE); - scriptGroupMap.put(type, scriptGroup); - } + ScriptGroup scriptGroup = scriptGroupMap.computeIfAbsent(type, ScriptGroup::new_type); scriptGroup.getOutputIndices().add(i); for (ScriptHandler handler: configuration.getScriptHandlers()) { for (Object context: contexts) { @@ -175,13 +169,7 @@ public TransactionWithScriptGroups build(Object... contexts) { throw new IllegalStateException("input lock hash should be the same as SUDT args in the SUDT-issue transaction"); } } - ScriptGroup scriptGroup = scriptGroupMap.get(lock); - if (scriptGroup == null) { - scriptGroup = new ScriptGroup(); - scriptGroup.setScript(lock); - scriptGroup.setGroupType(ScriptType.LOCK); - scriptGroupMap.put(lock, scriptGroup); - } + ScriptGroup scriptGroup = scriptGroupMap.computeIfAbsent(lock, ScriptGroup::new_lock); scriptGroup.getInputIndices().add(inputIndex); // add cellDeps and set witness placeholder for (ScriptHandler handler: configuration.getScriptHandlers()) { @@ -192,13 +180,7 @@ public TransactionWithScriptGroups build(Object... contexts) { Script type = input.output.type; if (type != null) { - scriptGroup = scriptGroupMap.get(type); - if (scriptGroup == null) { - scriptGroup = new ScriptGroup(); - scriptGroup.setScript(type); - scriptGroup.setGroupType(ScriptType.TYPE); - scriptGroupMap.put(type, scriptGroup); - } + scriptGroup = scriptGroupMap.computeIfAbsent(type, ScriptGroup::new_type); scriptGroup.getInputIndices().add(inputIndex); for (ScriptHandler handler: configuration.getScriptHandlers()) { for (Object context: contexts) { @@ -236,7 +218,7 @@ public TransactionWithScriptGroups build(Object... contexts) { } return TransactionWithScriptGroups.builder() .setTxView(tx) - .setScriptGroups(new ArrayList<>(scriptGroupMap.values())) + .setScriptGroups(new ArrayList<>(rebuildScriptGroups(scriptGroupMap).values())) .build(); } } diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java index 6ecbcce4..97257670 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java @@ -23,6 +23,7 @@ public TransactionBuilderConfiguration(Network network) { registerScriptHandler(SudtScriptHandler.class); registerScriptHandler(DaoScriptHandler.class); registerScriptHandler(OmnilockScriptHandler.class); + registerScriptHandler(TypIdHandler.class); } public Network getNetwork() { diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/handler/ScriptHandler.java b/ckb/src/main/java/org/nervos/ckb/transaction/handler/ScriptHandler.java index 994e26c8..3dcfedea 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/handler/ScriptHandler.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/handler/ScriptHandler.java @@ -8,4 +8,6 @@ public interface ScriptHandler { boolean buildTransaction(AbstractTransactionBuilder txBuilder, ScriptGroup scriptGroup, Object context); void init(Network network); + + default boolean postBuild(int index, AbstractTransactionBuilder txBuilder, Object context) {return false;} } diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/handler/TypIdHandler.java b/ckb/src/main/java/org/nervos/ckb/transaction/handler/TypIdHandler.java new file mode 100644 index 00000000..ebe84527 --- /dev/null +++ b/ckb/src/main/java/org/nervos/ckb/transaction/handler/TypIdHandler.java @@ -0,0 +1,71 @@ +package org.nervos.ckb.transaction.handler; + +import org.nervos.ckb.Network; +import org.nervos.ckb.crypto.Blake2b; +import org.nervos.ckb.sign.ScriptGroup; +import org.nervos.ckb.transaction.AbstractTransactionBuilder; +import org.nervos.ckb.type.CellInput; +import org.nervos.ckb.type.CellOutput; +import org.nervos.ckb.type.Script; +import org.nervos.ckb.utils.Numeric; + +import java.util.Arrays; +import java.util.List; + +import static org.nervos.ckb.utils.MoleculeConverter.packUint64; + +public class TypIdHandler implements ScriptHandler { + public static final byte[] TYPE_ID_CODE_HASH = Numeric.hexStringToByteArray("0x00000000000000000000000000000000000000000000000000545950455f4944"); + public static final byte[] ZERO_ARGS = new byte[32]; + + private boolean isMatched(Script script) { + if (script == null) { + return false; + } + return Arrays.equals(script.codeHash, TYPE_ID_CODE_HASH); + } + + @Override + public boolean buildTransaction(AbstractTransactionBuilder txBuilder, ScriptGroup scriptGroup, Object context) { + if (scriptGroup == null || !isMatched(scriptGroup.getScript()) || scriptGroup.getOutputIndices().isEmpty()) { + return false; + } + List outputIndices = scriptGroup.getOutputIndices(); + int index = outputIndices.get(outputIndices.size() - 1); + CellOutput output = txBuilder.getOutput(index); + if (isMatched(output.type)) { + if (output.type.args == null || output.type.args.length != 32) { + output.type.args = ZERO_ARGS.clone(); + } + return true; + } + + return false; + } + + @Override + public void init(Network network) { + + } + + public static byte[] calculateTypeId(CellInput input, int index) { + Blake2b blake2b = new Blake2b(); + blake2b.update(input.pack().toByteArray()); + blake2b.update(packUint64(index).toByteArray()); + return blake2b.doFinal(); + } + + @Override + public boolean postBuild(int index, AbstractTransactionBuilder txBuilder, Object context) { + CellOutput output = txBuilder.getOutput(index); + if (null == output || !isMatched(output.type) || !Arrays.equals(output.type.args, ZERO_ARGS)) { + return false; + } + CellInput input = txBuilder.getInput(0); + if (input == null) { + return false; + } + output.type.args = calculateTypeId(input, index); + return true; + } +} diff --git a/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java b/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java index b6904435..b8515a89 100644 --- a/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java +++ b/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java @@ -3,14 +3,17 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.nervos.ckb.Network; +import org.nervos.ckb.service.GsonFactory; import org.nervos.ckb.sign.TransactionWithScriptGroups; import org.nervos.ckb.transaction.CkbTransactionBuilder; import org.nervos.ckb.transaction.TransactionBuilderConfiguration; +import org.nervos.ckb.transaction.handler.TypIdHandler; import org.nervos.ckb.type.*; import org.nervos.ckb.utils.Numeric; import org.nervos.ckb.utils.address.Address; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; @@ -39,6 +42,28 @@ void testSingleInput() { Assertions.assertEquals(464, fee); } + @Test + void testTypeId() { + Iterator iterator = newTransactionInputs(); + TransactionBuilderConfiguration configuration = new TransactionBuilderConfiguration(Network.TESTNET); + configuration.setFeeRate(1000); + CellOutput output = new CellOutput(120, Address.decode("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r").getScript(), new Script(TypIdHandler.TYPE_ID_CODE_HASH, null)); + TransactionWithScriptGroups txWithGroups = new CkbTransactionBuilder(configuration, iterator) + .addOutput(output, new byte[64]) + .setChangeOutput(sender.encode()) + .build(); + + Transaction tx = txWithGroups.getTxView(); + + Assertions.assertEquals(1, tx.inputs.size()); + Assertions.assertEquals(2, txWithGroups.scriptGroups.size()); + Assertions.assertTrue(txWithGroups.scriptGroups.stream().anyMatch(scriptGroup -> scriptGroup.getScript() == lock)); + Assertions.assertTrue(txWithGroups.scriptGroups.stream().anyMatch(g -> g.getGroupType() == ScriptType.TYPE && g.getScript().codeHash == TypIdHandler.TYPE_ID_CODE_HASH && g.getScript().args.length == 32 && !Arrays.equals(g.getScript().args, TypIdHandler.ZERO_ARGS))); + Assertions.assertEquals(2, tx.outputs.size()); + long fee = 100000000000L - tx.outputs.get(0).capacity - tx.outputs.get(1).capacity; + Assertions.assertEquals(613, fee); + } + @Test void testMultipleInputs() { String sender = "ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r"; diff --git a/core/src/main/java/org/nervos/ckb/sign/ScriptGroup.java b/core/src/main/java/org/nervos/ckb/sign/ScriptGroup.java index e2afac5d..fe447832 100644 --- a/core/src/main/java/org/nervos/ckb/sign/ScriptGroup.java +++ b/core/src/main/java/org/nervos/ckb/sign/ScriptGroup.java @@ -12,6 +12,11 @@ public class ScriptGroup { private List inputIndices = new ArrayList<>(); private List outputIndices = new ArrayList<>(); + public ScriptGroup(Script script, ScriptType groupType) { + this.script = script; + this.groupType = groupType; + } + public Script getScript() { return script; } @@ -28,6 +33,14 @@ public void setGroupType(ScriptType groupType) { this.groupType = groupType; } + public static ScriptGroup new_type(Script script) { + return new ScriptGroup(script, ScriptType.TYPE); + } + + public static ScriptGroup new_lock(Script script) { + return new ScriptGroup(script, ScriptType.LOCK); + } + public List getInputIndices() { return inputIndices; } @@ -85,7 +98,7 @@ public Builder setInputIndices(List inputIndices) { } public Builder addInputIndices(int... indices) { - for (int index: indices) { + for (int index : indices) { this.inputIndices.add(index); } return this; @@ -97,16 +110,14 @@ public Builder setOutputIndices(List outputIndices) { } public Builder addOutputIndices(int... indices) { - for (int index: indices) { + for (int index : indices) { this.outputIndices.add(index); } return this; } public ScriptGroup build() { - ScriptGroup scriptGroup = new ScriptGroup(); - scriptGroup.setScript(script); - scriptGroup.setGroupType(groupType); + ScriptGroup scriptGroup = new ScriptGroup(script, groupType); scriptGroup.setInputIndices(inputIndices); scriptGroup.setOutputIndices(outputIndices); return scriptGroup; From 1b05e0bfd26badba3f0175493ffaeed36b354f99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 16:43:17 +0000 Subject: [PATCH 12/29] chore(deps): bump com.google.guava:guava from 31.1-jre to 32.1.1-jre Bumps [com.google.guava:guava](https://github.com/google/guava) from 31.1-jre to 32.1.1-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e1b7c104..386759cd 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { ext.okhttpVersion = '4.11.0' ext.loggingOkhttpVersion = '4.11.0' ext.slf4jVersion = '2.0.7' - ext.guavaVersion = '31.1-jre' + ext.guavaVersion = '32.1.1-jre' ext.junitVersion = '5.9.3' repositories { From 6d8ae44f74880cea7bac448b58f1bfcb91c3500f Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Thu, 20 Jul 2023 18:21:00 +0800 Subject: [PATCH 13/29] Fix guava dep for ckb --- ckb/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/ckb/build.gradle b/ckb/build.gradle index 41f4c572..1ebbe0f3 100644 --- a/ckb/build.gradle +++ b/ckb/build.gradle @@ -8,6 +8,7 @@ dependencies { implementation project(":serialization") implementation "com.google.code.gson:gson:$gsonVersion" + implementation "com.google.guava:guava:$guavaVersion" } apply plugin: 'com.github.johnrengelman.shadow' From 499f67375aec59879e9699837bf197a127de3474 Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Thu, 20 Jul 2023 18:23:00 +0800 Subject: [PATCH 14/29] Fix TypeIdHandler name typo --- .../ckb/transaction/TransactionBuilderConfiguration.java | 2 +- .../handler/{TypIdHandler.java => TypeIdHandler.java} | 2 +- .../test/java/transaction/CkbTransactionBuilderTest.java | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) rename ckb/src/main/java/org/nervos/ckb/transaction/handler/{TypIdHandler.java => TypeIdHandler.java} (97%) diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java index 97257670..cf744c05 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java @@ -23,7 +23,7 @@ public TransactionBuilderConfiguration(Network network) { registerScriptHandler(SudtScriptHandler.class); registerScriptHandler(DaoScriptHandler.class); registerScriptHandler(OmnilockScriptHandler.class); - registerScriptHandler(TypIdHandler.class); + registerScriptHandler(TypeIdHandler.class); } public Network getNetwork() { diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/handler/TypIdHandler.java b/ckb/src/main/java/org/nervos/ckb/transaction/handler/TypeIdHandler.java similarity index 97% rename from ckb/src/main/java/org/nervos/ckb/transaction/handler/TypIdHandler.java rename to ckb/src/main/java/org/nervos/ckb/transaction/handler/TypeIdHandler.java index ebe84527..3d6e9f32 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/handler/TypIdHandler.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/handler/TypeIdHandler.java @@ -14,7 +14,7 @@ import static org.nervos.ckb.utils.MoleculeConverter.packUint64; -public class TypIdHandler implements ScriptHandler { +public class TypeIdHandler implements ScriptHandler { public static final byte[] TYPE_ID_CODE_HASH = Numeric.hexStringToByteArray("0x00000000000000000000000000000000000000000000000000545950455f4944"); public static final byte[] ZERO_ARGS = new byte[32]; diff --git a/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java b/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java index b8515a89..14d2a393 100644 --- a/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java +++ b/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java @@ -3,11 +3,10 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.nervos.ckb.Network; -import org.nervos.ckb.service.GsonFactory; import org.nervos.ckb.sign.TransactionWithScriptGroups; import org.nervos.ckb.transaction.CkbTransactionBuilder; import org.nervos.ckb.transaction.TransactionBuilderConfiguration; -import org.nervos.ckb.transaction.handler.TypIdHandler; +import org.nervos.ckb.transaction.handler.TypeIdHandler; import org.nervos.ckb.type.*; import org.nervos.ckb.utils.Numeric; import org.nervos.ckb.utils.address.Address; @@ -47,7 +46,7 @@ void testTypeId() { Iterator iterator = newTransactionInputs(); TransactionBuilderConfiguration configuration = new TransactionBuilderConfiguration(Network.TESTNET); configuration.setFeeRate(1000); - CellOutput output = new CellOutput(120, Address.decode("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r").getScript(), new Script(TypIdHandler.TYPE_ID_CODE_HASH, null)); + CellOutput output = new CellOutput(120, Address.decode("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r").getScript(), new Script(TypeIdHandler.TYPE_ID_CODE_HASH, null)); TransactionWithScriptGroups txWithGroups = new CkbTransactionBuilder(configuration, iterator) .addOutput(output, new byte[64]) .setChangeOutput(sender.encode()) @@ -58,7 +57,7 @@ void testTypeId() { Assertions.assertEquals(1, tx.inputs.size()); Assertions.assertEquals(2, txWithGroups.scriptGroups.size()); Assertions.assertTrue(txWithGroups.scriptGroups.stream().anyMatch(scriptGroup -> scriptGroup.getScript() == lock)); - Assertions.assertTrue(txWithGroups.scriptGroups.stream().anyMatch(g -> g.getGroupType() == ScriptType.TYPE && g.getScript().codeHash == TypIdHandler.TYPE_ID_CODE_HASH && g.getScript().args.length == 32 && !Arrays.equals(g.getScript().args, TypIdHandler.ZERO_ARGS))); + Assertions.assertTrue(txWithGroups.scriptGroups.stream().anyMatch(g -> g.getGroupType() == ScriptType.TYPE && g.getScript().codeHash == TypeIdHandler.TYPE_ID_CODE_HASH && g.getScript().args.length == 32 && !Arrays.equals(g.getScript().args, TypeIdHandler.ZERO_ARGS))); Assertions.assertEquals(2, tx.outputs.size()); long fee = 100000000000L - tx.outputs.get(0).capacity - tx.outputs.get(1).capacity; Assertions.assertEquals(613, fee); From 90e8775d7fa0b743935a9a0c0306e91cdacd49ce Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Fri, 21 Jul 2023 12:10:53 +0800 Subject: [PATCH 15/29] feat: force small change as fee --- .../transaction/CkbTransactionBuilder.java | 43 +++++++++++++++++-- .../TransactionBuilderConfiguration.java | 17 ++++++++ .../CkbTransactionBuilderTest.java | 31 +++++++++++++ 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java b/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java index e12c325d..669df3f1 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java @@ -18,6 +18,11 @@ public CkbTransactionBuilder(TransactionBuilderConfiguration configuration, Iter super(configuration, availableInputs); } + /** + * Add a potential input for the transaction. + *

+ * The input may not be actually used if there's already enough capacity for the outputs. + */ public CkbTransactionBuilder addInput(TransactionInput transactionInput) { transactionInputs.add(transactionInput); return this; @@ -32,6 +37,9 @@ public CkbTransactionBuilder addHeaderDep(String headerDep) { return addHeaderDep(Numeric.hexStringToByteArray(headerDep)); } + /** + * Add outputs and data. The two parameters should have the same size. + */ public CkbTransactionBuilder setOutputs(List outputs, List outputsData) { tx.outputs.addAll(outputs); tx.outputsData.addAll(outputsData); @@ -57,6 +65,11 @@ public CkbTransactionBuilder addDaoDepositOutput(String address, long capacity) return addOutput(output, data); } + /** + * Set change output. Its capacity will be overwritten later when building the transaction. + *

+ * Change output should be set only once. + */ public CkbTransactionBuilder setChangeOutput(CellOutput output, byte[] data) { if (changeOutputIndex != -1) { throw new IllegalStateException("Change output has been set"); @@ -65,11 +78,19 @@ public CkbTransactionBuilder setChangeOutput(CellOutput output, byte[] data) { return addOutput(output, data); } + /** + * Set change output. Its capacity will be overwritten later when building the transaction. + *

+ * Change output should be set only once. + */ public CkbTransactionBuilder setChangeOutput(String address) { CellOutput output = new CellOutput(0, Address.decode(address).getScript()); return setChangeOutput(output, new byte[0]); } + /** + * Build the transaction. This will collect inputs so that there's enough capacity for the outputs. + */ @Override public TransactionWithScriptGroups build(Object... contexts) { Map scriptGroupMap = new HashMap<>(); @@ -125,13 +146,27 @@ public TransactionWithScriptGroups build(Object... contexts) { // check if there is enough capacity for output capacity and change long fee = calculateTxFee(tx, configuration.getFeeRate()); long changeCapacity = inputsCapacity - outputsCapacity - fee + reward; - CellOutput changeOutput = tx.outputs.get(changeOutputIndex); - byte[] changeOutputData = tx.outputsData.get(changeOutputIndex); - if (changeCapacity >= changeOutput.occupiedCapacity(changeOutputData)) { - tx.outputs.get(changeOutputIndex).capacity = changeCapacity; + final Long forceSmallChangeAsFee = getConfiguration().getForceSmallChangeAsFee(); + if (forceSmallChangeAsFee != null && changeCapacity > 0 && changeCapacity < forceSmallChangeAsFee) { + if (changeOutputIndex != -1) { + throw new IllegalStateException("Will discard change capacity but change output is set"); + } enoughCapacity = true; break; } + if (changeCapacity > 0) { + try { + CellOutput changeOutput = tx.outputs.get(changeOutputIndex); + byte[] changeOutputData = tx.outputsData.get(changeOutputIndex); + if (changeCapacity >= changeOutput.occupiedCapacity(changeOutputData)) { + tx.outputs.get(changeOutputIndex).capacity = changeCapacity; + enoughCapacity = true; + break; + } + } catch (IndexOutOfBoundsException e) { + throw new IllegalStateException("Change output not set"); + } + } } postBuild(scriptGroupMap); diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java index cf744c05..b17a58d7 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java @@ -3,6 +3,7 @@ import org.nervos.ckb.Network; import org.nervos.ckb.transaction.handler.*; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -11,6 +12,8 @@ public class TransactionBuilderConfiguration { private Network network; private List scriptHandlers = new ArrayList<>(); private long feeRate = 1000; + @Nullable + private Long forceSmallChangeAsFee; public TransactionBuilderConfiguration() { } @@ -63,4 +66,18 @@ public long getFeeRate() { public void setFeeRate(long feeRate) { this.feeRate = feeRate; } + + @Nullable + public Long getForceSmallChangeAsFee() { + return forceSmallChangeAsFee; + } + + /** + * Set forceSmallChangeAsFee. When building transaction, a change output will not be required if it would be smaller than the specified amount. + * + * @param forceSmallChangeAsFee Unit shannons + */ + public void setForceSmallChangeAsFee(@Nullable Long forceSmallChangeAsFee) { + this.forceSmallChangeAsFee = forceSmallChangeAsFee; + } } diff --git a/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java b/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java index 14d2a393..62592c0b 100644 --- a/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java +++ b/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java @@ -1,5 +1,6 @@ package transaction; +import com.google.common.collect.Iterators; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.nervos.ckb.Network; @@ -9,6 +10,7 @@ import org.nervos.ckb.transaction.handler.TypeIdHandler; import org.nervos.ckb.type.*; import org.nervos.ckb.utils.Numeric; +import org.nervos.ckb.utils.Utils; import org.nervos.ckb.utils.address.Address; import java.util.ArrayList; @@ -63,6 +65,35 @@ void testTypeId() { Assertions.assertEquals(613, fee); } + @Test + void testForceSmallFeeAsChange() { + Iterator inputs = newTransactionInputs(); + TransactionBuilderConfiguration configuration = new TransactionBuilderConfiguration(Network.TESTNET); + configuration.setForceSmallChangeAsFee(Utils.ckbToShannon(1)); + TransactionWithScriptGroups txWithGroups = new CkbTransactionBuilder(configuration, inputs) + .addOutput("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r", Utils.ckbToShannon(1099)) + .build(); + Assertions.assertEquals(txWithGroups.getTxView().outputs.size(), 1); + } + + @Test + void testForceSmallFeeAsChangeFailure() { + Iterator inputs = newTransactionInputs(); + TransactionBuilderConfiguration configuration = new TransactionBuilderConfiguration(Network.TESTNET); + // Not enough small change. + configuration.setForceSmallChangeAsFee(Utils.ckbToShannon(0.5)); + Exception exception = null; + try { + TransactionWithScriptGroups txWithGroups = new CkbTransactionBuilder(configuration, inputs) + .addOutput("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r", Utils.ckbToShannon(1099)) + .build(); + } catch (Exception e) { + exception = e; + } + Assertions.assertNotNull(exception); + Assertions.assertEquals(exception.getMessage(), "Change output not set"); + } + @Test void testMultipleInputs() { String sender = "ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r"; From f4dd99ec2068c4ee05cc60ebd8040c0eab4c5c6a Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Fri, 21 Jul 2023 14:37:18 +0800 Subject: [PATCH 16/29] Check that forceSmallChangeAsFee > 0 --- .../transaction/TransactionBuilderConfiguration.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java index b17a58d7..1adfcebc 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java @@ -73,11 +73,17 @@ public Long getForceSmallChangeAsFee() { } /** - * Set forceSmallChangeAsFee. When building transaction, a change output will not be required if it would be smaller than the specified amount. + * Set forceSmallChangeAsFee. When building transaction, a change output will not be required if its capacity would be + * smaller than the specified amount. * - * @param forceSmallChangeAsFee Unit shannons + * @param forceSmallChangeAsFee Should be positive. Unit is shannons. */ public void setForceSmallChangeAsFee(@Nullable Long forceSmallChangeAsFee) { + if (forceSmallChangeAsFee != null) { + if (forceSmallChangeAsFee <= 0) { + throw new IllegalArgumentException("invalid forceSmallChangeAsFee: " + forceSmallChangeAsFee); + } + } this.forceSmallChangeAsFee = forceSmallChangeAsFee; } } From 2718a2482dda1ec86dd560865eb44c3b5145f497 Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Fri, 21 Jul 2023 14:55:05 +0800 Subject: [PATCH 17/29] feat!: add script hash type data2 --- core/src/main/java/org/nervos/ckb/type/Script.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/nervos/ckb/type/Script.java b/core/src/main/java/org/nervos/ckb/type/Script.java index 6f65b7cf..a9694d0b 100644 --- a/core/src/main/java/org/nervos/ckb/type/Script.java +++ b/core/src/main/java/org/nervos/ckb/type/Script.java @@ -125,9 +125,11 @@ public enum HashType { @SerializedName("type") TYPE(0x01), @SerializedName("data1") - DATA1(0x02); + DATA1(0x02), + @SerializedName("data2") + DATA2(0x03); - private byte byteValue; + private final byte byteValue; HashType(int byteValue) { this.byteValue = (byte) byteValue; @@ -145,6 +147,8 @@ public static HashType unpack(byte value) { return TYPE; case 0x02: return DATA1; + case 0x03: + return DATA2; default: throw new NullPointerException(); } From 4db88971dbdd4eac3621bc50d260504768da859b Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Mon, 24 Jul 2023 18:42:10 +0800 Subject: [PATCH 18/29] Allow both changeOutput and forceSmallChangeAsFee --- .../AbstractTransactionBuilder.java | 1 - .../transaction/CkbTransactionBuilder.java | 98 +++++++++++++------ .../transaction/SudtTransactionBuilder.java | 3 +- .../CkbTransactionBuilderTest.java | 23 ++++- .../org/nervos/ckb/utils/address/Address.java | 3 +- 5 files changed, 90 insertions(+), 38 deletions(-) diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/AbstractTransactionBuilder.java b/ckb/src/main/java/org/nervos/ckb/transaction/AbstractTransactionBuilder.java index 690fd526..aeb5e9b0 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/AbstractTransactionBuilder.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/AbstractTransactionBuilder.java @@ -8,7 +8,6 @@ import java.util.*; public abstract class AbstractTransactionBuilder { - protected int changeOutputIndex = -1; protected TransactionBuilderConfiguration configuration; protected Iterator availableInputs; protected List inputsDetail = new ArrayList<>(); diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java b/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java index 669df3f1..205f7041 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java @@ -8,11 +8,17 @@ import org.nervos.ckb.utils.Numeric; import org.nervos.ckb.utils.address.Address; +import javax.annotation.Nonnull; import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class CkbTransactionBuilder extends AbstractTransactionBuilder { protected List transactionInputs = new ArrayList<>(); protected long reward = 0; + protected CellOutput changeOutput; + protected byte[] changeOutputData; + int transactionInputsIndex = 0; public CkbTransactionBuilder(TransactionBuilderConfiguration configuration, Iterator availableInputs) { super(configuration, availableInputs); @@ -66,33 +72,66 @@ public CkbTransactionBuilder addDaoDepositOutput(String address, long capacity) } /** - * Set change output. Its capacity will be overwritten later when building the transaction. + * Set possible change output. Its capacity must be 0. *

* Change output should be set only once. */ - public CkbTransactionBuilder setChangeOutput(CellOutput output, byte[] data) { - if (changeOutputIndex != -1) { + public CkbTransactionBuilder setChangeOutput(@Nonnull CellOutput output, @Nonnull byte[] data) { + if (changeOutput != null) { throw new IllegalStateException("Change output has been set"); } - changeOutputIndex = tx.outputs.size(); - return addOutput(output, data); + if (output.capacity != 0) { + throw new IllegalArgumentException("Change output capacity is not 0"); + } + changeOutput = output; + changeOutputData = data; + return this; } /** - * Set change output. Its capacity will be overwritten later when building the transaction. + * Set possible change output address. *

* Change output should be set only once. */ - public CkbTransactionBuilder setChangeOutput(String address) { + public CkbTransactionBuilder setChangeOutput(@Nonnull String address) { CellOutput output = new CellOutput(0, Address.decode(address).getScript()); return setChangeOutput(output, new byte[0]); } + /** + * Returns a clone of tx with the change output added. + */ + private Transaction txWithChangeOutput() { + List outputs1 = Stream.concat(tx.outputs.stream(), Stream.of(changeOutput)).collect(Collectors.toList()); + List outputsData1 = Stream.concat(tx.outputsData.stream(), Stream.of(changeOutputData)).collect(Collectors.toList()); + return new Transaction( + tx.version, + tx.cellDeps, + tx.headerDeps, + tx.inputs, + outputs1, + outputsData1, + tx.witnesses + ); + } + /** * Build the transaction. This will collect inputs so that there's enough capacity for the outputs. + *

+ * If changeOutput is set, a change output will be added, unless forceSmallChangeAsFee is set and the change is small enough. + *

+ *

+ * If changeOutput is not set, forceSmallChangeAsFee must be set and the change must be small enough. + *

+ * + * @throws IllegalStateException if settings are invalid or the transaction cannot be balanced. */ @Override public TransactionWithScriptGroups build(Object... contexts) { + if (getConfiguration().getForceSmallChangeAsFee() == null && changeOutput == null) { + throw new IllegalStateException("Neither forceSmallChangeAsFee or changeOutput are set"); + } + Map scriptGroupMap = new HashMap<>(); long outputsCapacity = 0L; for (int i = 0; i < tx.outputs.size(); i++) { @@ -143,28 +182,27 @@ public TransactionWithScriptGroups build(Object... contexts) { } inputsCapacity += input.output.capacity; - // check if there is enough capacity for output capacity and change - long fee = calculateTxFee(tx, configuration.getFeeRate()); - long changeCapacity = inputsCapacity - outputsCapacity - fee + reward; final Long forceSmallChangeAsFee = getConfiguration().getForceSmallChangeAsFee(); - if (forceSmallChangeAsFee != null && changeCapacity > 0 && changeCapacity < forceSmallChangeAsFee) { - if (changeOutputIndex != -1) { - throw new IllegalStateException("Will discard change capacity but change output is set"); + if (forceSmallChangeAsFee != null) { + long fee = calculateTxFee(tx, configuration.getFeeRate()); + long changeCapacity = inputsCapacity - outputsCapacity - fee + reward; + if (changeCapacity > 0 && changeCapacity < forceSmallChangeAsFee) { + enoughCapacity = true; + break; } - enoughCapacity = true; - break; } - if (changeCapacity > 0) { - try { - CellOutput changeOutput = tx.outputs.get(changeOutputIndex); - byte[] changeOutputData = tx.outputsData.get(changeOutputIndex); - if (changeCapacity >= changeOutput.occupiedCapacity(changeOutputData)) { - tx.outputs.get(changeOutputIndex).capacity = changeCapacity; - enoughCapacity = true; - break; - } - } catch (IndexOutOfBoundsException e) { - throw new IllegalStateException("Change output not set"); + + if (changeOutput != null) { + // Calculate fee with change output. + Transaction txWithChange = txWithChangeOutput(); + long fee = calculateTxFee(txWithChange, configuration.getFeeRate()); + long changeCapacity = inputsCapacity - outputsCapacity - fee + reward; + if (changeCapacity >= changeOutput.occupiedCapacity(changeOutputData)) { + changeOutput.capacity = changeCapacity; + // Replace tx with txWithChange. + tx = txWithChange; + enoughCapacity = true; + break; } } } @@ -190,13 +228,12 @@ public void postBuild(Map scriptGroupMap) { for (Object context : configuration.getScriptHandlers()) { if (handler.postBuild(idx, this, context)) { break; - }; + } } } } } } - int transactionInputsIndex = 0; public TransactionInput next() { if (transactionInputsIndex < transactionInputs.size()) { @@ -222,9 +259,6 @@ private boolean shouldFilterOut(TransactionInput input) { } } // only pool tx fee by null-type input - if (input.output.type != null) { - return true; - } - return false; + return input.output.type != null; } } diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/SudtTransactionBuilder.java b/ckb/src/main/java/org/nervos/ckb/transaction/SudtTransactionBuilder.java index 0024773d..c6128156 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/SudtTransactionBuilder.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/SudtTransactionBuilder.java @@ -6,7 +6,6 @@ import org.nervos.ckb.transaction.handler.ScriptHandler; import org.nervos.ckb.type.CellOutput; import org.nervos.ckb.type.Script; -import org.nervos.ckb.type.ScriptType; import org.nervos.ckb.type.TransactionInput; import org.nervos.ckb.utils.address.Address; @@ -20,6 +19,8 @@ public class SudtTransactionBuilder extends AbstractTransactionBuilder { private TransactionType transactionType; private Script sudtTypeScript; + private int changeOutputIndex = -1; + public enum TransactionType { ISSUE, TRANSFER diff --git a/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java b/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java index 62592c0b..01ddd72f 100644 --- a/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java +++ b/ckb/src/test/java/transaction/CkbTransactionBuilderTest.java @@ -1,6 +1,5 @@ package transaction; -import com.google.common.collect.Iterators; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.nervos.ckb.Network; @@ -72,26 +71,44 @@ void testForceSmallFeeAsChange() { configuration.setForceSmallChangeAsFee(Utils.ckbToShannon(1)); TransactionWithScriptGroups txWithGroups = new CkbTransactionBuilder(configuration, inputs) .addOutput("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r", Utils.ckbToShannon(1099)) + .setChangeOutput(sender.encode()) .build(); Assertions.assertEquals(txWithGroups.getTxView().outputs.size(), 1); } + @Test + void testForceSmallFeeAsChangeStillChange() { + Iterator inputs = newTransactionInputs(); + TransactionBuilderConfiguration configuration = new TransactionBuilderConfiguration(Network.TESTNET); + configuration.setForceSmallChangeAsFee(Utils.ckbToShannon(1)); + TransactionWithScriptGroups txWithGroups = new CkbTransactionBuilder(configuration, inputs) + .addOutput("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r", Utils.ckbToShannon(1001)) + .setChangeOutput(sender.encode()) + .build(); + Transaction txView = txWithGroups.getTxView(); + Assertions.assertEquals(2, txView.inputs.size()); + Assertions.assertEquals(2, txView.outputs.size()); + Assertions.assertEquals(Utils.ckbToShannon(1001), txView.outputs.get(0).capacity); + Assertions.assertEquals(9899999484L, txView.outputs.get(1).capacity); + } + @Test void testForceSmallFeeAsChangeFailure() { Iterator inputs = newTransactionInputs(); TransactionBuilderConfiguration configuration = new TransactionBuilderConfiguration(Network.TESTNET); - // Not enough small change. + // The change will be not small enough for forceSmallChangeAsFee but not big enough for a change output. configuration.setForceSmallChangeAsFee(Utils.ckbToShannon(0.5)); Exception exception = null; try { TransactionWithScriptGroups txWithGroups = new CkbTransactionBuilder(configuration, inputs) .addOutput("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r", Utils.ckbToShannon(1099)) + .setChangeOutput(sender.encode()) .build(); } catch (Exception e) { exception = e; } Assertions.assertNotNull(exception); - Assertions.assertEquals(exception.getMessage(), "Change output not set"); + Assertions.assertEquals("No enough capacity", exception.getMessage()); } @Test diff --git a/core/src/main/java/org/nervos/ckb/utils/address/Address.java b/core/src/main/java/org/nervos/ckb/utils/address/Address.java index ba678992..40184336 100644 --- a/core/src/main/java/org/nervos/ckb/utils/address/Address.java +++ b/core/src/main/java/org/nervos/ckb/utils/address/Address.java @@ -3,6 +3,7 @@ import org.nervos.ckb.Network; import org.nervos.ckb.type.Script; +import javax.annotation.Nonnull; import java.io.ByteArrayOutputStream; import java.util.Arrays; import java.util.Objects; @@ -40,7 +41,7 @@ public Address setNetwork(Network network) { } - public static Address decode(String address) { + public static Address decode(@Nonnull String address) { Objects.requireNonNull(address); Bech32.Bech32Data bech32Data = Bech32.decode(address); Bech32.Encoding encoding = bech32Data.encoding; From 311d410c563a9658ae288b406237033576bf6262 Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Fri, 21 Jul 2023 18:07:00 +0800 Subject: [PATCH 19/29] feat!: rpc updates * onlyCommitted * feeRateStatics -> feeRateStatistics --- .../main/java/org/nervos/ckb/CkbRpcApi.java | 36 +++++++++++++-- .../main/java/org/nervos/ckb/service/Api.java | 44 +++++++++++++------ ckb/src/test/java/service/ApiTest.java | 33 ++++++++------ ...ateStatics.java => FeeRateStatistics.java} | 2 +- .../ckb/type/TransactionWithStatus.java | 1 + .../java/org/nervos/ckb/type/TxPoolInfo.java | 2 + 6 files changed, 87 insertions(+), 31 deletions(-) rename core/src/main/java/org/nervos/ckb/type/{FeeRateStatics.java => FeeRateStatistics.java} (82%) diff --git a/ckb/src/main/java/org/nervos/ckb/CkbRpcApi.java b/ckb/src/main/java/org/nervos/ckb/CkbRpcApi.java index 6c92c576..8d761e6d 100644 --- a/ckb/src/main/java/org/nervos/ckb/CkbRpcApi.java +++ b/ckb/src/main/java/org/nervos/ckb/CkbRpcApi.java @@ -6,33 +6,55 @@ import org.nervos.indexer.model.SearchKey; import org.nervos.indexer.model.resp.*; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.IOException; import java.util.List; public interface CkbRpcApi { Block getBlock(byte[] blockHash) throws IOException; + BlockWithCycles getBlock(byte[] blockHash, boolean with_cycles) throws IOException; + PackedBlockWithCycles getPackedBlock(byte[] blockHash, boolean with_cycles) throws IOException; Block getBlockByNumber(long blockNumber) throws IOException; + BlockWithCycles getBlockByNumber(long blockNumber, boolean with_cycles) throws IOException; + PackedBlockWithCycles getPackedBlockByNumber(long blockNumber, boolean with_cycles) throws IOException; - TransactionWithStatus getTransaction(byte[] transactionHash) throws IOException; + default TransactionWithStatus getTransaction(@Nonnull byte[] transactionHash) throws IOException { + return getTransaction(transactionHash, null); + } + + TransactionWithStatus getTransaction(@Nonnull byte[] transactionHash, @Nullable Boolean onlyCommitted) throws IOException; /** * get transaction with verbosity value is 1 + * * @param transactionHash the transaction hash * @return the RPC does not return the transaction content and the field transaction must be null. * @throws IOException */ - TransactionWithStatus getTransactionStatus(byte[] transactionHash) throws IOException; - PackedTransactionWithStatus getPackedTransaction(byte[] transactionHash) throws IOException; + default TransactionWithStatus getTransactionStatus(@Nonnull byte[] transactionHash) throws IOException { + return getTransactionStatus(transactionHash, null); + } + + TransactionWithStatus getTransactionStatus(@Nonnull byte[] transactionHash, @Nullable Boolean onlyCommitted) throws IOException; + + default PackedTransactionWithStatus getPackedTransaction(@Nonnull byte[] transactionHash) throws IOException { + return getPackedTransaction(transactionHash, null); + } + + PackedTransactionWithStatus getPackedTransaction(@Nonnull byte[] transactionHash, @Nullable Boolean onlyCommitted) throws IOException; + byte[] getBlockHash(long blockNumber) throws IOException; BlockEconomicState getBlockEconomicState(byte[] blockHash) throws IOException; Header getTipHeader() throws IOException; + PackedHeader getPackedTipHeader() throws IOException; CellWithStatus getLiveCell(OutPoint outPoint, boolean withData) throws IOException; @@ -44,9 +66,11 @@ public interface CkbRpcApi { Epoch getEpochByNumber(long epochNumber) throws IOException; Header getHeader(byte[] blockHash) throws IOException; + PackedHeader getPackedHeader(byte[] blockHash) throws IOException; Header getHeaderByNumber(long blockNumber) throws IOException; + PackedHeader getPackedHeaderByNumber(long blockNumber) throws IOException; TransactionProof getTransactionProof(List txHashes) throws IOException; @@ -54,9 +78,13 @@ public interface CkbRpcApi { TransactionProof getTransactionProof(List txHashes, byte[] blockHash) throws IOException; List verifyTransactionProof(TransactionProof transactionProof) throws IOException; + TransactionAndWitnessProof getTransactionAndWitnessProof(List txHashes, byte[] blockHash) throws IOException; + List verifyTransactionAndWitnessProof(TransactionAndWitnessProof proof) throws IOException; + Block getForkBlock(byte[] blockHash) throws IOException; + PackedBlockWithCycles getPackedForkBlock(byte[] blockHash) throws IOException; Consensus getConsensus() throws IOException; @@ -129,5 +157,5 @@ long calculateDaoMaximumWithdraw(OutPoint outPoint, byte[] withdrawBlockHash) * @return Returns the fee_rate statistics of confirmed blocks on the chain. * @throws IOException if error there is an error */ - FeeRateStatics getFeeRateStatics(Integer target) throws IOException; + FeeRateStatistics getFeeRateStatistics(Integer target) throws IOException; } diff --git a/ckb/src/main/java/org/nervos/ckb/service/Api.java b/ckb/src/main/java/org/nervos/ckb/service/Api.java index ab1d1e17..29615aab 100644 --- a/ckb/src/main/java/org/nervos/ckb/service/Api.java +++ b/ckb/src/main/java/org/nervos/ckb/service/Api.java @@ -1,6 +1,9 @@ package org.nervos.ckb.service; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; import com.google.gson.reflect.TypeToken; +import org.jetbrains.annotations.NotNull; import org.nervos.ckb.CkbRpcApi; import org.nervos.ckb.type.*; import org.nervos.ckb.utils.Convert; @@ -9,13 +12,14 @@ import org.nervos.indexer.model.resp.*; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; public class Api implements CkbRpcApi { - private RpcService rpcService; + private final RpcService rpcService; public Api(String nodeUrl) { this(nodeUrl, false); @@ -29,6 +33,20 @@ public Api(RpcService rpcService) { this.rpcService = rpcService; } + // Remove trailing nulls for better backward compatibility. + @VisibleForTesting + public static List noTrailingNullParams(Object... ps) { + ArrayList params = Lists.newArrayList(ps); + for (int i = params.size() - 1; i >= 0; i--) { + if (params.get(i) == null) { + params.remove(i); + } else { + break; + } + } + return params; + } + @Override public Block getBlock(byte[] blockHash) throws IOException { return rpcService.post("get_block", Collections.singletonList(blockHash), Block.class); @@ -95,19 +113,19 @@ public PackedBlockWithCycles getPackedBlockByNumber(long blockNumber, boolean wi } @Override - public TransactionWithStatus getTransaction(byte[] transactionHash) throws IOException { + public TransactionWithStatus getTransaction(@NotNull byte[] transactionHash, Boolean onlyCommitted) throws IOException { return rpcService.post( - "get_transaction", Collections.singletonList(transactionHash), TransactionWithStatus.class); + "get_transaction", noTrailingNullParams(transactionHash, null, onlyCommitted), TransactionWithStatus.class); } @Override - public TransactionWithStatus getTransactionStatus(byte[] transactionHash) throws IOException { - return rpcService.post("get_transaction", Arrays.asList(transactionHash, 1), TransactionWithStatus.class); + public TransactionWithStatus getTransactionStatus(@NotNull byte[] transactionHash, Boolean onlyCommitted) throws IOException { + return rpcService.post("get_transaction", noTrailingNullParams(transactionHash, 1, onlyCommitted), TransactionWithStatus.class); } @Override - public PackedTransactionWithStatus getPackedTransaction(byte[] transactionHash) throws IOException { - return rpcService.post("get_transaction", Arrays.asList(transactionHash, 0), PackedTransactionWithStatus.class); + public PackedTransactionWithStatus getPackedTransaction(@NotNull byte[] transactionHash, Boolean onlyCommitted) throws IOException { + return rpcService.post("get_transaction", noTrailingNullParams(transactionHash, 0, onlyCommitted), PackedTransactionWithStatus.class); } @Override @@ -215,7 +233,7 @@ public List verifyTransactionProof(TransactionProof transactionProof) th public TransactionAndWitnessProof getTransactionAndWitnessProof(List txHashes, byte[] blockHash) throws IOException { return rpcService.post( "get_transaction_and_witness_proof", - blockHash == null ? Collections.singletonList(txHashes): Arrays.asList(txHashes, blockHash), + blockHash == null ? Collections.singletonList(txHashes) : Arrays.asList(txHashes, blockHash), TransactionAndWitnessProof.class); } @@ -248,7 +266,7 @@ public Consensus getConsensus() throws IOException { @Override public long getBlockMedianTime(byte[] blockHash) throws IOException { - return rpcService.post("get_block_median_time", Arrays.asList(blockHash), Long.class); + return rpcService.post("get_block_median_time", Collections.singletonList(blockHash), Long.class); } /** Stats RPC */ @@ -410,7 +428,7 @@ public TxsWithCells getTransactionsGrouped( @Override public CellCapacityResponse getCellsCapacity(SearchKey searchKey) throws IOException { return this.rpcService.post("get_cells_capacity", - Arrays.asList(searchKey), + Collections.singletonList(searchKey), CellCapacityResponse.class); } @@ -437,10 +455,10 @@ public List batchRPC(List requests) throws IOException { } @Override - public FeeRateStatics getFeeRateStatics(Integer target) throws IOException { + public FeeRateStatistics getFeeRateStatistics(Integer target) throws IOException { return rpcService.post( - "get_fee_rate_statics", + "get_fee_rate_statistics", target == null ? Collections.emptyList() : Collections.singletonList(target), - FeeRateStatics.class); + FeeRateStatistics.class); } } diff --git a/ckb/src/test/java/service/ApiTest.java b/ckb/src/test/java/service/ApiTest.java index 0d727d3f..b5224d0e 100644 --- a/ckb/src/test/java/service/ApiTest.java +++ b/ckb/src/test/java/service/ApiTest.java @@ -1,6 +1,5 @@ package service; -import com.google.common.collect.Streams; import org.junit.jupiter.api.*; import org.junit.jupiter.api.function.Executable; import org.nervos.ckb.service.Api; @@ -15,7 +14,6 @@ import java.io.IOException; import java.util.*; -import java.util.stream.Stream; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class ApiTest { @@ -32,6 +30,15 @@ public void init() { api = new Api("https://testnet.ckb.dev", false); } + @Test + public void testNoTrailingNullParams() { + Assertions.assertEquals(Arrays.asList(1, 2), Api.noTrailingNullParams(1, 2, null)); + Assertions.assertEquals(Arrays.asList(1, 2), Api.noTrailingNullParams(1, 2, null, null)); + Assertions.assertEquals(Arrays.asList(1, 2, null, 3), Api.noTrailingNullParams(1, 2, null, 3)); + Assertions.assertEquals(Collections.emptyList(), Api.noTrailingNullParams((Object) null)); + Assertions.assertEquals(Collections.emptyList(), Api.noTrailingNullParams(null, null)); + } + @Test public void testGetBlockByNumber() throws IOException { Block block = api.getBlockByNumber(1); @@ -759,20 +766,20 @@ public void execute() throws Throwable { @Test public void testGetFeeRateStatics() throws IOException { - FeeRateStatics statics = api.getFeeRateStatics(null); - Assertions.assertNotNull(statics); - Assertions.assertTrue(statics.mean > 0 && statics.median > 0); + FeeRateStatistics statistics = api.getFeeRateStatistics(null); + Assertions.assertNotNull(statistics); + Assertions.assertTrue(statistics.mean > 0 && statistics.median > 0); - statics = api.getFeeRateStatics(1); - Assertions.assertTrue(statics == null || statics.mean > 0 && statics.median > 0); + statistics = api.getFeeRateStatistics(1); + Assertions.assertTrue(statistics == null || statistics.mean > 0 && statistics.median > 0); - statics = api.getFeeRateStatics(101); - Assertions.assertTrue(statics == null || statics.mean > 0 && statics.median > 0); + statistics = api.getFeeRateStatistics(101); + Assertions.assertTrue(statistics == null || statistics.mean > 0 && statistics.median > 0); - statics = api.getFeeRateStatics(0); - Assertions.assertTrue(statics == null || statics.mean > 0 && statics.median > 0); + statistics = api.getFeeRateStatistics(0); + Assertions.assertTrue(statistics == null || statistics.mean > 0 && statistics.median > 0); - statics = api.getFeeRateStatics(102); - Assertions.assertTrue(statics == null || statics.mean > 0 && statics.median > 0); + statistics = api.getFeeRateStatistics(102); + Assertions.assertTrue(statistics == null || statistics.mean > 0 && statistics.median > 0); } } diff --git a/core/src/main/java/org/nervos/ckb/type/FeeRateStatics.java b/core/src/main/java/org/nervos/ckb/type/FeeRateStatistics.java similarity index 82% rename from core/src/main/java/org/nervos/ckb/type/FeeRateStatics.java rename to core/src/main/java/org/nervos/ckb/type/FeeRateStatistics.java index a47bdc99..e98741a0 100644 --- a/core/src/main/java/org/nervos/ckb/type/FeeRateStatics.java +++ b/core/src/main/java/org/nervos/ckb/type/FeeRateStatistics.java @@ -3,7 +3,7 @@ /** * The fee_rate statistics information, includes mean and median */ -public class FeeRateStatics { +public class FeeRateStatistics { public long mean; public long median; } diff --git a/core/src/main/java/org/nervos/ckb/type/TransactionWithStatus.java b/core/src/main/java/org/nervos/ckb/type/TransactionWithStatus.java index 23fb50af..86b8c2df 100644 --- a/core/src/main/java/org/nervos/ckb/type/TransactionWithStatus.java +++ b/core/src/main/java/org/nervos/ckb/type/TransactionWithStatus.java @@ -6,6 +6,7 @@ public class TransactionWithStatus { public TxStatus txStatus; public Transaction transaction; public Long cycles; + public Long timeAddedToPool; public static class TxStatus { public Status status; diff --git a/core/src/main/java/org/nervos/ckb/type/TxPoolInfo.java b/core/src/main/java/org/nervos/ckb/type/TxPoolInfo.java index 2c08e218..853d9c4c 100644 --- a/core/src/main/java/org/nervos/ckb/type/TxPoolInfo.java +++ b/core/src/main/java/org/nervos/ckb/type/TxPoolInfo.java @@ -10,4 +10,6 @@ public class TxPoolInfo { public long minFeeRate; public byte[] tipHash; public long tipNumber; + public long txSizeLimit; + public long maxTxPoolSize; } From d053055351c91cd2bcfe66361d6af8de344e19f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jul 2023 16:16:13 +0000 Subject: [PATCH 20/29] chore(deps): bump org.jetbrains.kotlin.jvm from 1.8.21 to 1.9.0 Bumps [org.jetbrains.kotlin.jvm](https://github.com/JetBrains/kotlin) from 1.8.21 to 1.9.0. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v1.8.21...v1.9.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5dda0832..fd3ae093 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { ext.guavaVersion = '32.1.1-jre' ext.junitVersion = '5.9.0' ext.kotestVersion = '5.6.1' - ext.kotlinVersion = "1.8.21" + ext.kotlinVersion = "1.9.0" ext.mockkVersion = "1.13.5" repositories { From d591da394ca7933fa5cafdeae1e0f6382be698cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jul 2023 16:16:32 +0000 Subject: [PATCH 21/29] chore(deps): bump junitVersion from 5.9.0 to 5.10.0 Bumps `junitVersion` from 5.9.0 to 5.10.0. Updates `org.junit.jupiter:junit-jupiter-api` from 5.9.0 to 5.10.0 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.10.0) Updates `org.junit.jupiter:junit-jupiter-engine` from 5.9.0 to 5.10.0 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.10.0) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- ckb-indexer/build.gradle | 4 ++-- ckb-mercury-sdk/build.gradle | 4 ++-- light-client/build.gradle | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 5dda0832..465bc45a 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { ext.loggingOkhttpVersion = '4.10.0' ext.slf4jVersion = '2.0.0' ext.guavaVersion = '32.1.1-jre' - ext.junitVersion = '5.9.0' + ext.junitVersion = '5.10.0' ext.kotestVersion = '5.6.1' ext.kotlinVersion = "1.8.21" ext.mockkVersion = "1.13.5" diff --git a/ckb-indexer/build.gradle b/ckb-indexer/build.gradle index a5000fe3..fdddaab5 100644 --- a/ckb-indexer/build.gradle +++ b/ckb-indexer/build.gradle @@ -7,8 +7,8 @@ dependencies { implementation "com.google.code.gson:gson:$gsonVersion" - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.3' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.0' // Enable use of the JUnitPlatform Runner within the IDE testImplementation("org.junit.platform:junit-platform-runner:1.9.3") diff --git a/ckb-mercury-sdk/build.gradle b/ckb-mercury-sdk/build.gradle index cb5f546a..7ddc8d42 100644 --- a/ckb-mercury-sdk/build.gradle +++ b/ckb-mercury-sdk/build.gradle @@ -9,8 +9,8 @@ dependencies { implementation "com.google.code.gson:gson:$gsonVersion" testImplementation project(":ckb") - testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.3") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0") // Enable use of the JUnitPlatform Runner within the IDE testImplementation("org.junit.platform:junit-platform-runner:1.9.3") } diff --git a/light-client/build.gradle b/light-client/build.gradle index 6293b451..84ae1aa4 100644 --- a/light-client/build.gradle +++ b/light-client/build.gradle @@ -17,8 +17,8 @@ dependencies { implementation("com.google.code.gson:gson:$gsonVersion") - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.3' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.0' testImplementation("io.kotest:kotest-runner-junit5:$kotestVersion") testImplementation("io.kotest:kotest-assertions-core:$kotestVersion") From 203f7b97214728d149022c9536499612614a46d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jul 2023 16:16:35 +0000 Subject: [PATCH 22/29] chore(deps): bump org.junit.platform:junit-platform-runner Bumps [org.junit.platform:junit-platform-runner](https://github.com/junit-team/junit5) from 1.9.3 to 1.10.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/commits) --- updated-dependencies: - dependency-name: org.junit.platform:junit-platform-runner dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- ckb-indexer/build.gradle | 2 +- ckb-mercury-sdk/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ckb-indexer/build.gradle b/ckb-indexer/build.gradle index a5000fe3..b27318e4 100644 --- a/ckb-indexer/build.gradle +++ b/ckb-indexer/build.gradle @@ -11,7 +11,7 @@ dependencies { testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.3' // Enable use of the JUnitPlatform Runner within the IDE - testImplementation("org.junit.platform:junit-platform-runner:1.9.3") + testImplementation("org.junit.platform:junit-platform-runner:1.10.0") } test { diff --git a/ckb-mercury-sdk/build.gradle b/ckb-mercury-sdk/build.gradle index cb5f546a..24a26e71 100644 --- a/ckb-mercury-sdk/build.gradle +++ b/ckb-mercury-sdk/build.gradle @@ -12,7 +12,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.3") // Enable use of the JUnitPlatform Runner within the IDE - testImplementation("org.junit.platform:junit-platform-runner:1.9.3") + testImplementation("org.junit.platform:junit-platform-runner:1.10.0") } test { From fc9f01139f0d75e02fabb0e6267e5d46b32ab67b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 03:57:11 +0000 Subject: [PATCH 23/29] chore(deps): bump kotestVersion from 5.6.1 to 5.6.2 Bumps `kotestVersion` from 5.6.1 to 5.6.2. Updates `io.kotest:kotest-runner-junit5` from 5.6.1 to 5.6.2 - [Release notes](https://github.com/kotest/kotest/releases) - [Commits](https://github.com/kotest/kotest/compare/v5.6.1...v5.6.2) Updates `io.kotest:kotest-assertions-core` from 5.6.1 to 5.6.2 - [Release notes](https://github.com/kotest/kotest/releases) - [Commits](https://github.com/kotest/kotest/compare/v5.6.1...v5.6.2) --- updated-dependencies: - dependency-name: io.kotest:kotest-runner-junit5 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.kotest:kotest-assertions-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2444b364..2b63b211 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { ext.slf4jVersion = '2.0.0' ext.guavaVersion = '32.1.1-jre' ext.junitVersion = '5.10.0' - ext.kotestVersion = '5.6.1' + ext.kotestVersion = '5.6.2' ext.kotlinVersion = "1.9.0" ext.mockkVersion = "1.13.5" From 0dba9089d25bf61cd60788659cbdd801633b8d4c Mon Sep 17 00:00:00 2001 From: Yin Guanhao <6764397+blckngm@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:08:16 +0800 Subject: [PATCH 24/29] Allow changeCapacity <= forceSmallChangeAsFee Co-authored-by: Quake Wang --- .../java/org/nervos/ckb/transaction/CkbTransactionBuilder.java | 2 +- .../nervos/ckb/transaction/TransactionBuilderConfiguration.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java b/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java index 205f7041..431c440a 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/CkbTransactionBuilder.java @@ -186,7 +186,7 @@ public TransactionWithScriptGroups build(Object... contexts) { if (forceSmallChangeAsFee != null) { long fee = calculateTxFee(tx, configuration.getFeeRate()); long changeCapacity = inputsCapacity - outputsCapacity - fee + reward; - if (changeCapacity > 0 && changeCapacity < forceSmallChangeAsFee) { + if (changeCapacity > 0 && changeCapacity <= forceSmallChangeAsFee) { enoughCapacity = true; break; } diff --git a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java index 1adfcebc..d4176151 100644 --- a/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java +++ b/ckb/src/main/java/org/nervos/ckb/transaction/TransactionBuilderConfiguration.java @@ -74,7 +74,7 @@ public Long getForceSmallChangeAsFee() { /** * Set forceSmallChangeAsFee. When building transaction, a change output will not be required if its capacity would be - * smaller than the specified amount. + * smaller than or equal to the specified amount. * * @param forceSmallChangeAsFee Should be positive. Unit is shannons. */ From 720ffa0902dda56eeec838db56045d3ee7f4c857 Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Thu, 24 Aug 2023 11:41:34 +0800 Subject: [PATCH 25/29] feat: support indexer filter script_len_range --- .../java/org/nervos/indexer/model/Filter.java | 1 + .../indexer/model/SearchKeyBuilder.java | 8 +++++++ ckb/src/test/java/service/ApiTest.java | 22 +++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/ckb-indexer/src/main/java/org/nervos/indexer/model/Filter.java b/ckb-indexer/src/main/java/org/nervos/indexer/model/Filter.java index a65ce71d..8a99e89c 100644 --- a/ckb-indexer/src/main/java/org/nervos/indexer/model/Filter.java +++ b/ckb-indexer/src/main/java/org/nervos/indexer/model/Filter.java @@ -9,4 +9,5 @@ public class Filter { public List outputDataLenRange; public List outputCapacityRange; public List blockRange; + public List scriptLenRange; } diff --git a/ckb-indexer/src/main/java/org/nervos/indexer/model/SearchKeyBuilder.java b/ckb-indexer/src/main/java/org/nervos/indexer/model/SearchKeyBuilder.java index 473fead3..972d92ac 100644 --- a/ckb-indexer/src/main/java/org/nervos/indexer/model/SearchKeyBuilder.java +++ b/ckb-indexer/src/main/java/org/nervos/indexer/model/SearchKeyBuilder.java @@ -53,6 +53,14 @@ public SearchKeyBuilder filterBlockRange(int inclusive, int exclusive) { return this; } + public SearchKeyBuilder filterScriptLen(int inclusive, int exclusive) { + initFilter(); + this.filter.scriptLenRange = new ArrayList<>(2); + this.filter.scriptLenRange.add(inclusive); + this.filter.scriptLenRange.add(exclusive); + return this; + } + private ScriptSearchMode _scriptSearchMode; public SearchKeyBuilder scriptSearchMode(ScriptSearchMode scriptSearchMode) { diff --git a/ckb/src/test/java/service/ApiTest.java b/ckb/src/test/java/service/ApiTest.java index b5224d0e..2d425cb4 100644 --- a/ckb/src/test/java/service/ApiTest.java +++ b/ckb/src/test/java/service/ApiTest.java @@ -9,6 +9,7 @@ import org.nervos.ckb.utils.Numeric; import org.nervos.indexer.model.Order; import org.nervos.indexer.model.ScriptSearchMode; +import org.nervos.indexer.model.SearchKey; import org.nervos.indexer.model.SearchKeyBuilder; import org.nervos.indexer.model.resp.*; @@ -680,6 +681,27 @@ void testGetCells() throws IOException { Assertions.assertTrue(cells.objects.size() > 0); } + @Test + void testGetCellsWithScriptLenRange() throws IOException { + SearchKey key = new SearchKeyBuilder() + .script( + new Script(Numeric.hexStringToByteArray( + "0x58c5f491aba6d61678b7cf7edf4910b1f5e00ec0cde2f42e0abb4fd9aff25a63"), + Numeric.hexStringToByteArray("0xe53f35ccf63bb37a3bb0ac3b7f89808077a78eae"), + Script.HashType.TYPE)) + .scriptType(ScriptType.LOCK) + .filterScript( + new Script(Numeric.hexStringToByteArray( + "0x58c5f491aba6d61678b7cf7edf4910b1f5e00ec0cde2f42e0abb4fd9aff25a63"), + Numeric.hexStringToByteArray("0xe53f35ccf63bb37a3bb0ac3b7f89808077a78eae"), + Script.HashType.TYPE) + ) + .filterScriptLen(0, 1) + .build(); + + api.getCells(key, Order.ASC, 10, null); + } + @Test void testGetCellCapacity() throws IOException { SearchKeyBuilder key = new SearchKeyBuilder(); From 891e8904af323fac5edfd125a95ee912a01d6544 Mon Sep 17 00:00:00 2001 From: Yin Guanhao Date: Thu, 24 Aug 2023 13:48:50 +0800 Subject: [PATCH 26/29] fix: value of data2 should be 4 instead of 3 --- core/src/main/java/org/nervos/ckb/type/Script.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/nervos/ckb/type/Script.java b/core/src/main/java/org/nervos/ckb/type/Script.java index a9694d0b..f9acd677 100644 --- a/core/src/main/java/org/nervos/ckb/type/Script.java +++ b/core/src/main/java/org/nervos/ckb/type/Script.java @@ -127,7 +127,7 @@ public enum HashType { @SerializedName("data1") DATA1(0x02), @SerializedName("data2") - DATA2(0x03); + DATA2(0x04); private final byte byteValue; @@ -147,7 +147,7 @@ public static HashType unpack(byte value) { return TYPE; case 0x02: return DATA1; - case 0x03: + case 0x04: return DATA2; default: throw new NullPointerException(); From dccee839178f013d61def1a62798e00ff29ff2a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:46:35 +0000 Subject: [PATCH 27/29] chore(deps): bump org.jetbrains.kotlin.jvm from 1.9.0 to 1.9.10 Bumps [org.jetbrains.kotlin.jvm](https://github.com/JetBrains/kotlin) from 1.9.0 to 1.9.10. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v1.9.10/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v1.9.0...v1.9.10) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2b63b211..29dcea5b 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { ext.guavaVersion = '32.1.1-jre' ext.junitVersion = '5.10.0' ext.kotestVersion = '5.6.2' - ext.kotlinVersion = "1.9.0" + ext.kotlinVersion = "1.9.10" ext.mockkVersion = "1.13.5" repositories { From 4f7b7427c33aa9d7b22a18630e96a297db4d70ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 02:16:58 +0000 Subject: [PATCH 28/29] chore(deps): bump io.mockk:mockk from 1.13.5 to 1.13.7 Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.5 to 1.13.7. - [Release notes](https://github.com/mockk/mockk/releases) - [Commits](https://github.com/mockk/mockk/commits) --- updated-dependencies: - dependency-name: io.mockk:mockk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 29dcea5b..67bc674f 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { ext.junitVersion = '5.10.0' ext.kotestVersion = '5.6.2' ext.kotlinVersion = "1.9.10" - ext.mockkVersion = "1.13.5" + ext.mockkVersion = "1.13.7" repositories { mavenCentral() From fbf73835fcb6cd4020e07d7a86f029fe81d59ec1 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Sun, 27 Oct 2024 16:52:27 +0800 Subject: [PATCH 29/29] Add support to v0.119.0 Signed-off-by: Eval EXEC --- .../main/java/org/nervos/ckb/CkbRpcApi.java | 10 ++++++ .../main/java/org/nervos/ckb/service/Api.java | 34 +++++++++++++++++++ .../java/org/nervos/ckb/type/SyncState.java | 16 ++++++--- .../java/org/nervos/ckb/type/TxPoolInfo.java | 4 ++- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/ckb/src/main/java/org/nervos/ckb/CkbRpcApi.java b/ckb/src/main/java/org/nervos/ckb/CkbRpcApi.java index 8d761e6d..11965349 100644 --- a/ckb/src/main/java/org/nervos/ckb/CkbRpcApi.java +++ b/ckb/src/main/java/org/nervos/ckb/CkbRpcApi.java @@ -106,6 +106,16 @@ default PackedTransactionWithStatus getPackedTransaction(@Nonnull byte[] transac byte[] sendTransaction(Transaction transaction, OutputsValidator outputsValidator) throws IOException; + byte[] sendTestTransaction(Transaction transaction) throws IOException; + + byte[] sendTestTransaction(Transaction transaction, OutputsValidator outputsValidator) + throws IOException; + + byte[] testTxPoolAccept(Transaction transaction) throws IOException; + + byte[] testTxPoolAccept(Transaction transaction, OutputsValidator outputsValidator) + throws IOException; + NodeInfo localNodeInfo() throws IOException; List getPeers() throws IOException; diff --git a/ckb/src/main/java/org/nervos/ckb/service/Api.java b/ckb/src/main/java/org/nervos/ckb/service/Api.java index 29615aab..9cbeeae7 100644 --- a/ckb/src/main/java/org/nervos/ckb/service/Api.java +++ b/ckb/src/main/java/org/nervos/ckb/service/Api.java @@ -297,6 +297,40 @@ public RawTxPoolVerbose getRawTxPoolVerbose() throws IOException { "get_raw_tx_pool", Collections.singletonList(true), RawTxPoolVerbose.class); } + @Override + public byte[] sendTestTransaction(Transaction transaction) throws IOException { + return rpcService.post( + "send_test_transaction", + Arrays.asList(Convert.parseTransaction(transaction), OutputsValidator.PASSTHROUGH), + byte[].class); + } + + @Override + public byte[] sendTestTransaction(Transaction transaction, OutputsValidator outputsValidator) + throws IOException { + return rpcService.post( + "send_test_transaction", + Arrays.asList(Convert.parseTransaction(transaction), outputsValidator), + byte[].class); + } + + @Override + public byte[] testTxPoolAccept(Transaction transaction) throws IOException { + return rpcService.post( + "test_tx_pool_accept", + Arrays.asList(Convert.parseTransaction(transaction), OutputsValidator.PASSTHROUGH), + byte[].class); + } + + @Override + public byte[] testTxPoolAccept(Transaction transaction, OutputsValidator outputsValidator) + throws IOException { + return rpcService.post( + "test_tx_pool_accept", + Arrays.asList(Convert.parseTransaction(transaction), outputsValidator), + byte[].class); + } + @Override public byte[] sendTransaction(Transaction transaction) throws IOException { return rpcService.post( diff --git a/core/src/main/java/org/nervos/ckb/type/SyncState.java b/core/src/main/java/org/nervos/ckb/type/SyncState.java index 488f1802..5b307a6f 100644 --- a/core/src/main/java/org/nervos/ckb/type/SyncState.java +++ b/core/src/main/java/org/nervos/ckb/type/SyncState.java @@ -1,12 +1,20 @@ package org.nervos.ckb.type; public class SyncState { - public boolean ibd; + public byte[] assumeValidTarget; + public boolean assumeValidTargetReached; public long bestKnownBlockNumber; public long bestKnownBlockTimestamp; - public long orphanBlocksCount; - public long inflightBlocksCount; public long fastTime; - public long normalTime; + public boolean ibd; + public long inflightBlocksCount; public long lowTime; + public long minChainWork; + public boolean minChainWorkReached; + public long normalTime; + public long orphanBlocksCount; + public byte[] tipHash; + public long tipNumber; + public byte[] unverifiedTipHash; + public long unverifiedTipNumber; } diff --git a/core/src/main/java/org/nervos/ckb/type/TxPoolInfo.java b/core/src/main/java/org/nervos/ckb/type/TxPoolInfo.java index 853d9c4c..771b88d8 100644 --- a/core/src/main/java/org/nervos/ckb/type/TxPoolInfo.java +++ b/core/src/main/java/org/nervos/ckb/type/TxPoolInfo.java @@ -10,6 +10,8 @@ public class TxPoolInfo { public long minFeeRate; public byte[] tipHash; public long tipNumber; - public long txSizeLimit; public long maxTxPoolSize; + public long minRbfRate; + public long txSizeLimit; + public long verifyQueueSize; }