主頁 > 區塊鏈 > 【Fabric v2.3.2】教程 - 使用 CouchDB

【Fabric v2.3.2】教程 - 使用 CouchDB

2021-09-19 11:31:35 區塊鏈

使用 CouchDB

本教程將講述在 Hyperledger Fabric 中使用 CouchDB 作為狀態資料庫的步驟,現在, 你應該已經熟悉 Fabric 的概念并且已經瀏覽了一些示例和教程,

注解

這個教程使用了 Fabric v2.0 引進的新功能鏈碼生命周期, 如果你想要使用以前版本的生命周期模型來操作鏈碼的索引功能, 訪問v1.4 版本的 使用 CouchDB .

本教程將帶你按如下步驟與學習:

  • 在 Hyperledger Fabric 中啟用 CouchDB
  • 創建一個索引
  • 將索引添加到你的鏈碼檔案夾
  • 安裝和定義鏈碼
  • 查詢CouchDB 狀態資料庫
  • 查詢和索引的最佳實踐
  • 在 CouchDB 狀態資料庫查詢中使用分頁
  • 升級索引
  • 洗掉索引

想要更深入的研究 CouchDB 的話,請參閱 使用 CouchDB 作為狀態資料庫 ,關于 Fabric 賬 本的跟多資訊請參閱 Ledger 主題,下邊的教程將詳細講述如何在你的區 塊鏈網路中使用 CouchDB ,

本教程將使用 Marbles sample 作為演示在 Fabric 中使用 CouchDB 的用例,并且將會把 Marbles 部署在 構建你的第一個網路 (BYFN)教程網路上,

為什么是 CouchDB ?

Fabric 支持兩種型別的節點資料庫,LevelDB 是默認嵌入在 peer 節點的狀態資料庫, LevelDB 用于將鏈碼資料存盤為簡單的鍵-值對,僅支持鍵、鍵范圍和復合鍵查詢,CouchDB 是一 個可選的狀態資料庫,支持以 JSON 格式在賬本上建模資料并支持富查詢,以便您查詢實際資料 內容而不是鍵,CouchDB 同樣支持在鏈碼中部署索引,以便高效查詢和對大型資料集的支持,

為了發揮 CouchDB 的優勢,也就是說基于內容的 JSON 查詢,你的資料必須以 JSON 格式 建模,你必須在設定你的網路之前確定使用 LevelDB 還是 CouchDB ,由于資料兼容性的問 題,不支持節點從 LevelDB 切換為 CouchDB ,網路中的所有節點必須使用相同的資料庫類 型,如果你想 JSON 和二進制資料混合使用,你同樣可以使用 CouchDB ,但是二進制資料只 能根據鍵、鍵范圍和復合鍵查詢,

在 Hyperledger Fabric 中啟用 CouchDB

CouchDB 是獨立于節點運行的一個資料庫行程,在安裝、管理和操作的時候有一些額外 的注意事項,有一個可用的 Docker 鏡像 CouchDB 并且我們建議它和節點運行在同一個服務器上,我們需要在每一個節點上安裝一個 CouchDB 容器,并且更新每一個節點的組態檔 core.yaml ,將節點指向 CouchDB 容器, core.yaml 檔案的路徑必須在環境變數 FABRIC_CFG_PATH 中指定:

  • 對于 Docker 的部署,在節點容器中 FABRIC_CFG_PATH 指定的檔案夾中的 core.yaml 是預先配置好的,如果你要使用 docker 環境,你可以通過重寫 docker-compose-couch.yaml 中的環境變數來覆寫core.yaml
    對于原生的二進制部署, core.yaml 包含在發布的構件中,

編輯 core.yaml 中的 stateDatabase 部分,將 stateDatabase 指定為 CouchDB 并且填寫 couchDBConfig
相關的配置,在 Fabric 中配置 CouchDB 的更多細節,請參閱 CouchDB 配置 ,

創建一個索引

為什么索引很重要?

索引可以讓資料庫不用在每次查詢的時候都檢查每一行,可以讓資料庫運行的更快和更高效, 一般來說,對頻繁查詢的資料進行索引可以使資料查詢更高效,為了充分發揮 CouchDB 的優 勢 – 對 JSON 資料進行富查詢的能力 – 并不需要索引,但是為了性能考慮強烈建議建立 索引,另外,如果在一個查詢中需要排序,CouchDB 需要在排序的欄位有一個索引,

注解

沒有索引的情況下富查詢也是可以使用的,但是會在 CouchDB 的日志中拋出一個沒有找到索引的警告,如果一個富查詢中包含了一個排序的說明,需要排序的那個欄位 就必須有索引;否則,查詢將會失敗并拋出錯誤,

為了演示構建一個索引,我們將會使用來自 Marbles sample. 的資料, 在這個例子中, Marbles 的資料結構定義如下:

type marble struct {
         ObjectType string `json:"docType"` //docType is used to distinguish the various types of objects in state database
         Name       string `json:"name"`    //the field tags are needed to keep case from bouncing around
         Color      string `json:"color"`
         Size       int    `json:"size"`
         Owner      string `json:"owner"`
}

在這個結構體中,( docType, name, color, size, owner )屬性 定義了和資產相關的賬本資料, docType 屬性用來在鏈碼中區分可能需要單獨查詢的 不同資料型別的模式,當時使用 CouchDB 的時候,建議包含 docType 屬性來區分在鏈 碼命名空間中的每一個檔案,(每一個鏈碼都需要有他們自己的 CouchDB 資料庫,也就是 說,每一個鏈碼都有它自己的鍵的命名空間,)

在 Marbles 資料結構的定義中, docType 用來識別這個檔案或者資產是一個彈珠資產, 同時在鏈碼資料庫中也可能存在其他檔案或者資產,資料庫中的檔案對于這些屬性值來說都是 可查詢的,

當為鏈碼查詢定義一個索引的時候,每一個索引都必須定義在一個擴展名為 *.json 的文本檔案中,并且索引定義的格式必須為 CouchDB 索引的 JSON 格式,

需要以下三條資訊來定義一個索引:

  • fields: 這些是常用的查詢欄位
  • name: 索引名
  • type: 它的內容一般是 json

例如,這是一個對欄位 foo 的一個名為 foo-index 的簡單索引,

{
    "index": {
        "fields": ["foo"]
    },
    "name" : "foo-index",
    "type" : "json"
}

可選地,設計檔案( design document )屬性 ddoc 可以寫在索引的定義中,design document 是 CouchDB 結構,用于包含索引,索引可以以組的形式定義在設計檔案中以提升效率,但是 CouchDB 建議每一個設計檔案包含一個索引,

小技巧

當定義一個索引的時候,最好將 ddoc 屬性和值包含在索引內,包含這個 屬性以確保在你需要的時候升級索引,這是很重要的,它還使你能夠明確指定要在查詢上使用的索引,

這里有另外一個使用 Marbles 示例定義索引的例子,在索引 indexOwner 使用了多個欄位 docTypeowner 并且包含了 ddoc 屬性:

{
  "index":{
      "fields":["docType","owner"] // Names of the fields to be queried
  },
  "ddoc":"indexOwnerDoc", // (optional) Name of the design document in which the index will be created.
  "name":"indexOwner",
  "type":"json"
}

在上邊的例子中,如果設計檔案 indexOwnerDoc 不存在,當索引部署的時候會自動創建 一個,一個索引可以根據欄位串列中指定的一個或者多個屬性構建,而且可以定義任何屬性的 組合,一個屬性可以存在于同一個 docType 的多個索引中,在下邊的例子中, index1 只包含 owner 屬性, index2 包含 owner 和 color 屬性, index3 包含 owner、 color 和 size 屬性,另外,注意,根據 CouchDB 的建議,每一個索引的定義 都包含一個它們自己的 ddoc 值,

{
  "index":{
      "fields":["owner"] // Names of the fields to be queried
  },
  "ddoc":"index1Doc", // (optional) Name of the design document in which the index will be created.
  "name":"index1",
  "type":"json"
}

{
  "index":{
      "fields":["owner", "color"] // Names of the fields to be queried
  },
  "ddoc":"index2Doc", // (optional) Name of the design document in which the index will be created.
  "name":"index2",
  "type":"json"
}

{
  "index":{
      "fields":["owner", "color", "size"] // Names of the fields to be queried
  },
  "ddoc":"index3Doc", // (optional) Name of the design document in which the index will be created.
  "name":"index3",
  "type":"json"
}

一般來說,你為索引欄位建模應該匹配將用于查詢過濾和排序的欄位,對于以 JSON 格式 構建索引的更多資訊請參閱 CouchDB documentation ,

關于索引最后要說的是,Fabric 在資料庫中為檔案建立索引的時候使用一種成為 索引升溫 (index warming) 的模式, CouchDB 直到下一次查詢的時候才會索引新的或者更新的 檔案,Fabric 通過在每一個資料區塊提交完之后請求索引更新的方式,來確保索引處于 ‘熱 (warm)’ 狀態,這就確保了查詢速度快,因為在運行查詢之前不用索引檔案,這個程序保 持了索引的現狀,并在每次新資料添加到狀態資料的時候重繪,

將索引添加到你的鏈碼檔案夾

當你完成索引之后,你需要把它打包到你的鏈碼中,以便于將它部署到合適的元資料檔案夾,你可以使用 peer lifecycle chaincode 命令安裝鏈碼,JSON 索引檔案必須放在鏈碼目錄的 META-INF/statedb/couchdb/indexes 路徑下,

下邊的 Marbles 示例 展示了如何將索引打包到鏈碼中,

Marbles Chaincode Index Package

這個例子包含了一個名為 indexOwnerDoc 的索引:

{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}

啟動網路

Try it yourself

我們將會啟動一個 Fabric 測驗網路并且使用它來部署 marbles 鏈碼, 使用下面的命令導航到 Fabric samples 中的目錄 test-network :

cd fabric-samples/test-network

對于這個教程,我們希望在一個已知的初始狀態進行操作, 下面的命令會洗掉正在進行的或停止的 docker 容器并且移除之前生成的構件:

./network.sh down

如果你之前從沒運行過這個教程,在我們部署鏈碼到網路之前你需要使用 vendor 來安裝鏈碼的依賴檔案, 運行以下的命令:

cd ../chaincode/marbles02/go
GO111MODULE=on go mod vendor
cd ../../../test-network

在 test-network 目錄中,使用以下命令部署帶有 CouchDB 的測驗網路:

./network.sh up createChannel -s couchdb

運行這個命令會創建兩個使用 CouchDB 作為狀態資料庫的 fabric 節點, 同時也會創建一個排序節點和一個名為 mychannel 的通道

安裝和定義鏈碼

客戶端應用程式通過鏈碼和區塊鏈賬本互動,所以我們需要在每一個執行和背書交易的節點上安裝鏈碼,但是在我們和鏈碼互動之前,通道中的成員需要一致同意鏈碼的定義,以此 來建立鏈碼的治理,在之前的章節中,我們演示了如何將索引添加到鏈碼檔案夾中以便索引和鏈碼部署在一起,

鏈碼在安裝到 Peer 節點之前需要打包,我們可以使用 peer lifecycle chaincode package 命令來打包彈珠鏈碼,

Try it yourself

  1. 啟動測驗網路后,在你終端拷貝粘貼下面的環境變數,這樣就可以使用 Org1 管理員用戶和網路互動, 確保你在 test-network 目錄中,
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
  1. 使用下面的命令來打包 marbles 鏈碼:
peer lifecycle chaincode package marbles.tar.gz --path ../chaincode/marbles02/go --lang golang --label marbles_1

這個命令會創建一個名為 marbles.tar.gz 的鏈碼包,

  1. 使用下面的命令來安裝鏈碼包到節點上 peer0.org1.example.com:
peer lifecycle chaincode install marbles.tar.gz

一個成功的安裝命令會回傳鏈碼 id ,就像下面的回傳資訊:

2019-04-22 18:47:38.312 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nJmarbles_1:0907c1f3d3574afca69946e1b6132691d58c2f5c5703df7fc3b692861e92ecd3\022\tmarbles_1" >
2019-04-22 18:47:38.312 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: marbles_1:0907c1f3d3574afca69946e1b6132691d58c2f5c5703df7fc3b692861e92ecd3

安裝鏈碼到 peer0.org1.example.com 后,我們需要讓 Org1 同意鏈碼定義,

  1. 使用下面的命令來用你的當前節點查詢已安裝鏈碼的 package ID ,
peer lifecycle chaincode queryinstalled

這個命令會回傳和安裝命令相同的 package ID , 你應該看到類似下面的輸出:

Installed chaincodes on peer:
Package ID: marbles_1:60ec9430b221140a45b96b4927d1c3af736c1451f8d432e2a869bdbf417f9787, Label: marbles_1
  1. 將 package ID 宣告為一個環境變數, 將 peer lifecycle chaincode queryinstalled 命令回傳的 marbles_1 的 package ID 粘貼到下面的命令中, package ID 不是所有用戶都一樣,所以你需要使用終端回傳的 package ID 來完成這個步驟,
export CC_PACKAGE_ID=marbles_1:60ec9430b221140a45b96b4927d1c3af736c1451f8d432e2a869bdbf417f9787
  1. 使用下面的命令讓 Org1 同意 marbles 鏈碼定義,
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0 --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

命令成功運行的時候你應該看到和下面類似的資訊:

2020-01-07 16:24:20.886 EST [chaincodeCmd] ClientWait -> INFO 001 txid [560cb830efa1272c85d2f41a473483a25f3b12715d55e22a69d55abc46581415] committed with status (VALID) at

在鏈碼定義提交之前,我們需要大多陣列織同意鏈碼定義,這意味著我們需要 Org2 也同意該鏈碼定義,因為我們不需要 Org2 背書鏈碼并且不安裝鏈碼包到 Org2 的節點,所以 packageID 作為鏈碼定義的一部分,我們不需要向 Org2 提供它,

  1. 讓終端使用 Org2 管理員身份操作,將下面的命令一起拷貝粘貼到節點容器并且一次性全部運行,
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
  1. 使用下面的命令讓 Org2 同意鏈碼定義:
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0 --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --init-required --sequence 1 --tls --cafile $ORDERER_CA
  1. 現在我們可以使用 peer lifecycle chaincode commit 命令來提交鏈碼定義到通道:
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
export ORG1_CA=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export ORG2_CA=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --version 1.0 --sequence 1 --signature-policy "OR('Org1MSP.member','Org2MSP.member')" --init-required --tls --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG1_CA --peerAddresses localhost:9051 --tlsRootCertFiles $ORG2_CA

提交交易成功的時候你應該看到類似下面的資訊:

2019-04-22 18:57:34.274 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [3da8b0bb8e128b5e1b6e4884359b5583dff823fce2624f975c69df6bce614614] committed with status (VALID) at peer0.org2.example.com:9051
2019-04-22 18:57:34.709 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [3da8b0bb8e128b5e1b6e4884359b5583dff823fce2624f975c69df6bce614614] committed with status (VALID) at peer0.org1.example.com:7051
  1. 因為 marbles 鏈碼包含一個初始化函式,所以在我們使用鏈碼其他函式前需要使用 peer chaincode invoke 命令呼叫 Init()
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name marbles --isInit --tls --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles $ORG1_CA -c '{"Args":["Init"]}'

驗證部署的索引

當鏈碼在節點上安裝并且在通道上部署完成之后,索引會被部署到每一個節點的 CouchDB 狀態資料庫上,你可以通過檢查 Docker 容器中的節點日志來確認 CouchDB 是否被創建成功,

Try it yourself

為了查看節點 Docker 容器的日志,打開一個新的終端視窗,然后運行下邊的命令來匹配索 引被創建的確認資訊,

docker logs peer0.org1.example.com  2>&1 | grep "CouchDB index"

你將會看到類似下邊的結果:

[couchdb] CreateIndex -> INFO 0be Created CouchDB index [indexOwner] in state database [mychannel_marbles] using design document [_design/indexOwnerDoc]

注解

如果 Marbles 沒有安裝在節點 peer0.org1.example.com 上,你可 能需要切換到其他的安裝了 Marbles的節點,

查詢 CouchDB 狀態資料庫

現在索引已經在 JSON 中定義了并且和鏈碼部署在了一起,鏈碼函式可以對 CouchDB 狀態資料庫執行 JSON 查詢,同時 peer 命令可以呼叫鏈碼函式,

在查詢的時候指定索引的名字是可選的,如果不指定,同時索引已經在被查詢的欄位上存在了,已存在的索引會自動被使用,

小技巧

在查詢的時候使用 use_index 關鍵字包含一個索引名字是一個好的習慣,如果 不使用索引名,CouchDB 可能不會使用最優的索引,而且CouchDB 也可能會不使用 索引,但是在測驗期間資料少的化你很難意識到,只有在資料量大的時候,你才可能 會意識到因為 CouchDB沒有使用索引而導致性能較低,

在鏈碼中構建一個查詢

你可以使用鏈碼中定義的富查詢來查詢賬本上的資料, marbles02 示例 中包含了兩個富查詢方法:

  • queryMarbles –

一個 富查詢 示例,這是一個可以將一個(選擇器)字串傳入函式的查詢, 這個查詢對于需要在運行時動態創建他們自己的選擇器的客戶端應用程式很有用, 跟多關于選擇器的資訊請參考 CouchDB selector syntax ,

  • queryMarblesByOwner –

一個查詢邏輯保存在鏈碼中的引數查詢的示例,在這個例子中,函式值接受單個引數, 就是彈珠的主人,然后使用 JSON 查詢語法查詢狀態資料庫中匹配 “marble” 的 docType 和 擁有者 id 的 JSON 檔案,

使用 peer 命令運行查詢

由于缺少一個客戶端程式,我們可以使用節點命令來測驗鏈碼中定義的查詢函式,我們將自定義 peer chaincode query 命令來使用Marbles索引 indexOwner 并且使用 queryMarbles 函式查詢所有 marbles 中擁有者是 “tom” 的 marble ,

Try it yourself

在查詢資料庫之前,我們應該添加些資料,運行下面的命令使用 Org1 創建一個擁有者是 “tom” 的 marble :

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
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 marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}'

當鏈碼實體化后,然后部署索引,索引就可以自動被鏈碼的查詢使用,CouchDB 可以根 據查詢的欄位決定使用哪個索引,如果這個查詢準則存在索引,它就會被使用,但是建議在查詢的時候指定 use_index 關鍵字,下邊的 peer 命令就是一個如何通過在選擇器語法中包含 use_index 關鍵字來明確地指定索引的例子:

// Rich Query with index name explicitly specified:
peer chaincode query -C mychannel -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}'

詳細看一下上邊的查詢命令,有三個引數值得關注:

  • queryMarbles
    Marbles 鏈碼中的函式名稱,注意使用了一個 shim shim.ChaincodeStubInterface 來訪問和修改賬本, getQueryResultForQueryString() 傳遞 queryString 給 shim API getQueryResult()
func (t *SimpleChaincode) queryMarbles(stub shim.ChaincodeStubInterface, args []string) pb.Response {

        //   0
        // "queryString"
         if len(args) < 1 {
                 return shim.Error("Incorrect number of arguments. Expecting 1")
         }

         queryString := args[0]

         queryResults, err := getQueryResultForQueryString(stub, queryString)
         if err != nil {
               return shim.Error(err.Error())
         }
         return shim.Success(queryResults)
}
  • {"selector":{"docType":"marble","owner":"tom"}

這是一個 ad hoc 選擇器 字串的示例,用來查找所有 owner 屬性值為 tommarble 的檔案,

  • "use_index":["_design/indexOwnerDoc", "indexOwner"]

指定設計檔案名 indexOwnerDoc 和索引名 indexOwner ,在這個示例中,查詢 選擇器通過指定 use_index 關鍵字明確包含了索引名,回顧一下上邊的索引定義 創建一個索引 , 它包含了設計檔案, “ddoc”:“indexOwnerDoc” ,在 CouchDB 中,如果你想在查詢 中明確包含索引名,在索引定義中必須包含 ddoc 值,然后它才可以被 use_index 關鍵字參考,
利用索引的查詢成功后回傳如下結果:

Query Result: [{"Key":"marble1", "Record":{"color":"blue","docType":"marble","name":"marble1","owner":"tom","size":35}}]

查詢和索引的最佳實踐

由于不必掃描整個資料庫,couchDB 中使用索引的查詢會完成的更快,理解索引的機制會使你在網路中寫出更高性能的查詢陳述句并幫你的應用程式處理更大的資料或區塊,

規劃好安裝在你鏈碼上的索引同樣重要,你應該每個鏈碼只安裝少量能支持大部分查詢的索引, 添加太多索引或索引使用過多的欄位會降低你網路的性能,這是因為每次區塊提交后都會更新索引, “索引升溫( index warming )”需要更新的索引越多,完成交易的時間就越長,

這部分的案例有助于演示查詢該如何使用索引,什么型別的查詢擁有最好的性能,當你寫查詢的時候記得下面幾點:

  • 使用的索引中所有欄位必須同樣包含在選擇器和排序部分,
  • 越復雜的查詢性能越低并且使用索引的幾率也越低,
  • 你應該盡量避免會引起全表查詢或全索引查詢的運算子,比如: $or, $in and $regex ,

在教程的前面章節,你已經對 marbles 鏈碼執行了下面的查詢:

// Example one: query fully supported by the index
export CHANNEL_NAME=mychannel
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

Marbles 鏈碼已經安裝了 indexOwnerDoc 索引:

{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}

注意查詢中的欄位 docType 和 owner 都包含在索引中,這使得該查詢成為一個完全支持查詢( fully supported query ), 因此這個查詢能使用索引中的資料,不需要搜索整個資料庫,像這樣的完全支持查詢比你鏈碼中的其他查詢回傳地更快,

如果你在上述查詢中添加了額外欄位,它仍會使用索引,然后,查詢會另外在索引資料中查找符合額外欄位的資料,導致相應時間變長, 下面的例子中查詢仍然使用索引,但是會比前面的查詢回傳更慢,

// Example two: query fully supported by the index with additional data
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\",\"color\":\"red\"}, \"use_index\":[\"/indexOwnerDoc\", \"indexOwner\"]}"]}'

沒有包含全部索引欄位的查詢會查詢整個資料庫,舉個例子,下面的查詢使用 owner 欄位查找資料, 沒有指定該項擁有的型別,因為索引 ownerIndexDoc 包含兩個欄位 owner 和 docType , 所以下面的查詢不會使用索引,

// Example three: query not supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"owner\":\"tom\"}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

一般來說,越復雜的查詢回傳的時間就越長,并且使用索引的概率也越低, 運算子 $or, $in 和 $regex 會常常使得查詢搜索整個索引或者根本不使用索引,

舉個例子,下面的查詢包含了條件 $or 使得查詢會搜索每一個 marble 和每一條擁有者是 tom 的資料,

// Example four: query with $or supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"$or\":[{\"docType\":\"marble\"},{\"owner\":\"tom\"}]}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

這個查詢仍然會使用索引,因為它查找的欄位都包含在索引 indexOwnerDoc 中,然而查詢中的條件 $or 需要掃描索引中 所有的項,導致回應時間變長,

索引不支持下面這個復雜查詢的例子,

// Example five: Query with $or not supported by the index
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarbles", "{\"selector\":{\"$or\":[{\"docType\":\"marble\",\"owner\":\"tom\"},{\"color\":\"yellow\"}]}, \"use_index\":[\"indexOwnerDoc\", \"indexOwner\"]}"]}'

這個查詢搜索所有擁有者是 tom 的 marbles 或其它顏色是黃色的項, 這個查詢不會使用索引因為它需要查找 整個表來匹配條件 $or,根據你賬本的資料量,這個查詢會很久才會回應或者可能超時,

雖然遵循查詢的最佳實踐非常重要,但是使用索引不是查詢大量資料的解決方案,區塊鏈的資料結構優化了 校驗和確定交易,但不適合資料分析或報告,如果你想要構建一個儀表盤( dashboard )作為應用程式的一部分或分析網路的 資料,最佳實踐是查詢一個從你節點復制了資料的離線區塊鏈資料庫,這樣可以使你了解區塊鏈上的資料并且不會降低 網路的性能或中斷交易,

你可以使用來自你應用程式的區塊或鏈碼事件來寫入交易資料到一個離線的鏈資料庫或分析引擎, 對于每一個接收到的區塊,區塊監聽應用將遍歷區塊中的每一個交易并根據每一個有效交易的 讀寫集 中的鍵值對構建一個資料存盤, 檔案 基于通道的 Peer 節點事件服務 提供了可重放事件,以確保下游資料存盤的完整性,有關如何使用事件監聽器將資料寫入外部資料庫的例子, 訪問 Fabric Samples 的 Off chain data sample

在 CouchDB 狀態資料庫查詢中使用分頁

當 CouchDB 的查詢回傳了一個很大的結果集時,有一些將結果分頁的 API 可以提供給鏈碼呼叫,分 頁提供了一個將結果集合磁區的機制,該機制指定了一個 pagesize 和起始點 – 一個從結果集 合的哪里開始的 書簽 ,客戶端應用程式以迭代的方式呼叫鏈碼來執行查詢,直到沒有更多的結 果回傳,更多資訊請參考 topic on pagination with CouchDB ,

我們將使用 Marbles sample 中的函式 queryMarblesWithPagination 來演示在鏈碼和客戶端應用程式中如何使用分頁,

  • queryMarblesWithPagination –

一個 使用分頁的 ad hoc 富查詢 的示例,這是一個像上邊的示例一樣,可以將一個(選擇器) 字串傳入函式的查詢,在這個示例中,在查詢中也包含了一個 pageSize 作為一個 書簽 ,

為了演示分頁,需要更多的資料,本例假設你已經加入了 marble1 ,在節點容器中執行下邊的命令創建 4 個 “tom” 的彈珠,這樣就創建了 5 個 “tom” 的彈珠:

Try it yourself

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
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 marbles -c '{"Args":["initMarble","marble2","yellow","35","tom"]}'
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 marbles -c '{"Args":["initMarble","marble3","green","20","tom"]}'
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 marbles -c '{"Args":["initMarble","marble4","purple","20","tom"]}'
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 marbles -c '{"Args":["initMarble","marble5","blue","40","tom"]}'

除了上邊示例中的查詢引數, queryMarblesWithPagination 增加了 pagesize 和 bookmark , PageSize 指定了每次查詢回傳結果的數量, bookmark 是一個用來告訴 CouchDB 從每一頁從 哪開始的 “錨(anchor)” ,(結果的每一頁都回傳一個唯一的書簽)

  • queryMarblesWithPagination
    Marbles 鏈碼中函式的名稱,注意 shim shim.ChaincodeStubInterface 用于訪問和修改賬本, getQueryResultForQueryStringWithPagination() 將 queryString 、 pagesize 和 bookmark 傳遞給 shim API GetQueryResultWithPagination() ,
func (t *SimpleChaincode) queryMarblesWithPagination(stub shim.ChaincodeStubInterface, args []string) pb.Response {

      //   0
      // "queryString"
      if len(args) < 3 {
              return shim.Error("Incorrect number of arguments. Expecting 3")
      }

      queryString := args[0]
      //return type of ParseInt is int64
      pageSize, err := strconv.ParseInt(args[1], 10, 32)
      if err != nil {
              return shim.Error(err.Error())
      }
      bookmark := args[2]

      queryResults, err := getQueryResultForQueryStringWithPagination(stub, queryString, int32(pageSize), bookmark)
      if err != nil {
              return shim.Error(err.Error())
      }
      return shim.Success(queryResults)
}

下邊的例子是一個 peer 命令,以 pageSize 為 3 沒有指定 boomark 的方式呼叫 queryMarblesWithPagination ,

小技巧

當沒有指定 bookmark 的時候,查詢從記錄的“第一”頁開始,

Try it yourself

// Rich Query with index name explicitly specified and a page size of 3:
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3",""]}'

下邊是接收到的回應(為清楚起見,增加了換行),回傳了五個彈珠中的三個,因為 pagesize 設定成了 3 ,

[{"Key":"marble1", "Record":{"color":"blue","docType":"marble","name":"marble1","owner":"tom","size":35}},
 {"Key":"marble2", "Record":{"color":"yellow","docType":"marble","name":"marble2","owner":"tom","size":35}},
 {"Key":"marble3", "Record":{"color":"green","docType":"marble","name":"marble3","owner":"tom","size":20}}]
[{"ResponseMetadata":{"RecordsCount":"3",
"Bookmark":"g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkGoOkOWDSOSANIFk2iCyIyVySn5uVBQAGEhRz"}}]

注解

Bookmark 是 CouchDB 每次查詢的時候唯一生成的,并顯示在結果集中,將回傳的 bookmark
傳遞給迭代查詢的子集中來獲取結果的下一個集合,

下邊是一個 pageSize 為 3 的呼叫 queryMarblesWithPagination 的 peer 命令, 注意一下這里,這次的查詢包含了上次查詢回傳的 bookmark ,

Try it yourself

peer chaincode query -C $CHANNEL_NAME -n marbles -c ‘{“Args”:[“queryMarblesWithPagination”, “{“selector”:{“docType”:“marble”,“owner”:“tom”}, “use_index”:[”_design/indexOwnerDoc", “indexOwner”]}",“3”,“g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkGoOkOWDSOSANIFk2iCyIyVySn5uVBQAGEhRz”]}’
下邊是接收到的回應(為清楚起見,增加了換行),回傳了五個彈珠中的三個,回傳了剩下的兩個記錄:

[{"Key":"marble4", "Record":{"color":"purple","docType":"marble","name":"marble4","owner":"tom","size":20}},
 {"Key":"marble5", "Record":{"color":"blue","docType":"marble","name":"marble5","owner":"tom","size":40}}]
[{"ResponseMetadata":{"RecordsCount":"2",
"Bookmark":"g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1"}}]

最后一個命令是呼叫 queryMarblesWithPagination 的 peer 命令,其中 pageSize 為 3 ,bookmark 是前一次查詢回傳的結果,

Try it yourself

peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesWithPagination", "{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}","3","g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1"]}'

下邊是接收到的回應(為清楚起見,增加了換行),沒有記錄回傳,說明所有的頁 面都獲取到了:

[] [{“ResponseMetadata”:{“RecordsCount”:“0”,
“Bookmark”:“g1AAAABLeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqz5yYWJeWkmoKkOWDSOSANIFk2iCyIyVySn5uVBQAGYhR1”}}]

對于如何使用客戶端應用程式使用分頁迭代結果集,請在 Marbles sample , 中搜索 getQueryResultForQueryStringWithPagination 函式,

升級索引

可能需要隨時升級索引,相同的索引可能會存在安裝的鏈碼的子版本中,為了索引的升級, 原來的索引定義必須包含在設計檔案 ddoc 屬性和索引名,為了升級索引定義,使用相 同的索引名并改變索引定義,簡單編輯索引 JSON 檔案并從索引中增加或者洗掉欄位, Fabric 只支持 JSON 型別的索引,不支持改變索引型別,升級后的索引定義在鏈碼定義提交之后 會重新部署在節點的狀態資料庫中,

注解

如果狀態資料庫有大量資料,重建索引的程序會花費較長時間,在此期間鏈碼執 行或者查詢可能會失敗或者超時,

迭代索引定義

如果你在開發環境中訪問你的節點的 CouchDB 狀態資料庫,你可以迭代測驗各種索引以支 持你的鏈碼查詢,鏈碼的任何改變都可能需要重新部署,使用 CouchDB Fauxton interface 或者命令列 curl 工具來創建和升級索引,

注解

Fauxton 是用于創建、升級和部署 CouchDB 索引的一個網頁,如果你想嘗試這個介面, 有一個 Marbles 示例中索引的
Fauxton 版本格式的例子,如果你使用 CouchDB 部署了測驗網路,可以通過在瀏覽器的導航欄中打開
http://localhost:5984/_utils 來 訪問 Fauxton ,

另外,如果你不想使用 Fauxton UI,下邊是通過 curl 命令在 mychannel_marbles 資料庫上創 建索引的例子:

// Index for docType, owner.
// Example curl command line to define index in the CouchDB channel_chaincode database
 curl -i -X POST -H "Content-Type: application/json" -d
        "{\"index\":{\"fields\":[\"docType\",\"owner\"]},
          \"name\":\"indexOwner\",
          \"ddoc\":\"indexOwnerDoc\",
          \"type\":\"json\"}" http://hostname:port/mychannel_marbles/_index

注解

如果你在測驗網路中配置了 CouchDB,請使用 localhost:5984 替換 hostname:port ,

洗掉索引

Fabric 工具不能洗掉索引,如果你需要洗掉索引,就要手動使用 curl 命令或者 Fauxton 接 口操作資料庫,

洗掉索引的 curl 命令格式如下:

curl -X DELETE http://localhost:5984/{database_name}/_index/{design_doc}/json/{index_name} -H  "accept: */*" -H  "Host: localhost:5984"

要洗掉本教程中的索引,curl 命令應該是:

curl -X DELETE http://localhost:5984/mychannel_marbles/_index/indexOwnerDoc/json/indexOwner -H  "accept: */*" -H  "Host: localhost:5984"

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/301349.html

標籤:區塊鏈

上一篇:Remix-IDE(三)

下一篇:Remix-IDE(一)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • JAVA使用 web3j 進行token轉賬

    最近新學習了下區塊鏈這方面的知識,所學不多,給大家分享下。 # 1. 關于web3j web3j是一個高度模塊化,反應性,型別安全的Java和Android庫,用于與智能合約配合并與以太坊網路上的客戶端(節點)集成。 # 2. 準備作業 jdk版本1.8 引入maven <dependency> < ......

    uj5u.com 2020-09-10 03:03:06 more
  • 以太坊智能合約開發框架Truffle

    前言 部署智能合約有多種方式,命令列的瀏覽器的渠道都有,但往往跟我們程式員的風格不太相符,因為我們習慣了在IDE里寫了代碼然后打包運行看效果。 雖然現在IDE中已經存在了Solidity插件,可以撰寫智能合約,但是部署智能合約卻要另走他路,沒辦法進行一個快捷的部署與測驗。 如果團隊管理的區塊節點多、 ......

    uj5u.com 2020-09-10 03:03:12 more
  • 谷歌二次驗證碼成為區塊鏈專用安全碼,你怎么看?

    前言 谷歌身份驗證器,前些年大家都比較陌生,但隨著國內互聯網安全的加強,它越來越多地出現在大家的視野中。 比較廣泛接觸的人群是國際3A游戲愛好者,游戲盜號現象嚴重+國外賬號安全應用廣泛,這類游戲一般都會要求用戶系結名為“兩步驗證”、“雙重驗證”等,平臺一般都推薦用谷歌身份驗證器。 后來區塊鏈業務風靡 ......

    uj5u.com 2020-09-10 03:03:17 more
  • 密碼學DAY1

    目錄 ##1.1 密碼學基本概念 密碼在我們的生活中有著重要的作用,那么密碼究竟來自何方,為何會產生呢? 密碼學是網路安全、資訊安全、區塊鏈等產品的基礎,常見的非對稱加密、對稱加密、散列函式等,都屬于密碼學范疇。 密碼學有數千年的歷史,從最開始的替換法到如今的非對稱加密演算法,經歷了古典密碼學,近代密 ......

    uj5u.com 2020-09-10 03:03:50 more
  • 密碼學DAY1_02

    目錄 ##1.1 ASCII編碼 ASCII(American Standard Code for Information Interchange,美國資訊交換標準代碼)是基于拉丁字母的一套電腦編碼系統,主要用于顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,并等同于國際標準ISO/IE ......

    uj5u.com 2020-09-10 03:04:50 more
  • 密碼學DAY2

    ##1.1 加密模式 加密模式:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html ECB ECB : Electronic codebook, 電子密碼本. 需要加密的訊息按照塊密碼的塊大小被分為數個塊,并對每個塊進 ......

    uj5u.com 2020-09-10 03:05:42 more
  • NTP時鐘服務器的特點(京準電子)

    NTP時鐘服務器的特點(京準電子) NTP時鐘服務器的特點(京準電子) 京準電子官V——ahjzsz 首先對時間同步進行了背景介紹,然后討論了不同的時間同步網路技術,最后指出了建立全球或區域時間同步網存在的問題。 一、概 述 在通信領域,“同步”概念是指頻率的同步,即網路各個節點的時鐘頻率和相位同步 ......

    uj5u.com 2020-09-10 03:05:47 more
  • 標準化考場時鐘同步系統推進智能化校園建設

    標準化考場時鐘同步系統推進智能化校園建設 標準化考場時鐘同步系統推進智能化校園建設 安徽京準電子科技官微——ahjzsz 一、背景概述隨著教育事業的快速發展,學校建設如雨后春筍,隨之而來的學校教育、管理、安全方面的問題成了學校管理人員面臨的最大的挑戰,這些問題同時也是學生家長所擔心的。為了讓學生有更 ......

    uj5u.com 2020-09-10 03:05:51 more
  • 位元幣入門

    引言 位元幣基本結構 位元幣基礎知識 1)哈希演算法 2)非對稱加密技術 3)數字簽名 4)MerkleTree 5)哪有位元幣,有的是UTXO 6)位元幣挖礦與共識 7)區塊驗證(共識) 總結 引言 上一篇我們已經知道了什么是區塊鏈,此篇說一下區塊鏈的第一個應用——位元幣。其實先有位元幣,后有的區塊 ......

    uj5u.com 2020-09-10 03:06:15 more
  • 北斗對時服務器(北斗對時設備)電力系統應用

    北斗對時服務器(北斗對時設備)電力系統應用 北斗對時服務器(北斗對時設備)電力系統應用 京準電子科技官微(ahjzsz) 中國北斗衛星導航系統(英文名稱:BeiDou Navigation Satellite System,簡稱BDS),因為是目前世界范圍內唯一可以大面積提供免費定位服務的系統,所以 ......

    uj5u.com 2020-09-10 03:06:20 more
最新发布
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:46:47 more
  • Hyperledger Fabric 使用 CouchDB 和復雜智能合約開發

    在上個實驗中,我們已經實作了簡單智能合約實作及客戶端開發,但該實驗中智能合約只有基礎的增刪改查功能,且其中的資料管理功能與傳統 MySQL 比相差甚遠。本文將在前面實驗的基礎上,將 Hyperledger Fabric 的默認資料庫支持 LevelDB 改為 CouchDB 模式,以實作更復雜的資料... ......

    uj5u.com 2023-04-16 07:28:31 more
  • .NET Core 波場鏈離線簽名、廣播交易(發送 TRX和USDT)筆記

    Get Started NuGet You can run the following command to install the Tron.Wallet.Net in your project. PM> Install-Package Tron.Wallet.Net 配置 public reco ......

    uj5u.com 2023-04-14 08:08:00 more
  • DKP 黑客分析——不正確的代幣對比率計算

    概述: 2023 年 2 月 8 日,針對 DKP 協議的閃電貸攻擊導致該協議的用戶損失了 8 萬美元,因為 execute() 函式取決于 USDT-DKP 對中兩種代幣的余額比率。 智能合約黑客概述: 攻擊者的交易:0x0c850f,0x2d31 攻擊者地址:0xF38 利用合同:0xf34ad ......

    uj5u.com 2023-04-07 07:46:09 more
  • Defi開發簡介

    Defi開發簡介 介紹 Defi是去中心化金融的縮寫, 是一項旨在利用區塊鏈技術和智能合約創建更加開放,可訪問和透明的金融體系的運動. 這與傳統金融形成鮮明對比,傳統金融通常由少數大型銀行和金融機構控制 在Defi的世界里,用戶可以直接從他們的電腦或移動設備上訪問廣泛的金融服務,而不需要像銀行或者信 ......

    uj5u.com 2023-04-05 08:01:34 more
  • solidity簡單的ERC20代幣實作

    // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; import "hardhat/console.sol"; //ERC20 同質化代幣,每個代幣的本質或性質都是相同 //ETH 是原生代幣,它不是ERC20代幣, ......

    uj5u.com 2023-03-21 07:56:29 more
  • solidity 參考型別修飾符memory、calldata與storage 常量修飾符C

    在solidity語言中 參考型別修飾符(參考型別為存盤空間不固定的數值型別) memory、calldata與storage,它們只能修飾參考型別變數,比如字串、陣列、位元組等... memory 適用于方法傳參、返參或在方法體內使用,使用完就會清除掉,釋放記憶體 calldata 僅適用于方法傳參 ......

    uj5u.com 2023-03-08 07:57:54 more
  • solidity注解標簽

    在solidity語言中 注釋符為// 注解符為/* 內容*/ 或者 是 ///內容 注解中含有這幾個標簽給予我們使用 @title 一個應該描述合約/介面的標題 contract, library, interface @author 作者的名字 contract, library, interf ......

    uj5u.com 2023-03-08 07:57:49 more
  • 評價指標:相似度、GAS消耗

    【代碼注釋自動生成方法綜述】 這些評測指標主要來自機器翻譯和文本總結等研究領域,可以評估候選文本(即基于代碼注釋自動方法而生成)和參考文本(即基于手工方式而生成)的相似度. BLEU指標^[^?88^^?^]^:其全稱是bilingual evaluation understudy.該指標是最早用于 ......

    uj5u.com 2023-02-23 07:27:39 more
  • 基于NOSTR協議的“公有制”版本的Twitter,去中心化社交軟體Damus

    最近,一個幽靈,Web3的幽靈,在網路游蕩,它叫Damus,這玩意詮釋了什么叫做病毒式營銷,滑稽的是,一個Web3產品卻在Web2的產品鏈上瘋狂傳銷,各方大佬紛紛為其背書,到底發生了什么?Damus的葫蘆里,賣的是什么藥? 注冊和簡單實用 很少有什么產品在用戶注冊環節會有什么噱頭,但Damus確實出 ......

    uj5u.com 2023-02-05 06:48:39 more