first commit

This commit is contained in:
2026-02-09 17:56:39 +08:00
parent a9c1b81aea
commit 78fcb7aa37
6 changed files with 481 additions and 20 deletions

4
.gitignore vendored
View File

@@ -42,4 +42,6 @@ bin/
### Mac OS ###
.DS_Store
fisco/
/fisco/
/conf

View File

@@ -110,22 +110,4 @@ CryptoKeyPair keyPair = AccountGenerator.loadPEMAccount("account/alice.pem", Cry
- 证书文件
- 群组配置
- 加密类型配置
## 开发环境
- IDE: IntelliJ IDEA推荐
- 操作系统: macOS / Linux / Windows
- Java 版本: JDK 8+
## 许可证
本项目采用开源许可证发布。
## 相关资源
- [FISCO BCOS 官方文档](https://fisco-bcos-documentation.readthedocs.io/)
- [FISCO BCOS Java SDK 文档](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/sdk/java_sdk/index.html)
## 贡献
欢迎提交 Issue 和 Pull Request 来改进这个项目。
将SDK证书拷贝到Java SDK的示例如下(这里假设SDK证书位于~/fisco/nodes/127.0.0.1/sdk目录)

View File

@@ -0,0 +1,165 @@
package com.org.fisco;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.model.CryptoType;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* 账户生成工具类
* 支持生成PEM格式的账户文件
*/
public class AccountGenerator {
private static final String ACCOUNT_DIR = "account";
/**
* 生成PEM格式的账户文件
* @param accountName 账户名称
* @param cryptoType 加密类型 (0: ECDSA, 1: 国密SM)
*/
public static CryptoKeyPair generatePEMAccount(String accountName, int cryptoType) {
try {
// 创建账户目录
File accountDir = new File(ACCOUNT_DIR);
if (!accountDir.exists()) {
accountDir.mkdirs();
}
// 创建加密套件
CryptoSuite cryptoSuite = new CryptoSuite(cryptoType);
// 生成密钥对
CryptoKeyPair cryptoKeyPair = cryptoSuite.createKeyPair();
// 获取私钥和公钥
String privateKey = cryptoKeyPair.getHexPrivateKey();
String publicKey = cryptoKeyPair.getHexPublicKey();
String address = cryptoKeyPair.getAddress();
// 保存为PEM格式
String pemFilePath = ACCOUNT_DIR + "/" + accountName + ".pem";
savePEMFile(pemFilePath, privateKey, publicKey, address, cryptoType);
System.out.println("=== PEM账户生成成功 ===");
System.out.println("账户名称: " + accountName);
System.out.println("账户地址: " + address);
System.out.println("公钥: " + publicKey);
System.out.println("私钥: " + privateKey);
System.out.println("文件路径: " + pemFilePath);
System.out.println("加密类型: " + (cryptoType == CryptoType.ECDSA_TYPE ? "ECDSA" : "国密SM"));
System.out.println("========================\n");
return cryptoKeyPair;
} catch (Exception e) {
System.err.println("生成PEM账户失败: " + e.getMessage());
e.printStackTrace();
return null;
}
}
/**
* 保存PEM格式文件
*/
private static void savePEMFile(String filePath, String privateKey, String publicKey,
String address, int cryptoType) throws IOException {
try (FileWriter writer = new FileWriter(filePath)) {
writer.write("-----BEGIN PRIVATE KEY-----\n");
writer.write(privateKey + "\n");
writer.write("-----END PRIVATE KEY-----\n");
writer.write("-----BEGIN PUBLIC KEY-----\n");
writer.write(publicKey + "\n");
writer.write("-----END PUBLIC KEY-----\n");
writer.write("-----BEGIN ADDRESS-----\n");
writer.write(address + "\n");
writer.write("-----END ADDRESS-----\n");
writer.write("-----BEGIN CRYPTO TYPE-----\n");
writer.write(cryptoType + "\n");
writer.write("-----END CRYPTO TYPE-----\n");
}
}
/**
* 从PEM文件加载账户
* @param pemFilePath PEM文件路径
* @param cryptoType 加密类型
*/
public static CryptoKeyPair loadPEMAccount(String pemFilePath, int cryptoType) {
try {
// 读取PEM文件获取私钥
String privateKey = readPrivateKeyFromPEM(pemFilePath);
// 创建加密套件
CryptoSuite cryptoSuite = new CryptoSuite(cryptoType);
// 从私钥恢复密钥对
CryptoKeyPair cryptoKeyPair = cryptoSuite.createKeyPair(privateKey);
System.out.println("=== PEM账户加载成功 ===");
System.out.println("文件路径: " + pemFilePath);
System.out.println("账户地址: " + cryptoKeyPair.getAddress());
System.out.println("=======================\n");
return cryptoKeyPair;
} catch (Exception e) {
System.err.println("加载PEM账户失败: " + e.getMessage());
e.printStackTrace();
return null;
}
}
/**
* 从PEM文件读取私钥
*/
private static String readPrivateKeyFromPEM(String filePath) throws IOException {
java.nio.file.Path path = java.nio.file.Paths.get(filePath);
String content = new String(java.nio.file.Files.readAllBytes(path));
// 提取私钥部分
String[] lines = content.split("\n");
for (int i = 0; i < lines.length; i++) {
if (lines[i].contains("BEGIN PRIVATE KEY")) {
return lines[i + 1].trim();
}
}
throw new IOException("无法从PEM文件中读取私钥");
}
/**
* 主函数 - 演示如何生成账户
*/
public static void main(String[] args) {
System.out.println("========================================");
System.out.println(" FISCO BCOS 账户生成工具");
System.out.println("========================================\n");
// 加密类型0 表示 ECDSA1 表示国密SM
int cryptoType = CryptoType.SM_TYPE; // 根据你的配置使用国密
// 1. 生成PEM格式账户
System.out.println("【1】生成PEM格式账户:");
CryptoKeyPair pemAccount = generatePEMAccount("user_pem", cryptoType);
// 2. 演示加载PEM账户
System.out.println("【2】加载PEM账户:");
CryptoKeyPair loadedPemAccount = loadPEMAccount(ACCOUNT_DIR + "/user_pem.pem", cryptoType);
// 3. 生成多个账户示例
System.out.println("【3】生成多个用户账户:");
generatePEMAccount("alice", cryptoType);
generatePEMAccount("bob", cryptoType);
generatePEMAccount("charlie", cryptoType);
System.out.println("========================================");
System.out.println("账户生成完成!账户文件保存在 " + ACCOUNT_DIR + " 目录下");
System.out.println("========================================");
System.exit(0);
}
}

View File

@@ -0,0 +1,55 @@
package com.org.fisco;
import org.fisco.bcos.sdk.BcosSDK;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.config.exceptions.ConfigException;
import org.fisco.bcos.sdk.transaction.model.exception.ContractException;
public class BcosSDKTest
{
// 获取配置文件路径
public final String configFile = BcosSDKTest.class.getClassLoader().getResource("config.toml").getPath();
public void testClient() throws ConfigException, ContractException {
// 初始化BcosSDK
BcosSDK sdk = BcosSDK.build(configFile);
// 为群组1初始化client
Client client = sdk.getClient(Integer.valueOf(1));
// 获取群组1的块高
java.math.BigInteger blockNumber = client.getBlockNumber().getBlockNumber();
// 向群组1部署HelloWorld合约
CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().getCryptoKeyPair();
HelloWorld helloWorld = HelloWorld.deploy(client, cryptoKeyPair);
// 调用HelloWorld合约的get接口
String getValue = helloWorld.get();
// 调用HelloWorld合约的set接口
TransactionReceipt receipt = helloWorld.set("Hello, fisco");
// 打印结果
System.out.println("当前块高: " + blockNumber);
System.out.println("合约地址: " + helloWorld.getContractAddress());
System.out.println("获取的值: " + getValue);
System.out.println("交易哈希: " + receipt.getTransactionHash());
System.out.println("交易状态: " + receipt.getStatus());
}
public static void main(String[] args) {
try {
BcosSDKTest test = new BcosSDKTest();
test.testClient();
System.out.println("测试执行成功!");
} catch (Exception e) {
System.err.println("测试执行失败: " + e.getMessage());
e.printStackTrace();
System.exit(1);
}
// 强制退出程序,避免后台线程继续运行
System.exit(0);
}
}

View File

@@ -0,0 +1,97 @@
package com.org.fisco;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.abi.FunctionReturnDecoder;
import org.fisco.bcos.sdk.abi.TypeReference;
import org.fisco.bcos.sdk.abi.datatypes.Function;
import org.fisco.bcos.sdk.abi.datatypes.Type;
import org.fisco.bcos.sdk.abi.datatypes.Utf8String;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple1;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.contract.Contract;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.model.CryptoType;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.transaction.model.exception.ContractException;
@SuppressWarnings("unchecked")
public class HelloWorld extends Contract {
public static final String[] BINARY_ARRAY = {"608060405234801561001057600080fd5b506040805190810160405280600d81526020017f48656c6c6f2c20576f726c6421000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6102d7806101166000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634ed3885e146100515780636d4ce63c146100ba575b600080fd5b34801561005d57600080fd5b506100b8600480360381019080803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061014a565b005b3480156100c657600080fd5b506100cf610164565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561010f5780820151818401526020810190506100f4565b50505050905090810190601f16801561013c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b8060009080519060200190610160929190610206565b5050565b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101fc5780601f106101d1576101008083540402835291602001916101fc565b820191906000526020600020905b8154815290600101906020018083116101df57829003601f168201915b5050505050905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a7230582038c8771306a5ae97d4fdca0877d9b0956d82586811ffcf98bb8156535fdf44160029"};
public static final String BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", BINARY_ARRAY);
public static final String[] SM_BINARY_ARRAY = {"608060405234801561001057600080fd5b506040805190810160405280600d81526020017f48656c6c6f2c20576f726c6421000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610107565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100a357805160ff19168380011785556100d1565b828001600101855582156100d1579182015b828111156100d05782518255916020019190600101906100b5565b5b5090506100de91906100e2565b5090565b61010491905b808211156101005760008160009055506001016100e8565b5090565b90565b6102d7806101166000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063299f7f9d146100515780633590b49f146100e1575b600080fd5b34801561005d57600080fd5b5061006661014a565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100a657808201518184015260208101905061008b565b50505050905090810190601f1680156100d35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100ed57600080fd5b50610148600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506101ec565b005b606060008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156101e25780601f106101b7576101008083540402835291602001916101e2565b820191906000526020600020905b8154815290600101906020018083116101c557829003601f168201915b5050505050905090565b8060009080519060200190610202929190610206565b5050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061024757805160ff1916838001178555610275565b82800160010185558215610275579182015b82811115610274578251825591602001919060010190610259565b5b5090506102829190610286565b5090565b6102a891905b808211156102a457600081600090555060010161028c565b5090565b905600a165627a7a7230582055a23c331239de7d84cefde97edd7668949c0b256facb94ed4e0ee831f023d590029"};
public static final String SM_BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);
public static final String[] ABI_ARRAY = {"[{\"constant\":false,\"inputs\":[{\"name\":\"n\",\"type\":\"string\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]"};
public static final String ABI = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", ABI_ARRAY);
public static final String FUNC_SET = "set";
public static final String FUNC_GET = "get";
protected HelloWorld(String contractAddress, Client client, CryptoKeyPair credential) {
super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
}
public static String getBinary(CryptoSuite cryptoSuite) {
return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
}
public TransactionReceipt set(String n) {
final Function function = new Function(
FUNC_SET,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(n)),
Collections.<TypeReference<?>>emptyList());
return executeTransaction(function);
}
public byte[] set(String n, TransactionCallback callback) {
final Function function = new Function(
FUNC_SET,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(n)),
Collections.<TypeReference<?>>emptyList());
return asyncExecuteTransaction(function, callback);
}
public String getSignedTransactionForSet(String n) {
final Function function = new Function(
FUNC_SET,
Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Utf8String(n)),
Collections.<TypeReference<?>>emptyList());
return createSignedTransaction(function);
}
public Tuple1<String> getSetInput(TransactionReceipt transactionReceipt) {
String data = transactionReceipt.getInput().substring(10);
final Function function = new Function(FUNC_SET,
Arrays.<Type>asList(),
Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}));
List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
return new Tuple1<String>(
(String) results.get(0).getValue()
);
}
public String get() throws ContractException {
final Function function = new Function(FUNC_GET,
Arrays.<Type>asList(),
Arrays.<TypeReference<?>>asList(new TypeReference<Utf8String>() {}));
return executeCallWithSingleValueReturn(function, String.class);
}
public static HelloWorld load(String contractAddress, Client client, CryptoKeyPair credential) {
return new HelloWorld(contractAddress, client, credential);
}
public static HelloWorld deploy(Client client, CryptoKeyPair credential) throws ContractException {
return deploy(HelloWorld.class, client, credential, getBinary(client.getCryptoSuite()), "");
}
}

View File

@@ -0,0 +1,160 @@
package com.org.fisco;
import org.fisco.bcos.sdk.BcosSDK;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.config.exceptions.ConfigException;
import org.fisco.bcos.sdk.transaction.model.exception.ContractException;
import org.fisco.bcos.sdk.model.CryptoType;
/**
* 使用指定账户发送HelloWorld合约交易
* 支持PEM格式的账户
*/
public class HelloWorldWithAccount {
// 获取配置文件路径
public final String configFile = HelloWorldWithAccount.class.getClassLoader()
.getResource("config.toml").getPath();
// 账户目录
private static final String ACCOUNT_DIR = "account";
/**
* 使用PEM格式账户发送交易
* @param pemAccountName PEM账户名称
* @param cryptoType 加密类型
*/
public void testWithPEMAccount(String pemAccountName, int cryptoType)
throws ConfigException, ContractException {
System.out.println("\n========================================");
System.out.println("使用PEM格式账户发送交易");
System.out.println("========================================");
// 初始化BcosSDK
BcosSDK sdk = BcosSDK.build(configFile);
// 为群组1初始化client
Client client = sdk.getClient(Integer.valueOf(1));
// 从PEM文件加载账户
String pemFilePath = ACCOUNT_DIR + "/" + pemAccountName + ".pem";
CryptoKeyPair cryptoKeyPair = AccountGenerator.loadPEMAccount(pemFilePath, cryptoType);
if (cryptoKeyPair == null) {
System.err.println("加载PEM账户失败");
return;
}
// 部署HelloWorld合约
System.out.println("【1】部署HelloWorld合约...");
HelloWorld helloWorld = HelloWorld.deploy(client, cryptoKeyPair);
String contractAddress = helloWorld.getContractAddress();
System.out.println("合约部署成功!");
System.out.println("合约地址: " + contractAddress);
System.out.println("部署账户: " + cryptoKeyPair.getAddress());
// 调用get接口
System.out.println("\n【2】调用get接口...");
String getValue = helloWorld.get();
System.out.println("获取的值: " + getValue);
// 调用set接口
System.out.println("\n【3】调用set接口...");
String newValue = "Hello from PEM account!";
TransactionReceipt setReceipt = helloWorld.set(newValue);
System.out.println("set交易发送成功");
System.out.println("交易哈希: " + setReceipt.getTransactionHash());
System.out.println("交易状态: " + setReceipt.getStatus());
System.out.println("Gas使用: " + setReceipt.getGasUsed());
// 再次调用get验证
System.out.println("\n【4】再次调用get接口验证...");
String updatedValue = helloWorld.get();
System.out.println("更新后的值: " + updatedValue);
// 获取当前块高
java.math.BigInteger blockNumber = client.getBlockNumber().getBlockNumber();
System.out.println("\n当前块高: " + blockNumber);
System.out.println("\n========================================");
System.out.println("PEM账户交易测试完成");
System.out.println("========================================\n");
}
/**
* 使用已存在的合约地址和指定账户进行交互
* @param contractAddress 已部署的合约地址
* @param cryptoKeyPair 账户密钥对
* @param client 客户端
*/
public void interactWithExistingContract(String contractAddress, CryptoKeyPair cryptoKeyPair, Client client)
throws ContractException {
System.out.println("\n========================================");
System.out.println("与已存在的合约交互");
System.out.println("========================================");
// 加载已存在的合约
HelloWorld helloWorld = HelloWorld.load(contractAddress, client, cryptoKeyPair);
System.out.println("合约地址: " + contractAddress);
System.out.println("操作账户: " + cryptoKeyPair.getAddress());
// 调用get接口
System.out.println("\n【1】调用get接口...");
String getValue = helloWorld.get();
System.out.println("当前值: " + getValue);
// 调用set接口
System.out.println("\n【2】调用set接口...");
String newValue = "Updated by " + cryptoKeyPair.getAddress().substring(0, 10) + "...";
TransactionReceipt receipt = helloWorld.set(newValue);
System.out.println("交易哈希: " + receipt.getTransactionHash());
System.out.println("交易状态: " + receipt.getStatus());
// 验证
System.out.println("\n【3】验证更新...");
String updatedValue = helloWorld.get();
System.out.println("更新后的值: " + updatedValue);
System.out.println("\n========================================");
System.out.println("合约交互完成!");
System.out.println("========================================\n");
}
/**
* 主函数 - 演示如何使用PEM格式账户发送交易
*/
public static void main(String[] args) {
try {
HelloWorldWithAccount test = new HelloWorldWithAccount();
// 根据config.toml配置这里使用国密
int cryptoType = CryptoType.SM_TYPE;
System.out.println("##########################################");
System.out.println("# FISCO BCOS HelloWorld 账户交易测试 #");
System.out.println("##########################################");
// 使用PEM格式账户发送交易
System.out.println("\n【测试】使用PEM格式账户发送交易");
System.out.println("------------------------------------------");
test.testWithPEMAccount("user_pem", cryptoType);
System.out.println("\n##########################################");
System.out.println("# 测试执行成功! #");
System.out.println("##########################################\n");
} catch (Exception e) {
System.err.println("测试执行失败: " + e.getMessage());
e.printStackTrace();
System.exit(1);
}
// 强制退出程序
System.exit(0);
}
}