Hyperledger Fabric 整理體系:
運行時架構
運行時架構
各項解釋如下:
- APP:代表一個客戶端或者SDK,作用是創(chuàng)建交易并獲取到足夠的背書之后向Orderer排序服務節(jié)點提交交易請求。(peer和orderer提供了gRPC遠程訪問接口,供客戶端調用)
- CA:負責對網絡中所有證書進行管理,提供標準的KPI服務
- MSP:為客戶端和peer提供證書的系統(tǒng)抽象組件
- Channel:通道提供了一種通訊機制,將peers和orderer連接在一起,形成一個具有保密性的通訊鏈路;將一個大網絡分割成不同私有子網,進行數(shù)據(jù)隔離
- Orderer:對客戶端提交的交易請求進行排序,之后生成區(qū)塊廣播給通道內所有peer節(jié)點
- Org1:代表聯(lián)盟中的某-組織
- Peer:表示組織中的節(jié)點;peer節(jié)點以區(qū)塊的形式從orderer排序服務節(jié)點接收有序狀態(tài)更新,維護狀態(tài)和賬本。fabric中Peer節(jié)點可劃分如下:
- Endorsing Peer:根據(jù)指定的策略調用智能合約,對結果進行背書,返回提案相應到客戶端
- Committing Peer:驗證數(shù)據(jù)并保存到賬本中
- Anchor Peer:跨組織通訊
- Leading Peer:做為組織內所有節(jié)點的代表連接到Orderer排序服務節(jié)點,將從排序服務節(jié)點接收到的批量區(qū)塊廣播給組織內的其他節(jié)點
- Chaincode:鏈碼,部署在fabric的網絡節(jié)點中,獨立運行在具有安全特性的受保護容器中,以gRPC協(xié)議與相應Peer節(jié)點進行通訊,提供相應的API與賬本數(shù)據(jù)進行交互
- Ledger:有排序服務構建的一個全部有序的交易哈希鏈塊,保存在所有的Peer節(jié)點中。
?Java SDK提供了一種執(zhí)行用戶鏈碼,查詢塊數(shù)據(jù),在通道進行交易及模擬事件的方式。
?此模式下,區(qū)塊鏈網絡由兩個組織,每個組織包含兩個結點,和一個order服務;將展示怎樣創(chuàng)建和初始化通道,安裝和部署鏈碼,和執(zhí)行調用和查詢操作。
fabric network
基本原理
?在fabric區(qū)塊鏈中,應用通過結點RPC協(xié)議接口訪問鏈碼。
基本流程
?類似于Shim API對鏈碼通訊協(xié)議的封裝,JavaSDK提供了對結點RPC協(xié)議接口封裝,其入口類為HFClient;對鏈碼的交易和查詢操作則封裝在channel類中。
基本流程 - 類說明
簡單實例
-
實現(xiàn)User接口
?HFClient訪問fabric網絡身份使用User接口實現(xiàn)。
?一個用戶的身份由它的證書來標識的,同時交易還需要證書對應的私鑰,因此LocalUser的核心邏輯就是利用指定的證書和私鑰PEM文件滿足User接口的要求。
User類實現(xiàn) 訪問鏈碼
?創(chuàng)建HFClient實例,然后獲取通道對象,就可以查詢鏈碼或者提交鏈碼交易。
命令行操作: hyperledger fabric byfn up詳解
代碼具體實現(xiàn)
- 運行fabric-samples中fabcar,創(chuàng)建區(qū)塊鏈網絡
- 新建Java工程,引入fabric-gateway-java,實現(xiàn)具體實現(xiàn)
pom.xml
<repositories>
<repository>
<id>oss-sonatype</id>
<name>OSS Sonatype</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.hyperledger.fabric</groupId>
<artifactId>fabric-gateway-java</artifactId>
<version>1.4.1-SNAPSHOT</version>
</dependency>
</dependencies>
加入Admins角色:
public class EnrollAdmin {
static {
System.setProperty("org.hyperledger.fabric.sdk.service_discovery.as_localhost", "true");
}
public static void main(String[] args) throws Exception {
// Create a CA client for interacting with the CA.
Properties props = new Properties();
props.put("pemFile",
"/Users/macserver/Documents/BlockChain/src/github.com/hyperledger/fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem");
props.put("allowAllHostNames", "true");
HFCAClient caClient = HFCAClient.createNewInstance("https://localhost:7054", props);
CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite();
caClient.setCryptoSuite(cryptoSuite);
// Create a wallet for managing identities
Wallet wallet = Wallet.createFileSystemWallet(Paths.get("wallet"));
// Check to see if we've already enrolled the admin user.
boolean adminExists = wallet.exists("admin");
if (adminExists) {
System.out.println("An identity for the admin user \"admin\" already exists in the wallet");
return;
}
// Enroll the admin user, and import the new identity into the wallet.
final EnrollmentRequest enrollmentRequestTLS = new EnrollmentRequest();
enrollmentRequestTLS.addHost("localhost");
enrollmentRequestTLS.setProfile("tls");
Enrollment enrollment = caClient.enroll("admin", "adminpw", enrollmentRequestTLS);
Identity user = Identity.createIdentity("Org1MSP", enrollment.getCert(), enrollment.getKey());
wallet.put("admin", user);
System.out.println("Successfully enrolled user \"admin\" and imported it into the wallet");
}
}
加入user1角色:
public class RegisterUser {
static {
System.setProperty("org.hyperledger.fabric.sdk.service_discovery.as_localhost", "true");
}
public static void main(String[] args) throws Exception {
// Create a CA client for interacting with the CA.
Properties props = new Properties();
props.put("pemFile",
"/Users/macserver/Documents/BlockChain/src/github.com/hyperledger/fabric-samples/first-network/crypto-config/peerOrganizations/org1.example.com/ca/ca.org1.example.com-cert.pem");
props.put("allowAllHostNames", "true");
HFCAClient caClient = HFCAClient.createNewInstance("https://localhost:7054", props);
CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite();
caClient.setCryptoSuite(cryptoSuite);
// Create a wallet for managing identities
Wallet wallet = Wallet.createFileSystemWallet(Paths.get("wallet"));
// Check to see if we've already enrolled the user.
boolean userExists = wallet.exists("user1");
if (userExists) {
System.out.println("An identity for the user \"user1\" already exists in the wallet");
return;
}
userExists = wallet.exists("admin");
if (!userExists) {
System.out.println("\"admin\" needs to be enrolled and added to the wallet first");
return;
}
Identity adminIdentity = wallet.get("admin");
User admin = new User() {
@Override
public String getName() {
return "admin";
}
@Override
public Set<String> getRoles() {
return null;
}
@Override
public String getAccount() {
return null;
}
@Override
public String getAffiliation() {
return "org1.department1";
}
@Override
public Enrollment getEnrollment() {
return new Enrollment() {
@Override
public PrivateKey getKey() {
return adminIdentity.getPrivateKey();
}
@Override
public String getCert() {
return adminIdentity.getCertificate();
}
};
}
@Override
public String getMspId() {
return "Org1MSP";
}
};
// Register the user, enroll the user, and import the new identity into the wallet.
RegistrationRequest registrationRequest = new RegistrationRequest("user1");
registrationRequest.setAffiliation("org1.department1");
registrationRequest.setEnrollmentID("user1");
String enrollmentSecret = caClient.register(registrationRequest, admin);
Enrollment enrollment = caClient.enroll("user1", enrollmentSecret);
Identity user = Identity.createIdentity("Org1MSP", enrollment.getCert(), enrollment.getKey());
wallet.put("user1", user);
System.out.println("Successfully enrolled user \"user1\" and imported it into the wallet");
}
}
客戶端:查詢及添加新數(shù)據(jù)
public class ClientApp {
static {
System.setProperty("org.hyperledger.fabric.sdk.service_discovery.as_localhost", "true");
}
public static void main(String[] args) throws Exception {
// Load a file system based wallet for managing identities.
Path walletPath = Paths.get("wallet");
Wallet wallet = Wallet.createFileSystemWallet(walletPath);
// load a CCP
Path networkConfigPath = Paths.get("/Users/macserver/Documents/BlockChain/src/github.com/hyperledger/fabric-samples/fabcar", "..", "first-network", "connection-org1.yaml");
Gateway.Builder builder = Gateway.createBuilder();
builder.identity(wallet, "user1").networkConfig(networkConfigPath).discovery(true);
// create a gateway connection
try (Gateway gateway = builder.connect()) {
// get the network and contract
Network network = gateway.getNetwork("mychannel");
Contract contract = network.getContract("fabcar");
byte[] result;
result = contract.evaluateTransaction("queryAllCars");
System.out.println(new String(result));
contract.submitTransaction("createCar", "CAR10", "VW", "Polo", "Grey", "Mary");
result = contract.evaluateTransaction("queryCar", "CAR10");
System.out.println(new String(result));
contract.submitTransaction("changeCarOwner", "CAR10", "Archie");
result = contract.evaluateTransaction("queryCar", "CAR10");
System.out.println(new String(result));
}
}
}
實現(xiàn)方式 二
?如果跳過gateway,直接使用fabric-sdk-java,數(shù)據(jù)查詢-實現(xiàn)代碼如下:
private static void queryAllCars() throws Exception {
HFClient hfClient = HFClient.createNewInstance();
CryptoSuite cryptoSuite = CryptoSuiteFactory.getDefault().getCryptoSuite();
hfClient.setCryptoSuite(cryptoSuite);
Enrollment enrollment = new X509Enrollment(getPrivateKey(Paths.get("wallet/user1/user1-priv")), getCertificate(certificate_user1));
User user = new User() {
@Override
public String getName() {
return "gateway";
}
@Override
public Set<String> getRoles() {
return Collections.emptySet();
}
@Override
public String getAccount() {
return "";
}
@Override
public String getAffiliation() {
return "";
}
@Override
public Enrollment getEnrollment() {
return enrollment;
}
@Override
public String getMspId() {
return "Org1MSP";
}
};
hfClient.setUserContext(user);
NetworkConfig networkConfig = NetworkConfig.fromYamlFile(new File(path + "first-network/connection-org1.yaml"));
Channel channel = hfClient.newChannel("mychannel");
List<String> peerNames = networkConfig.getClientOrganization().getPeerNames();
for (String name : peerNames) {
String url = networkConfig.getPeerUrl(name);
Properties props = networkConfig.getPeerProperties(name);
System.err.println("xxxxxxxxx:" + name + "..." + url);
Peer peer = hfClient.newPeer(name, url, props);
Channel.PeerOptions peerOptions = Channel.PeerOptions.createPeerOptions().setPeerRoles(EnumSet.allOf(Peer.PeerRole.class));
channel.addPeer(peer, peerOptions);
}
channel.initialize();
QueryByChaincodeRequest request = QueryByChaincodeRequest.newInstance(user);
request.setChaincodeID(getChaincodeId("fabcar"));
request.setFcn("queryAllCars");
request.setArgs("");
Collection<ProposalResponse> responses = channel.queryByChaincode(request, Collections.singletonList(channel.getPeers().iterator().next()));
ProposalResponse response = responses.iterator().next();
byte[] bytes = response.getChaincodeActionResponsePayload();
System.err.println("xxxxxxx:" + new String(bytes));
}
private static String getCertificate(String certificate) {
BufferedReader certReader = new BufferedReader(new StringReader(certificate));
return certReader.lines().collect(Collectors.joining("\n", "", "\n"));
}
private static PrivateKey getPrivateKey(Path pemFile) {
try {
PEMParser parser = new PEMParser(Files.newBufferedReader(pemFile));
Object key = parser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
return converter.getPrivateKey((PrivateKeyInfo) key);
} catch (IOException e) {
System.err.println("private key 獲取失敗");
return null;
}
}
private static ChaincodeID getChaincodeId(String chaincodeId) {
return ChaincodeID.newBuilder()
.setName(chaincodeId)
.build();
}