Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ckb/src/main/java/org/nervos/ckb/CkbRpcApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ byte[] sendTransaction(Transaction transaction, OutputsValidator outputsValidato
byte[] sendTestTransaction(Transaction transaction, OutputsValidator outputsValidator)
throws IOException;

byte[] testTxPoolAccept(Transaction transaction) throws IOException;
EntryCompleted testTxPoolAccept(Transaction transaction) throws IOException;

byte[] testTxPoolAccept(Transaction transaction, OutputsValidator outputsValidator)
EntryCompleted testTxPoolAccept(Transaction transaction, OutputsValidator outputsValidator)
throws IOException;

NodeInfo localNodeInfo() throws IOException;
Expand Down
6 changes: 3 additions & 3 deletions ckb/src/main/java/org/nervos/ckb/service/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -315,20 +315,20 @@ public byte[] sendTestTransaction(Transaction transaction, OutputsValidator outp
}

@Override
public byte[] testTxPoolAccept(Transaction transaction) throws IOException {
public EntryCompleted 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)
public EntryCompleted testTxPoolAccept(Transaction transaction, OutputsValidator outputsValidator)
throws IOException {
return rpcService.post(
"test_tx_pool_accept",
Arrays.asList(Convert.parseTransaction(transaction), outputsValidator),
byte[].class);
EntryCompleted.class);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.nervos.ckb.Network;
import org.nervos.ckb.transaction.handler.*;
import org.nervos.ckb.type.MultisigVersion;

import javax.annotation.Nullable;
import java.util.ArrayList;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,69 +4,88 @@
import org.nervos.ckb.sign.ScriptGroup;
import org.nervos.ckb.sign.signer.Secp256k1Blake160MultisigAllSigner;
import org.nervos.ckb.transaction.AbstractTransactionBuilder;
import org.nervos.ckb.type.CellDep;
import org.nervos.ckb.type.OutPoint;
import org.nervos.ckb.type.Script;
import org.nervos.ckb.type.WitnessArgs;
import org.nervos.ckb.type.*;
import org.nervos.ckb.utils.Numeric;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Secp256k1Blake160MultisigAllScriptHandler implements ScriptHandler {
private List<CellDep> cellDeps;
private byte[] codeHash;
private Network network;

public Secp256k1Blake160MultisigAllScriptHandler() {
}

public List<CellDep> getCellDeps() {
return cellDeps;
}

public void setCellDeps(List<CellDep> cellDeps) {
this.cellDeps = cellDeps;
}

public byte[] getCodeHash() {
return codeHash;
}

public void setCodeHash(byte[] codeHash) {
this.codeHash = codeHash;
}

@Override
public void init(Network network) {
public List<CellDep> getCellDeps(MultisigVersion multisigVersion) {
OutPoint outPoint = new OutPoint();
if (network == Network.MAINNET) {
outPoint.txHash = Numeric.hexStringToByteArray("0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c");
outPoint.index = 1;
} else if (network == Network.TESTNET) {
outPoint.txHash = Numeric.hexStringToByteArray("0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37");
outPoint.index = 1;
if (this.network == Network.MAINNET) {
switch (multisigVersion) {
case Legacy:
outPoint.txHash = Numeric.hexStringToByteArray("0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c");
outPoint.index = 1;
break;
case V2:
outPoint.txHash = Numeric.hexStringToByteArray("0x6888aa39ab30c570c2c30d9d5684d3769bf77265a7973211a3c087fe8efbf738");
outPoint.index = 0;
break;
default:
throw new IllegalArgumentException("Unsupported multisig version");
}
} else if (this.network == Network.TESTNET) {
switch (multisigVersion) {
case Legacy:
outPoint.txHash = Numeric.hexStringToByteArray("0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37");
outPoint.index = 1;
break;
case V2:
outPoint.txHash = Numeric.hexStringToByteArray("0x2eefdeb21f3a3edf697c28a52601b4419806ed60bb427420455cc29a090b26d5");
outPoint.index = 0;
break;
default:
throw new IllegalArgumentException("Unsupported multisig version");
}
} else {
throw new IllegalArgumentException("Unsupported network");
}
CellDep cellDep = new CellDep();
cellDep.outPoint = outPoint;
cellDep.depType = CellDep.DepType.DEP_GROUP;
cellDeps = Arrays.asList(cellDep);
this.codeHash = Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH;
return Arrays.asList(cellDep);
}

private boolean isMatched(Script script) {

@Override
public void init(Network network) {
this.network = network;
}

private Optional<MultisigVersion> isMatched(Script script) {
if (script == null) {
return false;
return Optional.empty();
}

if (Arrays.equals(script.codeHash, MultisigVersion.Legacy.codeHash()) && script.hashType == MultisigVersion.Legacy.hashType()) {
return Optional.of(MultisigVersion.Legacy);
} else if (Arrays.equals(script.codeHash, MultisigVersion.V2.codeHash()) && script.hashType == MultisigVersion.V2.hashType()) {
return Optional.of(MultisigVersion.V2);
} else {
return Optional.empty();
}
return Arrays.equals(script.codeHash, codeHash);
}

@Override
public boolean buildTransaction(AbstractTransactionBuilder txBuilder, ScriptGroup scriptGroup, Object context) {
if (scriptGroup == null || !isMatched(scriptGroup.getScript())) {
if (scriptGroup == null) {
return false;
}
Optional<MultisigVersion> multisigVersion = isMatched(scriptGroup.getScript());
if (!multisigVersion.isPresent()) {
return false;
}

List<CellDep> cellDeps = this.getCellDeps(multisigVersion.get());

Secp256k1Blake160MultisigAllSigner.MultisigScript multisigScript;
if (context instanceof Secp256k1Blake160MultisigAllSigner.MultisigScript) {
multisigScript = (Secp256k1Blake160MultisigAllSigner.MultisigScript) context;
Expand Down
12 changes: 10 additions & 2 deletions core/src/main/java/org/nervos/ckb/sign/TransactionSigner.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ public class TransactionSigner {
.registerLockScriptSigner(
Script.SECP256K1_BLAKE160_SIGNHASH_ALL_CODE_HASH, new Secp256k1Blake160SighashAllSigner())
.registerLockScriptSigner(
Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH, new Secp256k1Blake160MultisigAllSigner())
Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_LEGACY, new Secp256k1Blake160MultisigAllSigner())
.registerLockScriptData1Signer(
Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_V2, new Secp256k1Blake160MultisigAllSigner())
.registerLockScriptSigner(
Script.ANY_CAN_PAY_CODE_HASH_TESTNET, new AcpSigner())
.registerLockScriptSigner(
Expand All @@ -31,7 +33,9 @@ Script.PW_LOCK_CODE_HASH_TESTNET, new PwSigner())
.registerLockScriptSigner(
Script.SECP256K1_BLAKE160_SIGNHASH_ALL_CODE_HASH, new Secp256k1Blake160SighashAllSigner())
.registerLockScriptSigner(
Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH, new Secp256k1Blake160MultisigAllSigner())
Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_LEGACY, new Secp256k1Blake160MultisigAllSigner())
.registerLockScriptData1Signer(
Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_V2, new Secp256k1Blake160MultisigAllSigner())
.registerLockScriptSigner(
Script.ANY_CAN_PAY_CODE_HASH_MAINNET, new AcpSigner())
.registerLockScriptSigner(
Expand Down Expand Up @@ -83,6 +87,10 @@ public TransactionSigner registerLockScriptSigner(byte[] codeHash, ScriptSigner
return register(codeHash, Script.HashType.TYPE, ScriptType.LOCK, scriptSigner);
}

public TransactionSigner registerLockScriptData1Signer(byte[] codeHash, ScriptSigner scriptSigner) {
return register(codeHash, Script.HashType.DATA1, ScriptType.LOCK, scriptSigner);
}

public TransactionSigner registerLockScriptSigner(String codeHash, ScriptSigner scriptSigner) {
return registerLockScriptSigner(Numeric.hexStringToByteArray(codeHash), scriptSigner);
}
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/org/nervos/ckb/type/EntryCompleted.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.nervos.ckb.type;

public class EntryCompleted {
public long cycles;
public long fee;
}
35 changes: 35 additions & 0 deletions core/src/main/java/org/nervos/ckb/type/MultisigVersion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.nervos.ckb.type;

public enum MultisigVersion {
/// Multisig Script deployed on Genesis Block
/// https://explorer.nervos.org/script/0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8/type
Legacy,
/// Latest multisig script, Enhance multisig handling for optional since value
/// https://github.com/nervosnetwork/ckb-system-scripts/pull/99
/// https://explorer.nervos.org/script/0x36c971b8d41fbd94aabca77dc75e826729ac98447b46f91e00796155dddb0d29/data1
V2;

public byte[] codeHash(){
switch (this)
{
case Legacy:
return Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_LEGACY;
case V2:
return Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_V2;
default:
throw new IllegalArgumentException("Unknown multisig version: " + this);
}
}

public Script.HashType hashType() {
switch (this)
{
case Legacy:
return Script.HashType.TYPE;
case V2:
return Script.HashType.DATA1;
default:
throw new IllegalArgumentException("Unknown multisig version: " + this);
}
}
}
10 changes: 9 additions & 1 deletion core/src/main/java/org/nervos/ckb/type/Script.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@
import static org.nervos.ckb.utils.MoleculeConverter.packByte32;
import static org.nervos.ckb.utils.MoleculeConverter.packBytes;


public class Script {
public static final byte[] SECP256K1_BLAKE160_SIGNHASH_ALL_CODE_HASH =
Numeric.hexStringToByteArray("0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8");
public static final byte[] SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH =
// Multisig Script deployed on Genesis Block
// https://explorer.nervos.org/script/0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8/type
public static final byte[] SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_LEGACY =
Numeric.hexStringToByteArray("0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8");
// Latest multisig script, Enhance multisig handling for optional since value
// https://github.com/nervosnetwork/ckb-system-scripts/pull/99
// https://explorer.nervos.org/script/0x36c971b8d41fbd94aabca77dc75e826729ac98447b46f91e00796155dddb0d29/data1
public static final byte[] SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_V2=
Numeric.hexStringToByteArray("0x36c971b8d41fbd94aabca77dc75e826729ac98447b46f91e00796155dddb0d29");
public static final byte[] ANY_CAN_PAY_CODE_HASH_MAINNET =
Numeric.hexStringToByteArray("0xd369597ff47f29fbc0d47d2e3775370d1250b85140c670e4718af712983a2354");
public static final byte[] ANY_CAN_PAY_CODE_HASH_TESTNET =
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/java/org/nervos/ckb/utils/address/Address.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private static Address decodeShort(byte[] payload, Network network) {
if (args.length != 20) {
throw new AddressFormatException("Invalid args length " + args.length);
}
codeHash = Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH;
codeHash = Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_LEGACY;
} else if (codeHashIndex == 0x02) {
if (args.length < 20 || args.length > 22) {
throw new AddressFormatException("Invalid args length " + args.length);
Expand Down Expand Up @@ -145,7 +145,7 @@ public String encodeShort() {
byte[] codeHash = script.codeHash;
if (Arrays.equals(codeHash, Script.SECP256K1_BLAKE160_SIGNHASH_ALL_CODE_HASH)) {
codeHashIndex = 0x00;
} else if (Arrays.equals(codeHash, Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH)) {
} else if (Arrays.equals(codeHash, Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_LEGACY)) {
codeHashIndex = 0x01;
} else if ((network == Network.MAINNET && Arrays.equals(codeHash, Script.ANY_CAN_PAY_CODE_HASH_MAINNET)
|| (network == Network.TESTNET && Arrays.equals(codeHash, Script.ANY_CAN_PAY_CODE_HASH_TESTNET)))) {
Expand Down Expand Up @@ -260,4 +260,4 @@ public int hashCode() {
result = 31 * result + network.hashCode();
return result;
}
}
}
15 changes: 14 additions & 1 deletion core/src/test/java/utils/AddressTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.junit.jupiter.api.Test;
import org.nervos.ckb.Network;
import org.nervos.ckb.type.MultisigVersion;
import org.nervos.ckb.type.Script;
import org.nervos.ckb.utils.Numeric;
import org.nervos.ckb.utils.address.Address;
Expand All @@ -22,7 +23,7 @@ public void testDecodeDecode() {
testShort(script, Network.MAINNET, "ckb1qyqt8xaupvm8837nv3gtc9x0ekkj64vud3jqfwyw5v");
testShort(script, Network.TESTNET, "ckt1qyqt8xaupvm8837nv3gtc9x0ekkj64vud3jq5t63cs");

script = generateScript(Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH,
script = generateScript(Script.SECP256K1_BLAKE160_MULTISIG_ALL_CODE_HASH_LEGACY,
"4fb2be2e5d0c1a3b8694f832350a33c1685d477a", Script.HashType.TYPE);
testShort(script, Network.MAINNET, "ckb1qyq5lv479ewscx3ms620sv34pgeuz6zagaaqklhtgg");
testShort(script, Network.TESTNET, "ckt1qyq5lv479ewscx3ms620sv34pgeuz6zagaaqt6f5y5");
Expand Down Expand Up @@ -59,6 +60,18 @@ public void testDecodeDecode() {
"b39bbc0b3673c7d36450bc14cfcdad2d559c6c64", Script.HashType.DATA1);
testFullBech32m(script, Network.MAINNET, "ckb1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq4nnw7qkdnnclfkg59uzn8umtfd2kwxceqcydzyt");
testFullBech32m(script, Network.TESTNET, "ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq4nnw7qkdnnclfkg59uzn8umtfd2kwxceqkkxdwn");

// multiscript v2

script = generateScript(MultisigVersion.V2.codeHash(),
"986b5c23988427044e57d188fee45530d8877bcc", MultisigVersion.V2.hashType());
testFullBech32m(script, Network.MAINNET, "ckb1qqmvjudc6s0mm992hjnhm367sfnjntycg3a5d7g7qpukz4wamvxjjq5cddwz8xyyyuzyu4733rlwg4fsmzrhhnqvclulh");
testFullBech32m(script, Network.TESTNET, "ckt1qqmvjudc6s0mm992hjnhm367sfnjntycg3a5d7g7qpukz4wamvxjjq5cddwz8xyyyuzyu4733rlwg4fsmzrhhnqz25n40");

script = generateScript(MultisigVersion.Legacy.codeHash(),
"986b5c23988427044e57d188fee45530d8877bcc", MultisigVersion.Legacy.hashType());
testFullBech32m(script, Network.MAINNET, "ckb1qpw9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32sqvcddwz8xyyyuzyu4733rlwg4fsmzrhhnqq5gm75");
testFullBech32m(script, Network.TESTNET, "ckt1qpw9q60tppt7l3j7r09qcp7lxnp3vcanvgha8pmvsa3jplykxn32sqvcddwz8xyyyuzyu4733rlwg4fsmzrhhnqwxr55v");
}

private void testShort(Script script, Network network, String encoded) {
Expand Down
Loading
Loading