我目前正在深入研究Hyperledger Fabric,但是我无法使用Java SDK(指的是1.0.0-beta版本)来启动。是否有一个可行的示例,从连接到Fabric节点开始,进行查询等操作?到目前为止,通过广泛的谷歌搜索,我找到的都是“让我们编写一些链代码”的示例。
我目前正在深入研究Hyperledger Fabric,但是我无法使用Java SDK(指的是1.0.0-beta版本)来启动。是否有一个可行的示例,从连接到Fabric节点开始,进行查询等操作?到目前为止,通过广泛的谷歌搜索,我找到的都是“让我们编写一些链代码”的示例。
这是一个示例,实现了fabcar(query.js和invoke.js——仅查询一辆汽车并更改所有者)的部分功能。
我在Windows上使用了Java8。如果您使用其他操作系统,请相应更新路径。
为避免使用额外的库(需要处理证书),我没有使用任何 json 实现。
您需要运行 fabcar 示例。 而且(因为 'no json'):
代码(fabrictest/fabcar/Program.java):
package fabrictest.fabcar;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import javax.xml.bind.DatatypeConverter;
import org.hyperledger.fabric.sdk.ChaincodeID;
import org.hyperledger.fabric.sdk.Channel;
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.HFClient;
import org.hyperledger.fabric.sdk.ProposalResponse;
import org.hyperledger.fabric.sdk.QueryByChaincodeRequest;
import org.hyperledger.fabric.sdk.TransactionProposalRequest;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
public class Program {
private static HFClient client = null;
public static void main(String[] args) throws Throwable {
/*
* wallet_path: path.join(__dirname, './creds'), user_id: 'PeerAdmin',
* channel_id: 'mychannel', chaincode_id: 'fabcar', network_url:
* 'grpc://192.168.99.100:7051', orderer: grpc://192.168.99.100:7050
*
*/
// just new objects, without any payload inside
client = HFClient.createNewInstance();
CryptoSuite cs = CryptoSuite.Factory.getCryptoSuite();
client.setCryptoSuite(cs);
// We implement User interface below in code
// folder c:\tmp\creds should contain PeerAdmin.cert (extracted from HF's fabcar
// example's PeerAdmin json file)
// and PeerAdmin.priv (copy from
// cd96d5260ad4757551ed4a5a991e62130f8008a0bf996e4e4b84cd097a747fec-priv)
User user = new SampleUser("c:\\tmp\\creds", "PeerAdmin");
// "Log in"
client.setUserContext(user);
// Instantiate channel
Channel channel = client.newChannel("mychannel");
channel.addPeer(client.newPeer("peer", "grpc://192.168.99.100:7051"));
// It always wants orderer, otherwise even query does not work
channel.addOrderer(client.newOrderer("orderer", "grpc://192.168.99.100:7050"));
channel.initialize();
// below is querying and setting new owner
String newOwner = "New Owner #" + new Random(new Date().getTime()).nextInt(999);
System.out.println("New owner is '" + newOwner + "'\n");
queryFabcar(channel, "CAR1");
updateCarOwner(channel, "CAR1", newOwner, false);
System.out.println("after request for transaction without commit");
queryFabcar(channel, "CAR1");
updateCarOwner(channel, "CAR1", newOwner, true);
System.out.println("after request for transaction WITH commit");
queryFabcar(channel, "CAR1");
System.out.println("Sleeping 5s");
Thread.sleep(5000); // 5secs
queryFabcar(channel, "CAR1");
System.out.println("all done");
}
private static void queryFabcar(Channel channel, String key) throws Exception {
QueryByChaincodeRequest req = client.newQueryProposalRequest();
ChaincodeID cid = ChaincodeID.newBuilder().setName("fabcar").build();
req.setChaincodeID(cid);
req.setFcn("queryCar");
req.setArgs(new String[] { key });
System.out.println("Querying for " + key);
Collection<ProposalResponse> resps = channel.queryByChaincode(req);
for (ProposalResponse resp : resps) {
String payload = new String(resp.getChaincodeActionResponsePayload());
System.out.println("response: " + payload);
}
}
private static void updateCarOwner(Channel channel, String key, String newOwner, Boolean doCommit)
throws Exception {
TransactionProposalRequest req = client.newTransactionProposalRequest();
ChaincodeID cid = ChaincodeID.newBuilder().setName("fabcar").build();
req.setChaincodeID(cid);
req.setFcn("changeCarOwner");
req.setArgs(new String[] { key, newOwner });
System.out.println("Executing for " + key);
Collection<ProposalResponse> resps = channel.sendTransactionProposal(req);
if (doCommit) {
channel.sendTransaction(resps);
}
}
}
/***
* Implementation of user. main business logic (as for fabcar example) is in
* getEnrollment - get user's private key and cert
*
*/
class SampleUser implements User {
private final String certFolder;
private final String userName;
public SampleUser(String certFolder, String userName) {
this.certFolder = certFolder;
this.userName = userName;
}
@Override
public String getName() {
return userName;
}
@Override
public Set<String> getRoles() {
return new HashSet<String>();
}
@Override
public String getAccount() {
return "";
}
@Override
public String getAffiliation() {
return "";
}
@Override
public Enrollment getEnrollment() {
return new Enrollment() {
@Override
public PrivateKey getKey() {
try {
return loadPrivateKey(Paths.get(certFolder, userName + ".priv"));
} catch (Exception e) {
return null;
}
}
@Override
public String getCert() {
try {
return new String(Files.readAllBytes(Paths.get(certFolder, userName + ".cert")));
} catch (Exception e) {
return "";
}
}
};
}
@Override
public String getMspId() {
return "Org1MSP";
}
/***
* loading private key from .pem-formatted file, ECDSA algorithm
* (from some example on StackOverflow, slightly changed)
* @param fileName - file with the key
* @return Private Key usable
* @throws IOException
* @throws GeneralSecurityException
*/
public static PrivateKey loadPrivateKey(Path fileName) throws IOException, GeneralSecurityException {
PrivateKey key = null;
InputStream is = null;
try {
is = new FileInputStream(fileName.toString());
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
boolean inKey = false;
for (String line = br.readLine(); line != null; line = br.readLine()) {
if (!inKey) {
if (line.startsWith("-----BEGIN ") && line.endsWith(" PRIVATE KEY-----")) {
inKey = true;
}
continue;
} else {
if (line.startsWith("-----END ") && line.endsWith(" PRIVATE KEY-----")) {
inKey = false;
break;
}
builder.append(line);
}
}
//
byte[] encoded = DatatypeConverter.parseBase64Binary(builder.toString());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("ECDSA");
key = kf.generatePrivate(keySpec);
} finally {
is.close();
}
return key;
}
}
您可以查看以下内容:
- Java SDK for Hyperledger Fabric 2.2。其中,在文件夹“fabric-sdk-java/src/test/java/org/hyperledger/fabric/sdkintegration/”中提供了两个文件==> End2endAndBackAgainIT.java,End2endIT.java。这可以帮助。
2020年6月7日更新
上述链接Java SDK for Hyperledger Fabric 2.2是与Hyperledger Fabric交互的低级SDK。
如果您的目的是构建Hyperledger Fabric区块链客户端应用程序,则建议使用Java版Hyperledger Fabric网关SDK,这是一个高级API。它非常简单易用,只需参考[2.2]中的代码片段即可。请参考链接如何使用。// code snippet from [2.2]
class Sample {
public static void main(String[] args) throws IOException
{
// Load an existing wallet holding identities used to access the network.
Path walletDirectory = Paths.get("wallet");
Wallet wallet = Wallets.newFileSystemWallet(walletDirectory);
// Path to a common connection profile describing the network.
Path networkConfigFile = Paths.get("connection.json");
// Configure the gateway connection used to access the network.
Gateway.Builder builder = Gateway.createBuilder() .identity(wallet, "user1").networkConfig(networkConfigFile);
// Create a gateway connection
try (Gateway gateway = builder.connect()){
// Obtain a smart contract deployed on the network.
Network network = gateway.getNetwork("mychannel");
Contract contract = network.getContract("fabcar");
// Submit transactions that store state to the ledger.
byte[] createCarResult = contract.createTransaction("createCar").submit("CAR10", "VW", "Polo", "Grey","Mary");
System.out.println(new String(createCarResult, StandardCharsets.UTF_8));
// Evaluate transactions that query state from the ledger.
byte[] queryAllCarsResult = contract.evaluateTransaction("queryAllCars");
System.out.println(new String(queryAllCarsResult, StandardCharsets.UTF_8));
}
catch (ContractException | TimeoutException | InterruptedException e) {
e.printStackTrace();
}
}
}
$ docker-compose up -d Creating network "sdkintegration_default" with the default driver Creating sdkintegration_ccenv_1 ... Creating orderer.example.com ... Creating ca_peerOrg2 ... Creating ca_peerOrg1 ... Creating sdkintegration_ccenv_1 Creating orderer.example.com Creating ca_peerOrg2 Creating sdkintegration_ccenv_1 ... done
- JGlassConnect to localhost:7054 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused: connect
你能克服这个问题吗?我能够从这里获取的docker-compose正常工作 - 就连接而言 - 但其他示例却无法正常工作。非常感谢您的想法! - JGlass
KeyFactory.getInstance("ECDSA");
更改为KeyFactory.getInstance("EC");
解决了问题。 - Neo