# 部署 Hyperledger Fabric sample
## 環境準備
在建立 Docker-based Fabric 網路環境之前,要安裝 pre-required 套件。官網上沒有特別說 Linux 需要的環境,但在[官方文檔](https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html#linux-ubuntu-debian-based-distro) 針對 Windows 用戶的環境有提到 "Next you will need to install a Linux distribution such as Ubuntu-20.04 and make sure ...",所以就去安裝 Ubuntu-20.04。
### 安裝 Ubuntu 20.04
到[官方網站](https://releases.ubuntu.com/focal/)下載 Ubuntu 20.04.6 LTS (Focal Fossa),再用 virtual box 打開。

預設密碼參考[官網](https://ubuntu.com/tutorials/how-to-run-ubuntu-desktop-on-a-virtual-machine-using-virtualbox)

### Terminal 無法正常開啟
原本我的 terminal 都點不開,也不會報錯。參考這篇[文章](https://askubuntu.com/questions/1442350/terminal-not-launching-in-ubuntu-22-04),去設定把語言改掉,並重新啟動。



terminal 就可以正常開啟了,連中文亂碼也解決了 ovo。

### 使用者提權
如果使用 sudo 把自己提權出現錯誤 "... is not in the sudoers file" ,可以參考此[文章](https://prathapreddy-mudium.medium.com/vboxuser-is-not-in-the-sudoers-file-this-incident-will-be-reported-enable-sudo-in-ubuntu-resolved-305e7988c6bc),先使用 `su` 指令切去 root 用戶,密碼是你原先帳戶的密碼。
安裝 sudo
```
apt-get install sudo -y
```
把原本的使用者名稱加入 sudo 群組
```
adduser vboxuser sudo
```

修改 /etc/sudoer 文件

成功

### 雙向複製貼上
可以參考[這篇文章](https://medium.com/%E8%8A%B1%E5%93%A5%E7%9A%84%E5%A5%87%E5%B9%BB%E6%97%85%E7%A8%8B/%E8%A7%A3%E6%B1%BAvirtualbox%E7%84%A1%E6%B3%95%E9%9B%99%E5%90%91%E8%A4%87%E8%A3%BD%E8%B2%BC%E4%B8%8A-1554d5a81da0),超級有用
參考上述文章去下載 virtualbox-guest-x11 會發現有很多尚未更新的。

這時候就無法成功完成雙向設定

更新 apt
```
sudo apt upgrade
```
再一次下載 virtualbox-guest-x11,原本沒更新的更新完成了

重新開機



可以雙向複製貼上了

### 安裝 Prerequisites
參考[官方文件](https://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html),裡面提到在正式使用 HLF 之前要先安裝 git, cURL, Docker。
```sh=
sudo apt-get install git curl docker-compose -y
# Make sure the Docker daemon is running.
sudo systemctl start docker
# Add your user to the Docker group.
sudo usermod -a -G docker <username>
# Check version numbers
docker --version
docker-compose --version
# Optional: If you want the Docker daemon to start when the system starts, use the following:
sudo systemctl enable docker
```
因為之後可能會需要用到智能合約,所以還要安裝 Go。按照[官方文件](https://golang.org/doc/install)指示刪掉之前版本,安裝最新的。

```
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.23.5.linux-amd64.tar.gz
```
```
export PATH=$PATH:/usr/local/go/bin
```

最後是安裝最新版本的 jq,[官方網站](https://jqlang.github.io/jq/download/)都有給予對應作業系統要用的安裝指令
> - go: 1.23.5
> - Docker version 26.1.3
## 安裝 Fabric 範本
按照[官方文件](https://hyperledger-fabric.readthedocs.io/en/latest/install.html)
```
mkdir -p $HOME/go/src/github.com/<your_github_userid>
cd $HOME/go/src/github.com/<your_github_userid>
```
```
curl -sSLO https://raw.githubusercontent.com/hyperledger/fabric/main/scripts/install-fabric.sh && chmod +x install-fabric.sh
```
使用 docker 去下載 Fabric Container Images,接著clone fabric-samples github repo 並下載 Fabric binaries
```
./install-fabric.sh docker samples binary
```
選擇特定版本
```
./install-fabric.sh --fabric-version 2.5.10 binary
```
總之安裝完成大概會看到這些
```
root@Ubuntu2204LTS:~/go/src/github.com/<github-user-name># ls
bin builders config fabric-samples install-fabric.sh
```
## [建立測試環境的網路](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html)
```
cd fabric-samples/test-network
./network.sh up
```

可以看到三個 container 建立好了。這個 Fabric 網路包含兩個 peer 和一個 ordering node

## 建立 channel
通道(Channel)是其架構中一個至關重要的概念,主要用於實現不同參與者之間的私密交易和數據隔離。以下是通道在Hyperledger Fabric中的重要性詳細說明。
通道的基本概念
定義:通道是一個邏輯結構,允許特定組織之間進行私有交易。每個通道都有自己的賬本(ledger),並且可以運行多個鏈碼(chaincode),這使得不同的業務應用能夠在同一網絡中獨立運行而不互相干擾
我們用[官方文件](https://hyperledger-fabric.readthedocs.io/en/latest/test_network.html)的範例在兩個機構之間建立 channel,這個新的 channel 會叫 "mychannel",這是因為 `network.config` 這個檔案預先設定的。

```
./network.sh createChannel
```

自定義名稱可以用
```
./network.sh createChannel -c <customized_name>
```
:::spoiler 解決 Error: proposal failed (err: bad proposal response 500: cannot create ledger from genesis block: ledger [mychannel] already exists with state [ACTIVE]) After 5 attempts, peer0.1 has failed to join channel 'mychannel'
### 錯誤

```
Error: proposal failed (err: bad proposal response 500: cannot create ledger from genesis block: ledger [mychannel] already exists with state [ACTIVE])
After 5 attempts, peer0.org1 has failed to join channel 'mychannel'
```
### 解決
```
./network.sh down
docker system prune --volumes
```


https://github.com/hyperledger/fabric-samples/issues/1097
:::
## 把 peer 加入到環境變數
按照[官方文件](https://hyperledger-fabric.readthedocs.io/en/release-2.4/test_network.html),進入到 `test-network` 路徑,輸入以下指令。如果前面的 pre-required 都有安裝正確的話,就可以成功抓到位於 fabric-samples/bin 的 peer binaries 檔案。
```
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
```
輸入 `peer`,成功

這樣就可以執行許多指令,例如
- 查看目前有哪些 channel: `peer channel list` 
- 查詢某通道的區塊編號(height) `peer channel getinfo -c <channel_name>` 
- 取得通道的創世區塊(Genesis Block)`peer channel fetch config genesis_block.pb -c <通道名稱> --orderer <訂購服務地址>`
> The first block of a newly created channel is known as a “genesis block”
:::spoiler 如何查看網路配置的組織、通道、訂購服務(Orderer)、策略
`configtx.yaml`是網路設定檔,通常放在 Fabric 網路的配置資料夾。它定義了 組織、通道、訂購服務(Orderer)、策略 。
```
cat configtx/configtx.yaml
```
:::
:::spoiler 如何查看一個通道上有哪些機構
抓取通道組態區塊
```
peer channel fetch config config_block.pb -o localhost:7050 \
--ordererTLSHostnameOverride orderer.example.com --tls \
--cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" \
-c mychannel
```

轉換區塊為 JSON 格式,儲存為 config.json
```
configtxlator proto_decode --input config_block.pb --type common.Block \
| jq .data.data[0].payload.data.config > config.json
```
查看有哪些機構
```
jq -r '.channel_group.groups.Application.groups | keys' config.json
```

:::
### Crypto Generator
## [在 channel 建立智慧合約](https://hyperledger-fabric.readthedocs.io/en/latest/deploy_chaincode.html)
區塊鏈的使用者是透過執行智慧合約來跟帳本互動的。在 Hyperledger Fabric 裡,這些智慧合約是打包成 chaincode 來部署的,也就是說我們常聽到的 smart contract 是一個邏輯層面的概念,描述的是區塊鏈中資產和交易的規則和邏輯。Chaincode 是智慧合約在 Fabric 中的具體表現形式,包含了智慧合約的業務邏輯,並運行於區塊鏈節點之上。
如果某個組織想要驗證交易或查詢帳本,就需要在自己的對等節點 (peers) 上安裝 chaincode。當 chaincode 安裝到已加入某個通道的節點後,通道裡的成員就可以正式部署它,然後用裡面的智慧合約來新增或更新帳本上的資產。
### peer lifecycle chaincode
部署 chaincode 的過程叫做 Fabric chaincode lifecycle ,以確保所有相關的組織都能在 chaincode 正式運行前,先達成共識。舉個例子,endorsement policy 會定義哪些組織需要執行 chaincode 來驗證交易,而通道成員必須透過這個生命週期流程來決定最終的 endorsement policy。
### 建立 chaincode
部署 chaincode 其時有四個步驟
1. Step one: Package the smart contract
2. Step two: Install the chaincode package
3. Step three: Approve a chaincode definition
4. Step four: Committing the chaincode definition to the channel
官方文件說使用
```
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go
```
:::spoiler 記得幫 go 設置環境變數
如果遇到以下 error

雖然之前安裝 Prerequisites 的時候有做過,但這邊要再一次設置環境變數。這是因為 go 官方文檔提供的環境變數變更只會影響當前的 Shell Session,如果開啟一個新的終端或切換到另一個目錄,原本的 export PATH 設定就不會自動保留,因為環境變數在不同的 Shell Session 之間不會自動傳遞。官方提供的環境變數設置如下:
```
export PATH=$PATH:/usr/local/go/bin
```
如果不想每次切換目錄或開啟新終端時都要重新設置 PATH,可以將它添加到 Shell 配置檔案,對於 Ubuntu 就是修改 Bash
```
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc
```
:::
再執行建立 chaincode 的指令,就可以看到建立成功的結果:

### 應用 chaincode 範例 - 轉移資產
透過設置環境變數來指定查詢的對象
```
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=Org1MSP
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
```
:::spoiler 否則等等執行指令會出現以下問題


```
2025-01-30 14:50:16.554 CST 0001 ERRO [main] InitCmd -> Cannot run peer because cannot init crypto, specified path "/root/go/src/github.com/<user-name>/fabric-samples/config/msp" does not exist or cannot be accessed: stat /root/go/src/github.com/<user-name>/fabric-samples/config/msp: no such file or directory
```
https://stackoverflow.com/questions/66651603/cannot-run-peer-because-cannot-init-crypto-error-while-using-peer-command
:::
環境變數設定完成後執行
```
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"InitLedger","Args":[]}'
```

當區塊鏈網路的成員想要轉移或修改帳本上的資產時,就會執行 chaincode。可以用下面的指令來調用「資產轉移 (基本版)」chaincode,來變更帳本上某個資產的擁有者
變更前輸入以下指令就可以看目前的資產狀態
```
peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
```
```json
[
{"AppraisedValue":300,"Color":"blue","ID":"asset1","Owner":"Tomoko","Size":5},
{"AppraisedValue":400,"Color":"red","ID":"asset2","Owner":"Brad","Size":5},
{"AppraisedValue":500,"Color":"green","ID":"asset3","Owner":"Jin Soo","Size":10},
{"AppraisedValue":600,"Color":"yellow","ID":"asset4","Owner":"Max","Size":10},
{"AppraisedValue":700,"Color":"black","ID":"asset5","Owner":"Adriana","Size":15},
{"AppraisedValue":800,"Color":"white","ID":"asset6","Owner":"Michel","Size":15}
]
```
透過 chaincode 變更。這條指令的意思是"在 mychannel 上調用 basic chaincode,執行 TransferAsset 函數,把 ID 為 asset6 的資產轉移給 Christopher,並透過 Orderer 廣播交易,讓 Org1 和 Org2 的 peer0 節點進行驗證。"
```
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"TransferAsset","Args":["asset6","Christopher"]}'
```

再次用指令驗證目前資產轉移結果,成功
```json
[
{"AppraisedValue":300,"Color":"blue","ID":"asset1","Owner":"Tomoko","Size":5},
{"AppraisedValue":400,"Color":"red","ID":"asset2","Owner":"Brad","Size":5},
{"AppraisedValue":500,"Color":"green","ID":"asset3","Owner":"Jin Soo","Size":10},
{"AppraisedValue":600,"Color":"yellow","ID":"asset4","Owner":"Max","Size":10},
{"AppraisedValue":700,"Color":"black","ID":"asset5","Owner":"Adriana","Size":15},
{"AppraisedValue":800,"Color":"white","ID":"asset6","Owner":"Christopher","Size":15}
]
```
### [建立自己的智能合約](https://hyperledger-fabric.readthedocs.io/en/latest/deploy_chaincode.html)
## MSP
雖然名字叫「Membership Service Provider(MSP,成員服務提供者)」,但它其實並不會「提供」任何服務。MSP 的實作方式其實就是一組資料夾,這些資料夾被加入到網路的設定中,並用來定義一個組織的身份:
- **內部管理**:組織可以透過 MSP 來決定誰是管理員。
- **外部驗證**:其他組織可以透過 MSP 來確認某個身份是否有權限執行特定操作。
與此同時,**憑證授權機構(CA,Certificate Authority)** 負責發放代表身份的憑證,而 **MSP** 則是維護一個授權身份的清單,也就是說,MSP 紀錄了哪些身份被允許參與網路。
### MSP 的作用
MSP 會透過以下方式來決定哪些 Root CA(根憑證機構)和 Intermediate CA(中介憑證機構)是可信的:
1. **列出成員身份**:直接記錄哪些身份被允許加入。
2. **授權 CA 發放身份**:指定哪些 CA 可以發放有效的身份憑證。
但 MSP 的功能不僅限於定義誰能參與網路或某個頻道(Channel),它還負責**將身份與角色綁定**,進而決定該身份在網路中的權限。例如,當使用 Fabric CA 註冊一個身份時,必須賦予該身份一個角色,如:
- **Admin(管理員)**
- **Peer(節點)**
- **Client(客戶端)**
- **Orderer(排序節點)**
- **Member(成員)**
舉例來說:
- 註冊為「Peer」角色的身份,應該被分配給 Peer 節點。
- 註冊為「Admin」角色的身份,應該交給組織的管理者。
稍後我們會更深入探討這些角色的具體作用。
### MSP 還能做什麼?
除了定義合法身份,MSP 還可以用來管理**已撤銷的身份**。如果某個身份被撤銷,它會被加入 MSP 的黑名單,這樣網路中的其他節點就能知道這個身份已經失效。我們稍後會進一步介紹這個過程的運作方式。
---
## 機構底下有什麼?

### CA Certificate

### peers

### MSP

---
## CA
在憑證授權機構(CA)負責處理組織內所有實體的身份,所謂實體包含了網路元件和網路使用者。每個實體都會從CA獲得一個憑證(crypto material,加密材料)。該憑證包含一個私鑰以及代表該實體的數位證書。只要實體保持私鑰的安全,安全性就能得到維護。
Hyperledger Fabric 提供了 cryptogen 這個套件,用以建立 crypto material,
## crypto material 檔案路徑結構

## CA Server 建立 crypto material
前面提到的`./network.sh up`指令只會建立一個基本的 Fabric 網路,包含兩個 Peer 節點和一個 Orderer 節點。預設情況下,它使用 cryptogen 工具來產生組織的憑證和金鑰,並透過 docker-compose-test-net.yaml 啟動 Peer 和 Orderer 節點。
而`./network.sh up -ca`則進一步加入「憑證授權機構(Certificate Authorities,CA)」來產生加密材料,而不是使用 cryptogen。它會使用 Fabric CA 伺服器的設定檔,並透過 organizations/fabric-ca 目錄下的 registerEnroll.sh 腳本來處理註冊和認證。Fabric CA 會在 organizations 目錄內為所有組織建立加密材料和 MSP(Membership Service Provider)資料夾。
```
./network.sh up -ca
```




使用 HLF 的 cryptogen 工具建立加密材料,和使用 CA Server 建立加密材料,其中一個差別在於 private secret key 儲存的地方,使用 CA Server 建立的話 PSK 就會位於遠端的伺服器。


## [自己寫一個 chaincode](https://hyperledger-fabric.readthedocs.io/en/latest/chaincode4ade.html)
在 Hyperledger Fabric 中,Chaincode(鏈碼)通常負責處理網路成員共同認可的業務邏輯,因此它的概念類似於「智能合約」。當我們想要更新或查詢帳本時,可以透過交易請求(proposal transaction)來調用 chaincode。
### Fabric 鏈碼生命週期(Chaincode Lifecycle)
Fabric Chaincode Lifecycle 是一個流程,允許多個組織**在鏈碼上線前**先達成共識,確保大家都同意它的運作方式,才能讓它在通道上使用。
在這個流程中,**網路運營者(Network Operator)** 會使用 **Fabric 鏡碼生命週期** 來執行以下任務:
1. **安裝並定義鏈碼**(Install and define a chaincode)— 先將鏈碼安裝到節點,然後定義它的參數,例如名稱、版本、策略等。
2. **升級鏈碼**(Upgrade a chaincode)— 當需要對鏈碼進行修改時,可以透過生命週期流程升級它,確保新版本獲得組織的同意後再部署。
3. **不同的部署場景**(Deployment Scenarios)— 針對不同的業務需求,Fabric 提供多種鏈碼部署方式,例如單組織或多組織協作模式。
4. **遷移到新版生命週期**(Migrate to the new Fabric lifecycle)— 如果你的網路還在使用舊版鏈碼管理方式,建議遷移到新版 **Fabric 鏈碼生命週期**,以獲得更靈活的治理能力。
這個流程確保了**區塊鏈網路的安全性與一致性**,避免單一組織隨意更改鏈碼影響其他成員
### 安裝並定義鏈碼(Install and define a chaincode)
在 Fabric 鏈碼生命週期 中,各組織需要事先達成共識,確定鏈碼的參數,例如:名稱(Name)、版本(Version)、背書策略(Endorsement Policy)
通道中的成員組織需要透過以下四個步驟來完成鏈碼定義,不是每個組織都需要執行所有步驟:
#### 1. 打包鏈碼
- 這個步驟可以由某個組織單獨執行,也可以讓每個組織都自行打包。
```
peer lifecycle chaincode package mychaincode.tar.gz --path ./chaincode/ --lang golang --label mychaincode_1
```

鏈碼必須打包為 `.tar.gz` 格式的 tar 文件,並且該 tar 文件必須包含兩個文件(無目錄結構):
- metadata.json:元數據文件,包含鏈碼語言、代碼路徑和包標籤。
```json
// metadata.json
{
"Path": "fabric-samples/asset-transfer-basic/chaincode-go",
"Type": "golang",
"Label": "basicv1"
}
```
- code.tar.gz:包含鏈碼文件的壓縮包。
#### 2. 安裝鏈碼到 Peer 節點
- 每個組織 如果要使用這個鏈碼來背書交易或查詢帳本,都需要完成這一步。
- 以下指令會將 mychaincode.tar.gz 安裝到本節點(Peer)。
```
peer lifecycle chaincode install mychaincode.tar.gz
```
鏈碼包需要安裝到每個執行和背書交易的對等節點上。無論使用 CLI 還是 SDK,都需要以**對等節點管理員(Peer Administrator)**身份執行這一步。
當鏈碼安裝到對等節點後,對等節點會嘗試構建鏈碼。如果鏈碼有問題,則會返回構建錯誤。因此,建議每個組織僅打包一次鏈碼,然後將相同的包安裝到組織內的所有對等節點上。
如果希望確保通道(channel)內的所有組織運行相同的鏈碼,則可以由一個組織打包鏈碼,並**通過線下方式(out of band)**將其發送給其他成員。
成功執行安裝命令後,將返回鏈碼包標識符(package identifier),該標識符是鏈碼標籤 + 鏈碼包哈希值的組合。此標識符將用於將安裝在對等節點上的鏈碼與組織批准的鏈碼定義(Chaincode Definition)關聯起來,請保存此標識符以供下一步使用。
也可以使用 Peer CLI 查詢已安裝的鏈碼來獲取 package identifier。

鏈碼安裝流程
Org1 和 Org2 的對等節點管理員將 MYCC_1 鏈碼安裝到加入通道的對等節點上,並生成鏈碼包標識符 MYCC_1:hash。
#### 3. 核准鏈碼定義
- 每個希望使用該鏈碼的組織都需要批准它的鏈碼定義。
- 只有當足夠的組織批准(通常是多數同意)後,鏈碼才能啟動
- 以下指令讓組織批准 mychaincode,並指定 sequence(鏈碼版本遞增)與 package-id(鏈碼包 ID)。
```
peer lifecycle chaincode approveformyorg -o orderer.example.com:7050 --channelID mychannel --name mychaincode --version 1.0 --package-id mychaincode_1:hash --sequence 1 --init-required
```
鏈碼受鏈碼定義(Chaincode Definition)管理。當通道成員批准鏈碼定義時,該批准相當於該組織對鏈碼參數的投票。批准後的鏈碼定義允許通道成員在鏈碼運行前達成一致。
鏈碼定義包括以下必須在所有組織之間保持一致的參數:
1. 名稱(Name):應用程式在調用鏈碼時使用的名稱。
2. 版本(Version):鏈碼版本號。如果升級鏈碼,則需要更新版本號。
3. 序列號(Sequence):鏈碼定義的更新次數,每次升級鏈碼時,序列號遞增。例如,首次安裝時 Sequence = 1,升級後變為 Sequence = 2。
4. 背書策略(Endorsement Policy):哪些組織需要執行並驗證交易輸出。默認為 Channel/Application/Endorsement,即通道內的多數組織需進行背書。
5. 私有數據集合配置(Collection Configuration):鏈碼使用的私有數據集合文件路徑(如適用)。
6. ESCC/VSCC 插件:自定義背書或驗證插件名稱(如適用)。
7. 初始化函數(Initialization):如果使用 Fabric Chaincode Shim API 的底層 API,鏈碼必須包含 Init 方法來初始化狀態。可以通過 --init-required 標誌強制要求初始化。
#### 4. 提交鏈碼定義
- 當足夠多的組織批准後,任意一個組織 可以負責提交(commit)這個鏈碼定義,讓它正式運行。
- 這步驟會收集足夠的背書,然後提交交易,最終鏈碼才能在通道上運行。
```
peer lifecycle chaincode commit -o orderer.example.com:7050 --channelID mychannel --name mychaincode --version 1.0 --sequence 1 --init-required
```

### 撰寫 chaincode 注意事項
https://www.youtube.com/watch?v=80w8yiud4Vc
## 組織內配置不同角色
## 新組織加入
## [自己寫一個 chaincode](https://hyperledger-fabric.readthedocs.io/en/latest/chaincode4ade.html)
```
mkdir myFirstChainCode && cd myFirstChainCode
```
```bash
go mod init myFirstChainCode # create go.mod file
touch myFirstChainCode.go
```


```
nano myFirstChainCode.go
```
::: spoiler chaincode
```go
// 以 Asset Transfer Chaincode 為例子
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// SmartContract defines the federated learning contract
type SmartContract struct {
contractapi.Contract
}
// Model represents a federated learning model
type Model struct {
ModelID string `json:"modelID"`
Owner string `json:"owner"`
ModelHash string `json:"modelHash"`
Aggregated bool `json:"aggregated"`
Contributors []string `json:"contributors"`
}
// InitLedger initializes the ledger with a base model
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
models := []Model{
{ModelID: "model1", Owner: "admin", ModelHash: "abc123", Aggregated: false, Contributors: []string{}},
}
for _, model := range models {
modelJSON, err := json.Marshal(model)
if err != nil {
return err
}
err = ctx.GetStub().PutState(model.ModelID, modelJSON)
if err != nil {
return fmt.Errorf("failed to put model in ledger: %v", err)
}
}
return nil
}
// SubmitModelUpdate allows nodes to submit local model updates
func (s *SmartContract) SubmitModelUpdate(ctx contractapi.TransactionContextInterface, modelID string, modelHash string) error {
modelJSON, err := ctx.GetStub().GetState(modelID)
if err != nil {
return fmt.Errorf("failed to get model: %v", err)
}
if modelJSON == nil {
return fmt.Errorf("model %s does not exist", modelID)
}
var model Model
err = json.Unmarshal(modelJSON, &model)
if err != nil {
return err
}
// Get submitter identity
clientID, err := ctx.GetClientIdentity().GetID()
if err != nil {
return fmt.Errorf("failed to get client identity: %v", err)
}
// Zero Trust: Verify client authorization
if !s.isAuthorized(clientID) {
return fmt.Errorf("access denied: unauthorized client")
}
// Store new update
model.ModelHash = modelHash
model.Contributors = append(model.Contributors, clientID)
updatedModelJSON, err := json.Marshal(model)
if err != nil {
return err
}
return ctx.GetStub().PutState(modelID, updatedModelJSON)
}
// AggregateModel finalizes the model after validation
func (s *SmartContract) AggregateModel(ctx contractapi.TransactionContextInterface, modelID string) error {
modelJSON, err := ctx.GetStub().GetState(modelID)
if err != nil {
return fmt.Errorf("failed to get model: %v", err)
}
if modelJSON == nil {
return fmt.Errorf("model %s does not exist", modelID)
}
var model Model
err = json.Unmarshal(modelJSON, &model)
if err != nil {
return err
}
if len(model.Contributors) < 2 { // Example consensus: at least 2 updates
return fmt.Errorf("not enough contributors for aggregation")
}
model.Aggregated = true
updatedModelJSON, err := json.Marshal(model)
if err != nil {
return err
}
return ctx.GetStub().PutState(modelID, updatedModelJSON)
}
// isAuthorized enforces zero-trust access control (simplified)
func (s *SmartContract) isAuthorized(clientID string) bool {
allowedClients := []string{"Org1MSP", "Org2MSP"} // Replace with actual verification
for _, id := range allowedClients {
if clientID == id {
return true
}
}
return false
}
// ReadModel retrieves the model details
func (s *SmartContract) ReadModel(ctx contractapi.TransactionContextInterface, modelID string) (*Model, error) {
modelJSON, err := ctx.GetStub().GetState(modelID)
if err != nil {
return nil, fmt.Errorf("failed to read model: %v", err)
}
if modelJSON == nil {
return nil, fmt.Errorf("model %s does not exist", modelID)
}
var model Model
err = json.Unmarshal(modelJSON, &model)
if err != nil {
return nil, err
}
return &model, nil
}
// GetAllModels retrieves all models
func (s *SmartContract) GetAllModels(ctx contractapi.TransactionContextInterface) ([]*Model, error) {
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
if err != nil {
return nil, err
}
defer resultsIterator.Close()
var models []*Model
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
var model Model
err = json.Unmarshal(queryResponse.Value, &model)
if err != nil {
return nil, err
}
models = append(models, &model)
}
return models, nil
}
func main() {
modelChaincode, err := contractapi.NewChaincode(&SmartContract{})
if err != nil {
log.Panicf("Error creating federated learning chaincode: %v", err)
}
if err := modelChaincode.Start(); err != nil {
log.Panicf("Error starting federated learning chaincode: %v", err)
}
}
```
:::
### 打包 chaincode
由於這些 code 不在 libraries 裡面,所以要先打包,之後才可以裝到 peers 節點裡面。首先我們要先把檔案變成壓縮檔:
1. 轉換成壓縮檔案 `.tar.gz`
```
tar -cvf <myproject>.tar .
gzip myproject.tar
```
2.
- peer chaincode package
- 用于将链码打包成一个 .cds 文件(链码部署规范文件),以便在网络中的对等节点上安装和实例化链码。
- 使用时机:在准备将链码部署到 Fabric 网络时,需要先将链码打包成 .cds 文件。
```bash
peer chaincode package
```
- peer chaincode install
- 用于在对等节点上安装打包好的链码。安装后,链码会被存储在对等节点的文件系统中,但还未在通道上实例化。
- 使用时机:在对等节点上安装链码后,需要在通道上实例化链码才能使其可用。
```bash
peer chaincode install
```
### 管理與外部套件的依賴關係
以下兩行指令的詳細說明可以參考文章 [【go语言】Go基础知识:go.mod文件、go mod命令、私有仓库、导入版本管理、Vendor目录详解](https://www.cnblogs.com/shangxiaofei/articles/18568463)。
```bash
go mod tidy
go mod vendor # This places the external dependencies for your chaincode into a local vendor directory.
```

(中間還有一堆)

Once dependencies are vendored in your chaincode directory, peer chaincode package and peer chaincode install operations will then include code associated with the dependencies into the chaincode package.
### chaincode 權限控制
透過`ctx.GetStub().GetCreator()` API 取得用戶的 certificate
## [peer](https://hyperledger-fabric.readthedocs.io/en/latest/peers/peers.html) (non-ordering nodes)
>[!Note]
>簡單來說,Peer 是帳本、鏈碼和服務的託管者,因此客戶端應用 (client applications) 和管理者 (administrators) 都必須透過 Peer 來訪問這些資源。
- Peers 是執行鏈碼 (Chaincode) 並維護帳本 (Ledger) 的核心節點,不同於其他區塊鏈的礦工節點。
- 管理 ledgers 和 smart contracts
- 帳本 (Ledger)
- 是不可變的 (Immutable): Fabric 的 帳本 會記錄所有交易,而且一旦寫入,就無法被修改或刪除,這是區塊鏈的核心特性之一。
- 智慧合約 (Smart Contracts)
- 負責產生交易
- 在 Fabric 中,智慧合約 (Smart Contract) 是定義商業邏輯的程式碼,它會處理資產轉移、權限管理等邏輯。
- 負責定義 「如何處理交易」(即「流程」)。
- 鏈碼 (Chaincode) 是智慧合約的實作方式,類似於其他區塊鏈平台(如 Ethereum)中的智能合約。
> [!Note]
> Peer 可以同時託管多個帳本,這樣的設計讓 Fabric 網路更具靈活性,因為一個 Peer 可以同時參與多個通道 (channels)。鏈碼 (chaincode) 是部署在特定通道上的,而每個通道(和帳本)可以有多個鏈碼與之互動。
> 
> [!Note]
> 因為區塊鏈需要在 同一通道 (channel) 內的 Peer 之間維持一致的數據副本 (consistent replicas of data) 和智慧合約 (smart contracts)。這種設計在 Fabric 網路中提供了刻意的冗餘 (deliberate redundancy),藉此避免單點故障 (single points of failure),確保帳本 (ledger) 的一致性與即時性。
- 透過 Fabric Gateway service 管理 transaction proposals 和 endorsements
- 交易需要獲得必要組織的背書 (Endorsement)
- Fabric 採用「授權機制 (Endorsement Policy)」,不同於公鏈的「共識機制 (Proof of Work/Stake)」。
- 只有獲得指定組織的認可 (Endorsed by required organizations),交易才會被視為有效,這樣能夠實現隱私控制,讓不同組織之間的交易保持透明但又不公開給所有人。

每個節點都有一份 copy 的 ledger,然後都 invoke 同一份 chaincode
## Fabric Gateway
交易的處理分為三個階段:
1. 交易提案與背書(提交交易請求 → 執行鏈碼 → 收集背書)。
2. 交易提交與排序(提交至 Orderer → 排序並打包區塊)。
3. 交易驗證與提交(檢查交易有效性 → 更新帳本 → 通知應用程式)。
以上三階段 Gateway SDK 已經自動處理,開發者只需使用 SDK 即可完成。
## Peers 和 channel

## Peers 和 Organizations

---
## 參考
- [](https://kctheservant.medium.com/two-ways-to-generate-crypto-materials-in-hyperledger-fabric-cryptogen-and-ca-server-36d3c3e2daad)
- [link text](https:// "title")