面向开发人员的区块链链代码深入研究:使用 Go 编写智能合约

【区块链】智能合约简介 简单介绍了智能合约相关概念 阅读详情

http://www.th7.cn/Program/go/201703/1141269.shtml


在本教程中,将学习如何使用 Golang 为基于 Hyperledger Fabric v0.6 的区块链网络开发链代码。我不但会介绍一些基础知识,比如链代码的角色和与底层 Fabric 交互的 API,还会介绍各种高级主题,比如数据建模、访问控制和事件。大量的代码示例演示了区块链上的一个住房贷款和购买合同流程。(参见本教程末尾部分的 “可下载资源”,下载完整的示例链代码。)


本教程是本系列的第一篇;后续教程将介绍如何对链代码执行单元测试,以及如何开发可调用您部署的链代码的客户端应用程序。


链代码是什么? 
在 IBM Cloud 上开发-- 免费试用 30 天 

您可以获得 2GB 运行时和容器内存,配置最多 10 个云服务,以及获得免费的服务台支持。试用 Bluemix,只需单击一次即可通过Blockchain Starter Developer 计划开始构建和测试区块链网络。


链代码也称为 智能合约 ,实质上是控制区块链网络中的不同实体或相关方如何相互交互或交易的业务逻辑。简言之,链代码将业务网络交易封装在代码中。可以调用链代码来设置和获取账本或 world state。


在发表本教程时,Hyperledger 支持使用 Golang 或 Java™ 语言编写链代码,链代码最终在一个 Docker 容器内运行。因为 Java 链代码支持还处于公测阶段,所以本教程将重点介绍 Go。


设置开发环境 
区块链开发人员推荐阅读内容 

借助区块链开发人员中心内的 developerWorks 教程、课程、博客和社区支持,提高您的开发技能。


按照 IBM Bluemix 文档中的步骤开始 “ 设置开发环境 ”。到达题为 “设置开发管道” 的小节时,您已经为开始使用 Go 开发链代码做好了准备。


链代码结构 

让我们仔细看看链代码的结构。前面已经提到过,清单 1 及整篇教程中的示例链代码,以及所讨论的架构都严格遵守 Hyperledger Fabric v0.6 预览版的规定。


清单 1 的 第 4 行 将 shim 包导入您的链代码包中。shim 包提供了一些 API,以便您的链代码与底层区块链网络交互来访问状态变量、交易上下文、调用方证书和属性,并调用其他链代码和执行其他操作。


清单 1. 示例链代码 
package main
import "fmt"
import "github.com/hyperledger/fabric/core/chaincode/shim"
type SampleChaincode struct {
}
func (t *SampleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
return nil, nil
}
func (t *SampleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
return nil, nil
}
func (t *SampleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
return nil, nil
}
func main() {
err := shim.Start(new(SampleChaincode))
if err != nil {
fmt.Println("Could not start SampleChaincode")
} else {
fmt.Println("SampleChaincode successfully started")
}
} 
Main 函数 

任何 Go 程序的起点都是 main 函数,因此该函数被用于引导/启动链代码。当对等节点部署其链代码实例时,就会执行 main 函数。


如清单 2 中 第 2 行 所示,shim.Start(new(SampleChaincode)) 行启动了链代码并向对等节点注册它。要在本地验证这一点,可在您的开发环境中运行该代码,这将生成以下错误:[shim] CRIT : peer.address not configured, can't connect to peer.


清单 2. Main() 
func main() {
err := shim.Start(new(SampleChaincode))
if err != nil {
fmt.Println("Could not start SampleChaincode")
} else {
fmt.Println("SampleChaincode successfully started")
}
} 

SampleChaincode 是实现 shim.Chaincode 接口所需的结构,它必须包含 3 种方法 — Init、Query 和 Invoke — 才能被 shim 包视为有效的链代码类型。让我们逐一看看这 3 种方法。


Init 方法 

Init 方法 在链代码首次部署到区块链网络时调用,将由部署自己的链代码实例的每个对等节点执行。此方法可用于任何与初始化、引导或设置相关的任务。


清单 3. Init() 
func (t *SampleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
return nil, nil
} 
Query 方法 

只要在区块链状态上执行任何读取/获取/查询操作,就会调用Query 方法。根据链代码的复杂性,此方法含有您的读取/获取/查询逻辑,或者它可以外包给可从 Query 方法内调用的不同方法。


Query 方法不会更改底层链代码的状态,因此它不会在交易上下文内运行。如果尝试在 Query 方法内修改区块链的状态,将出现一个错误显示缺少交易上下文。另外,因为此方法仅用于读取区块链的状态,所以对它的调用不会记录在区块链上。


清单 4. Query() 
func (t *SampleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
return nil, nil
} 
Invoke 方法 

只要修改区块链的状态,就会调用Invoke 方法。简言之,所有创建、更新和删除操作都应封装在 Invoke 方法内。因为此方法将修改区块链的状态,所以区块链 Fabric 代码会自动创建一个交易上下文,以便此方法在其中执行。对此方法的所有调用都会在区块链上记录为交易,这些交易最终被写入区块中。


清单 5. Invoke() 
func (t *SampleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
return nil, nil
} 
链代码中的数据模型 

Hyperledger 账本包含两部分:


World State,存储在一个键值存储中。这个键值存储由 RocksDB 提供支持。这个键值存储获取一个字节数组作为值,该值可用于存储序列化 JSON 结构。基本上讲,这个键值存储可用于存储您的智能合约正常运行所需的所有自定义数据模型/模式。
区块链,由一系列区块组成,每个区块包含许多交易。每个区块包含 World State 的哈希值,并被链接到前一个区块。区块链采用仅附加模式 (append-only)。

清单 6 展示了如何创建自定义数据模型/模式。它定义了住房贷款申请所需的数据模型。主要模型称为 LoanApplication ,它拥有原始数据类型和复杂数据类型,也就是 Personal 和 Financial Info。


因为我们的键值存储将数据存储为 JSON,所以这些数据模型最终需要转换为 JSON 字符串。每个字段(如 json:"id" )的注释的作用类似于编组 (marshal) /解组 (unmarshal) API 的元数据,该 API 将使用这些注释将每个字段映射到相应的 JSON 字符串等效表示。


清单 6. 创建自定义数据模型/模式的代码 
//custom data models
type PersonalInfo struct {
Firstname string `json:"firstname"`
Lastnamestring `json:"lastname"`
DOB string `json:"DOB"`
Email string `json:"email"`
Mobilestring `json:"mobile"`
}
type FinancialInfo struct {
MonthlySalaryint `json:"monthlySalary"`
MonthlyRentint `json:"monthlyRent"`
OtherExpenditure int `json:"otherExpenditure"`
MonthlyLoanPayment int `json:"monthlyLoanPayment"`
}
type LoanApplication struct {
ID string`json:"id"`
PropertyId string`json:"propertyId"`
LandId string`json:"landId"`
PermitId string`json:"permitId"`
BuyerIdstring`json:"buyerId"`
SalesContractIdstring`json:"salesContractId"`
PersonalInfo PersonalInfo`json:"personalInfo"`
FinancialInfoFinancialInfo `json:"financialInfo"`
Status string`json:"status"`
RequestedAmountint `json:"requestedAmount"`
FairMarketValueint `json:"fairMarketValue"`
ApprovedAmount int `json:"approvedAmount"`
ReviewerId string`json:"reviewerId"`
LastModifiedDate string`json:"lastModifiedDate"`
} 
存储和检索数据 

清单 7 和清单 8 中的代码展示了如何将数据存储到账本中以及如何从账本中获取数据。


将数据存储到账本中 

清单 7 中 第 1 行 上的 CreateLoanApplication 接受两个参数。第一个参数是 ChaincodeStubInterface,它拥有实用的 API 来与区块链账本、交易上下文、调用方证书等交互。第二个参数是一个字符串数组,该方法的调用方可以使用该数组传入所需的参数。


第 2-8 行记录和验证了输入参数。


在 第 9 行 上,检索了贷款申请的 Id 值,该值将用作存储实际贷款申请对象的键。


在 第 10 行 上,以 JSON 字符串格式检索了实际贷款申请内容。例如,‘{"propertyId":"prop1","landId":"land1","permitId":"permit1","buyerId":"vojha24","personalInfo":{"firstname":"Varun","lastname":"Ojha","dob":"dob","email":"varun@gmail.com","mobile":"99999999"},"financialInfo":{"monthlySalary":10000,"otherExpenditure":0,"monthlyRent":1000,"monthlyLoanPayment":1000},"status":"Submitted","requestedAmount":40000,"fairMarketValue":58000,"approvedAmount":40000,"reviewedBy":"abc1","lastModifiedDate":"21/09/2016 2:30pm"}’


在 第 12 行 上,调用了 stub.PutState 方法,以便将贷款申请 id 和实际的贷款申请 JSON 内容作为一个键值对存储到区块链账本中。请注意,存储在键值存储中的值必须始终是字节数组。因此,在存储到账本之前,贷款申请 JSON 字符串首先被转换为字节数组。


清单 7. 将数据存储到账本中的代码 
func CreateLoanApplication(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
fmt.Println("Entering CreateLoanApplication")
if len(args) < 2 {
fmt.Println("Invalid number of args")
return nil, errors.New("Expected at least two arguments for loan application creation")
}
var loanApplicationId = args[0]
var loanApplicationInput = args[1]
err := stub.PutState(loanApplicationId, []byte(loanApplicationInput))
if err != nil {
fmt.Println("Could not save loan application to ledger", err)
return nil, err
}
fmt.Println("Successfully saved loan application")
return nil, nil
} 
从账本获取数据 

在清单 8 中, 第 1 行 上的 GetLoanApplication 方法接受两个参数。第一个参数是 ChaincodeStubInterface ,它拥有实用的 API 来与区块链账本、交易上下文、调用方证书等交互。第二个参数是一个字符串数组,该方法的调用方可使用该数组传入需要的参数。


第 2-7 行记录和验证了输入参数。


在 第 9 行 上,检索了贷款申请的 Id 值,该值将用作从账本中检索实际贷款申请对象的键。


在 第 10 行 上,通过传入 loanApplicationId 键,调用 stub.GetState 方法以字节数组格式检索贷款申请 JSON 内容。请注意,存储在键值存储中的值必须始终是字节数组。因此,在存储到账本之前,贷款申请 JSON 字符串首先被转换为字节数组。


清单 8. 从账本中获取数据的代码 
func GetLoanApplication(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
fmt.Println("Entering GetLoanApplication")
if len(args) < 1 {
fmt.Println("Invalid number of arguments")
return nil, errors.New("Missing loan application ID")
}
var loanApplicationId = args[0]
bytes, err := stub.GetState(loanApplicationId)
if err != nil {
fmt.Println("Could not fetch loan application with id "+loanApplicationId+" from ledger", err)
return nil, err
}
return bytes, nil
} 

备注:也可以使用传统关系数据模型处理数据。例如, ChaincodeStubInterface 能够创建表格并处理行和列。但这只是一种逻辑抽象,而且数据将作为键值对存储在 RocksDB 中。在撰写本文时,Hyperledger Fabric 1.0 版正在开发之中,而且表数据结构已被弃用。因此,本教程不会讨论它,以便最大限度地减少链代码开发人员从 v0.6 过渡到 v1.0 所需执行的更改。


在 golang 结构与 JSON 字符串之间编组和解组数据 

如清单 7 和清单 8 中所示,stub.PutState 和 stub.GetState 方法只处理字节数组。所以,能够将链代码中使用的常规结构对象与 JSON 字符串进行相互转换很重要。


清单 9 展示了如何将一种结构编组为可存储在账本中的 JSON 字符串字节数组。 第 2 行 创建了 PersonalInfo 对象的一个实例。 第 3 行 使用 json 包将对象编组为 JSON 字符串,并返回同一个字符串的字节数组。


可以通过将 "encoding/json" 包含在顶部的 import 代码块中来导入 json 包。然后此字节数组可以使用清单 7 中给出的 stub.PutState 方法来存储到账本中。


清单 9. 将一种结构编组为 JSON 字符串字节数组的代码 
var personalInfo PersonalInfo
personalInfo = PersonalInfo{"Varun", "Ojha", "dob", "varun@gmail.com", "9999999999"}
bytes, err ;= json.Marshal (&personalInfo)
if err != nil {
fmt.Println("Could not marshal personal info object", err)
return nil, err
}
err = stub.PutState("key", bytes) 

清单 10 展示如何将一种结构从字节数组解组为已填充的结构。 第 1 行 使用关联的键从账本中获取 PersonalInfo JSON 字符串字节。 第 3 行 将第 1 行中检索的字节解组为变量 personalInfo 所引用的 PersonalInfo 对象。


现在可以使用 第 4 行 所示的点记法来访问和修改 personalInfo 对象。


清单 10. 将一种结构从字节数组解组为已填充的结构的代码 
piBytes, err := stub.GetState(la1)
var personalInfo PersonalInfo
err = json.Unmarshal(piBytes, &personalInfo)
fmt.Println(personalInfo.Firstname) 
实现访问控制和权限 

Hyperledger 与其他区块链结构的主要区别之一是,它有一个安全的、带许可的账本,该账本适合用于实现企业级解决方案。


成员服务 

Hyperledger 中的 “成员服务” 组件对在区块链网络中实现安全性和许可发挥着关键作用。它负责向用户发放登记和交易证书来响应注册和登记。


登记证书 :成员服务中的证书颁发机构将向希望在区块链上交易的用户发放一个登记证书,作为一种身份证明。
交易证书 :交易证书应用作一次性令牌,由调用方/调用应用程序连同对链代码的每个调用请求一起传递。交易证书是通过数学方式从父登记证书那里获得的,因此从理论上讲,可以利用父登记证书生成无限多个交易证书。在将交易数据存储在区块链中时,可以使用交易证书对该数据进行签名和加密。这可以确保只有拥有交易证书的用户或拥有父证书的监管者/审计者等人员,能够实际查看写入的交易内容。
属性 :每个交易证书可以包含一些由用户定义的属性。在从客户端应用程序发往证书颁发机构的注册请求中,可以提及这些属性。本系列的后续教程将从开发客户端应用程序的角度进行详细介绍。

清单 11 展示了如何从调用方的交易证书检索属性。前面已经提到过,用户或客户端应用程序需要在每个链代码调用请求中传入用户的证书,以便对区块链网络上的目标对等节点执行身份验证。HFC SDK 负责自动在请求中传递证书。


清单 11 的 第 11 行 上的 Invoke 函数已经过修改,以便检查输入函数名称并将调用工作委托给合适的处理函数。此外,Invoke 函数还会验证发送 CreateLoanApplication 调用请求的调用方的访问权限和角色。Invoke 函数调用自定义的 GetCertAttribute 函数从调用方的交易证书中检索特定属性。


GetCertAttribute函数通过在 第 3 行 传入属性名称来获取属性值。


第 15 行检查调用方是否拥有 Bank Admin 角色并能调用 CreateLoanApplication 函数。如果调用方没有所需的角色,则会返回相应的错误。这样就可以在链代码中实现基于属性的访问控制。


ChaincodeStubInterface有一些实用程序函数可以处理属性,比如 ReadCertAttribute 、 VerifyAttribute 和 VerifyAttributes 。所有这些方法都依靠 github.com/hyperledger/fabric/core/chaincode/shim/crypto/attr包来创建和使用负责处理属性的 AttributeHandlerImpl。


在目前正在开发的 Hyperledger Fabric 版本 (v1.0) 中,这些实用程序函数已从 ChaincodeStubInterface 删除。因此在 v1.0 中,链代码开发人员需要直接使用 AttributeHandlerImpl 来处理属性。


清单 11. 从调用方的交易证书中检索属性 
func GetCertAttribute(stub shim.ChaincodeStubInterface, attributeName string) (string, error) {
fmt.Println("Entering GetCertAttribute")
attr, err := stub.ReadCertAttribute(attributeName)
if err != nil {
return "", errors.New("Couldn't get attribute " + attributeName + ". Error: " + err.Error())
}
attrString := string(attr)
return attrString, nil
}
func (t *SampleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
if function == "CreateLoanApplication" {
username, _ := GetCertAttribute(stub, "username")
role, _ := GetCertAttribute(stub, "role")
if role == "Bank_Home_Loan_Admin" {
return CreateLoanApplication(stub, args)
} else {
return nil, errors.New(username + " with role " + role + " does not have access to create a loan application")
}
}
return nil, nil
} 
创建和发出自定义事件 

Hyperledger 包含一个事件框架,可以使用该框架发布/订阅预定义的或自定义的事件。您可以自由地在链代码中创建和发出自定义事件。例如,只要区块链的状态发生更改,就会生成一个事件。通过向区块链上的事件中心注册一个事件适配器,客户端应用程序可以订阅和使用这些事件。本系列的后续教程将详细介绍客户端应用程序如何使用 HFC SDK 订阅和使用通过链代码生成的事件。


除了自定义事件之外,Hyperledger 中包含的一些预定义的内部事件还包括:


区块事件 
链代码事件 
拒绝事件 
注册事件 

清单 12 中的代码展示了如何创建和发布自定义事件。


第 1-4 行定义了一个包含类型和描述字段的自定义事件对象。


CreateLoanApplication函数从 第 6 行 开始,已被修改为包括在成功创建贷款申请时创建事件。


第 23 行创建了 customEvent 对象的实例并填入适当的事件细节。


第 24 行按照前面解释的方法将事件对象编组为 JSON 字符串字节数组。


第 28 行设置了自定义事件。 stub.SetEvent 方法接受两个参数:事件 name 和 payload 。客户端应用程序可订阅同一个事件名称/主题,以便在链代码生成事件时接收它们。


清单 12. 创建和发布自定义事件 
type customEvent struct {
Typestring `json:"type"`
Description string `json:"description"`
}
func CreateLoanApplication(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
fmt.Println("Entering CreateLoanApplication")
if len(args) < 2 {
fmt.Println("Invalid number of args")
return nil, errors.New("Expected at least two arguments for loan application creation")
}
var loanApplicationId = args[0]
var loanApplicationInput = args[1]
err := stub.PutState(loanApplicationId, []byte(loanApplicationInput))
if err != nil {
fmt.Println("Could not save loan application to ledger", err)
return nil, err
}
var event = customEvent = {"createLoanApplication", "Successfully created loan application with ID " + loanApplicationId}
eventBytes, err ;= json.Marshal(&event)
if err != nil {
return nil, err
}
err = stub.SetEvent("evtSender", eventBytes)
if err != nil {
fmt.Println("Could not set event for loan application creation", err)
}
fmt.Println("Successfully saved loan application")
return nil, nil
} 
处理日志 

要在链代码中处理日志,既可以使用标准 fmt 包和 print 语句,也可以使用 shim 包中的 ChaincodeLogger 类型。


ChaincodeLogger 支持以下日志级别:


CRITICAL 
ERROR 
WARNING 
NOTICE 
INFO 
DEBUG 

可以通过 3 种方式设置日志级别:


shim.SetChaincodeLoggingLevel() :此方法将采用 CORE_LOGGING_CHAINCODE 集中的 core.yaml 文件内指定的日志级别。core.yaml 文件包含设置和部署区块链网络所需的所有配置信息。
shim.SetLoggingLevel(level LoggingLevel) :此方法将在 shim 级别上设置日志级别。
ChaincodeLogger.SetLevel(level LoggingLevel) :此方法将在单个记录器实例级别上设置日志级别。

清单 13 展示了如何创建、配置和使用 ChaincodeLogger。


清单 13. 创建、配置和使用 ChaincodeLogger 
func SampleLogging() {
//Different Logging Levels
criticalLevel, _ := shim.LogLevel("CRITICAL")
errorLevel, _ := shim.LogLevel("ERROR")
warningLevel, _ := shim.LogLevel("WARNING")
noticeLevel, _ := shim.LogLevel("NOTICE")
infoLevel, _ := shim.LogLevel("INFO")
debugLevel, _ := shim.LogLevel("DEBUG")
//Logging level at the shim level
shim.SetLoggingLevel(infoLevel)
//Create a logger instance
myLogger := shim.NewLogger("SampleChaincodeLogger")
//Set logging level on logger instance
myLogger.SetLevel(infoLevel)
//Check logging level
fmt.Println(myLogger.IsEnabledFor(infoLevel))
//Log statements
myLogger.Info("Info Message")
myLogger.Critical("Critical Message")
myLogger.Warning("Warning Message")
myLogger.Error("Error Message")
myLogger.Notice("Notice Message")
myLogger.Debug("Debug Message")
} 
常见问题和最佳实践 

在与客户一起开发区块链应用程序时,我常常被问及以下问题。


如何将文件(图像、音频、视频、PDF 等)存储在区块链中? 

以下两种方法在最新的 Hyperledger Fabric (v0.6) 中都有效:


将所有文件/对象存储为 base64 编码字符串。客户端应用程序将文件/对象转换为 base64 编码字符串,并将它作为输入参数发送给链代码函数。然后链代码将它作为字节数组存储在键/值存储中。 
实际的文件/对象内容存储在区块链以外的地方;例如,存储在 IBM Bluemix Object Storage 服务 中。仅将文件/对象的链接/引用/ID 连同文件/对象的哈希值一起存储在区块链上。存储哈希值可确保在区块链外对文件/对象的任何篡改都能被相关方/实体检测出来。
如何避免将私有业务逻辑/合同细节泄漏给网络中的所有对等节点? 

此问题是在一个供应链场景中提出的,区块链解决方案的一个最终用户不满意在对所有对等节点可见的智能合约中共享私有业务逻辑/合同信息(比如与不同供应商谈判的不同价格)。在 v0.6 中,可以使用外部系统集成来处理这种情况。


解决方案:对等节点希望保持为私有的业务逻辑/规则/合同,可以作为一组业务规则在外部应用程序(比如服务)中运行。链代码本身能够执行出站调用。所以举例而言,链代码可对业务规则/逻辑服务执行 REST API 调用并获取结果,以便隐藏逻辑,让实际链代码看不见它。


可以从链代码内与区块链外的系统集成。例如,可以使用链代码与外部数据库、API 等通信。但重要的是确保与这些系统的交互不会让链代码变得不确定。


局限性和问题 
修改业务规则服务时无需了解其他对等节点,因为它在区块链外运行。根据区块链网络中不同参与方之间的业务交互类型,这可能导致信任问题。 
业务规则服务必须可供区块链网络中运行智能合约/链代码的所有对等节点使用。 
该解决方案可能导致链代码变得不确定。 链代码必须是确定性的。

简言之,如果多方使用相同的参数调用链代码中的同一个函数,那么结果应该是相同的。例如,如果在与响应关联的链代码函数中使用一个时间戳或计数器,那么多方对链代码的调用会导致不同的结果。这将在区块链网络中的不同对等节点之间产生不一致的账本状态。

请记住,每次调用链代码都会导致一致性网络中所有对等节点在自己的本地账本副本上调用链代码。


备注:在目前正在开发的 Hyperledger Fabric v1.0 中,此问题已通过更改架构本身得到系统解决。


结束语 

本教程首先介绍了链代码的基础知识,然后深入介绍了链代码的构建块,以及可用于在链代码中执行重要任务(比如访问控制、数据建模和事件管理)的不同 API。请下载 SampleChaincode.go 文件中的统一代码段。


本系列的后续教程将介绍测试驱动的链代码开发,开发可与区块链网络通信的 Node.js 客户端应用程序,从而将开发流程补充完整。


Go语言与区块链:用Golang开发区块链应用实战 本文旨在为开发者提供使用Go语言开发区块链应用的全面指南。区块链基础原理和架构Go语言在区块链开发中的优势区块链核心组件的Go实现智能合约开发实际应用案例分析区块链核心概念和原理Go语言实现区块链的关键技术完整区块链项目实战实际应用场景和工具推荐未来发展趋势和挑战区块链:一种分布式数据库技术,通过加密算法将数据区块按时间顺序链接起来智能合约:运行在区块链上的自执行合约,条款直接写入代码共识机制:区块链网络中节点达成一致的算法挖矿。 阅读详情

相关推荐

Go语言的区块链

简洁性:Go语言的语法相对简单,开发人员可以快速上手,减少了学习成本。并发性:内置的并发模型(Goroutines)使得Go在处理高并发场景时表现优异。高性能:Go语言编译后的执行速度接近C语言,适合高性能应用开发。垃圾回收:内存管理方面,Go语言提供了垃圾回收机制,减轻了开发者的负担。强大的标准库:Go的标准库中提供了大量用于网络编程、数据处理等功能的模块,方便了开发。去中心化:不依赖于中央机构,通过点对点网络实现数据的共享与维护。不可篡改性。

2501_90416780的博客 2611

三、hyperledger fabric 开发第一个智能合约

一、编写智能合约代码HelloWorld.go,go语言实现,代码很简单,每个合约包含两个方法,Init、Invoke。 package main import ( "fmt" "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/protos/peer" ...

u010857052的专栏 8185

Go最新使用Golang Web3库进行区块链开发_go语言有web3库吗(1),Golang面试题汇总

在区块链开发中,智能合约是非常重要的组件。Web3库提供了API来部署和与智能合约进行交互。在上述代码中,我们首先准备一个包含智能合约代码的ABI(Application Binary Interface)和字节码。然后,我们使用函数来部署合约。此函数接受一个上下文对象、一个账户对象、一个智能合约的ABI、一个区块链客户端、智能合约的字节码、以太币的价值、构造函数的参数。

BlackCATdog的博客 1103

使用go与智能合约交互之使用abigen生成合约go文件进行调用

本章我们就来学习一下如何使用abigen生成合约go文件并进行调用

外柏叁布道者 2321

基于Hyperledger Fabric的企业级区块链开发指南:Go语言与链码编写

Hyperledger Fabric 是一个由Linux基金会主办的开源区块链项目,主要面向企业使用场景。模块化设计:允许用户根据需求定制各个组件(如共识机制、身份管理等)。支持智能合约(链码):链码是Hyperledger Fabric网络中的业务逻辑代码,类似于以太坊中的智能合约。隐私保护:通过通道(Channel)机制确保数据的隔离和隐私。高性能:Fabric提供了高吞吐量和低延迟的交易处理。链码的结构通常需要继承,这是Hyperledger Fabric提供的基类,用于简化开发。import (

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 707

使用golang与智能合约进行交互

Go和以太坊智能合约交互,是使用了以太坊的JSON-RPC接口,即把所有读取写入请求转换成RPC请求,发送给以太坊节点,并等待回应。这和之前转账是完全一致的,只不过交互的地址从EOA变成了合约而已。

西京刀客 1750

Fabric智能合约实验-学生信息管理系统(Windows系统)

注意:该方法是绑定在智能合约对象中的(StudentContract结构体), 因为要提供智能合约允许被外部调用,而StudentContract结构体是继承了超级账本智能合约接口的对象,拥有被外部调用的能力)本实验项目为一个学生信息管理系统(部分),要求链码提供学生信息的管理功能:包括新增学生信息,修改学生信息,查询学生信息等。在本项目中,只要涉及数据变更的,都需要通过执行调用。(2)定义结构体:本项目要定义两个结构体,第一个是继承Fabric智能合约对象的接口的结构体,另外一个是学生信息结构体。

weixin_61275790的博客 2967

Go-开源|基于区块链的智能合约快速上手

[云框架]基于区块链的智能合约 / Blockchain, Fabric Hyperledger, Smart Contract / 区块链, Fabric Hyperledger, 智能合约

区块链学习笔记(一. 了解)

区块链是一种全新的信息记录模式,每一个参与者都可以是记录者,分布式账本。它不是一种单纯的技术,是多个老技术和新技术的结合应用,去中心化,如果是联盟链应该是多中心化了,类似于git,p2p下载,数据不可篡改,不可抵赖。 第一代是加密货币, 第二代是智能合约, 第三代是联盟链(私有链)。 共识算法 Merkle 树(简化支付验证),查询的话,区块头(版本号,区块高度,难度值,时间戳,随机数...

lin49940的专栏 1426

ESP32 BLE Mesh Provisioner实战:手把手教你用ESP-IDF配网智能灯泡(附常见错误排查)

本文提供了一份基于ESP-IDF的ESP32 BLE Mesh Provisioner实战指南,详细解析了配网器的核心角色与工作流程。文章手把手教你从工程搭建、代码初始化到核心回调解析,并重点针对常见的‘Model not bound to AppKey’等错误提供了深度排查思路与解决方案,帮助你构建一个稳定可靠的智能照明网关。

desk3的博客 513

从零到一:用Python打造你的智能交互桌宠,附完整源码与打包指南

本文详细介绍了如何从零开始使用Python开发智能交互桌宠,涵盖环境配置、窗口创建、动图加载、交互功能实现及打包发布全流程。教程特别适合零基础开发者,通过完整源码和分步指南,帮助读者快速掌握桌面宠物开发技巧,打造个性化AI伴侣。

weixin_29094539的博客 292

hyperledger fabric 智能合约开发(三)------合约接口的数据操作方法

合约接口的数据操作方法 写入区块链数据如果是 struct 结构体,需要序列化成二进制,通常使用 json,其他形式的序列化也可以,只要能反序列化即可(反序列化,是二进制数组变为格式化数据)。Hyperledger fabric levelDB提供基于key/value的数据存储,其中key是字符串,value则是二进制字节数组,Hyperledger的Go API提供了三个方法用于数据存取:P...

Rcvisual的博客 5116

TEM图像处理实战指南:从基础操作到金属材料分析

本文提供了一份全面的透射电镜(TEM)图像处理实战指南,涵盖从基础操作到金属材料深度分析的全流程。重点讲解了TEM图像预处理、选区电子衍射(SAED)标定、高分辨像(HRTEM)分析及STEM图像应用等核心技能,并结合金属材料(如铝合金、钢)的析出相鉴定、位错分析和界面结构研究等实际案例,帮助研究者从原始数据中准确提取晶体结构、缺陷及成分信息。

weixin_29284201的博客 206

如何成为区块链开发人员

目前的区块链现象是以极其强大的存在形式进行着技术革命,这将在不久的将来成为改变游戏规则的方式,并且是区块链开发人员技能提升的必要条件。区块链应用程序可以使每个领域受益; 这就是为什么需要个人或团队来帮助公司将区块链技术应用到他们的业务运营中。 许多公司,如三星和IBM,都开始实施区块链产品,以改变其工作流程,使客户更舒适,更轻松地使用。目前,区块链开发商的...

rejames的博客 1万+

告别手动复制粘贴:3种高效合并Excel表格的方法对比(含代码)

本文对比了VBA、Power Query和Python三种高效合并Excel表格的方法,并提供了可直接运行的代码。针对不同数据量、更新频率和技术背景,详细分析了各方案的优缺点与适用场景,帮助读者告别低效的手动操作,实现自动化数据整合。

weixin_29057237的博客 440

从零开始:手把手教你用Verilog搭建一个可配置的Cache模块(以Vortex GPGPU为例)

本文详细介绍了如何使用Verilog从零开始搭建一个可配置的Cache模块,以Vortex GPGPU为例。内容涵盖Cache设计基础、模块接口与参数化设计、核心子模块实现、仲裁与一致性机制、功能验证与性能调优等关键环节,适合RTL设计初学者和希望深入理解Cache工作原理的工程师。通过实战指南,读者可以掌握硬件代码分析技巧,提升Cache模块的设计能力。

weixin_42552315的博客 440

长安链使用Golang编写智能合约教程(二)

本篇说的是长安链2.3.+的版本的智能合约,虽然不知道两者有什么区别,但是编译器区分。

目前专注区块链相关技术的学习与分享 2630

游戏开发实战:用UE4 Marschner模型打造次世代头发渲染(附Shader代码解析)

本文详细解析了如何在UE4中使用Marschner模型实现次世代头发渲染,包括Shader代码逐行解读与参数调优。通过对比传统Kajiya-Kay模型,展示了Marschner模型在物理精确性和视觉效果上的优势,并提供了性能优化与实战技巧,帮助技术美术师提升游戏角色渲染品质。

weixin_28223453的博客 239

在Geth私链上发布智能合约

前一阵子学习了一些区块链相关,并记录了在在Geth上创建私链的过程。详情请参考如下的几篇文章: 在Ubuntu下使用Geth搭建自己的以太坊私有链 CentOS7下安装Geth,搭建以太坊私有链 Geth私链的多节点运行 这篇文章简单讲述下如何在Geth上部署和发布智能合约。 智能合约是部署在区块链上的一组预定义的业务规则,具备确定性(Deterministic)执行的特征。换句话说...

Kevin的博客 4078

基于STM32的智慧农业大棚监测与控制系统设计与实现

摘要:本文设计了一种基于STM32F103C8T6单片机的智慧农业大棚监测与控制系统,集成多参数环境监测、智能控制和远程管理功能。系统可实时采集光照、CO2、温湿度和土壤湿度等参数,通过OLED显示并采用双模式控制机制:自动模式下根据阈值调节设备,手动模式下支持APP或按键控制。通过ESP8266模块接入机智云平台实现数据云存储和远程控制。测试表明系统具有高精度(温度±0.5℃、CO2±50ppm)、快速响应(<2s)和稳定运行(30天无故障)等特点,有效解决了传统大棚调控不及时等问题。创新点包括多参

3254968421的博客 484

计算机视觉学习路线图:从入门到专家

计算机视觉学习路线图:从入门到专家​ ,人工智能,计算机视觉,大模型,AI,计算机视觉学习路线图从七方面展开。先强调数学基础,含线性代数、概率统计和微积分;接着介绍 Python、OpenCV 等编程语言与工具;涵盖边缘检测、特征提取等经典算法;阐述深度学习中 CNN 结构、经典模型及实现;涉及目标检测、图像分割等高级专题;包含图像分类、目标检测和人脸识别等项目实战;最后提及科研进阶的论文阅读、项目参与和论文发表,助学习者从入门到专家。

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 7万+

使用solidity编程语言编写智能合约

智能合约编程语言 solidity语言 前言一、solidity语言是什么?二、一个简单的solidity智能合约1.编写智能合约2.编译合约3.部署合约总结 文章目录前言一、solidity语言是什么?二、一个简单的solidity智能合约1.编写智能合约2.编译合约3.部署合约总结 前言 随着区块链技术的不断发展,区块链被越来越多运用到生活中,什么是区块链智能合约嘞?简单说下,智能合约,就是一段写在区块链上的代码,一旦某个事件触发合约中的条款,代码即自动执行。也就是说,满足条件就执行,不需要人

chen07200的博客 4164

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Go语言原生智能合约开发与部署完全指南

Go语言作为编译型语言,在WASM合约开发中具有天然优势

码刀攻城 1018

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

07.Fabric的智能合约详解

导语 智能合约是区块链中一个非常重要的概念和组成部分。在Fabric中内成为Chaincode,中文翻译为链码。涉及到链码地方都是 Chaincode. 7.1 Chaincode 初探 Fabric中的Chaincode包含了一个Chaincode代码和Chaincode管理命令这两部分。 Chaincode 代码是业务的承载体,负责具体的业务逻辑 Chaincode 管理命令负责 Chain...

boss2967的博客 1万+

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

上一篇: 网页爬虫--scrapy入门
下一篇: tensorflow中文社区
pms1888
博客等级 码龄22年 20粉丝 43原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值