Hyperledger Fabric Go语言链码API解读

Go语言链码API解读

ChaincodeStubInterface Go语言的源码

package shim

import (
	"github.com/golang/protobuf/ptypes/timestamp"
	"github.com/hyperledger/fabric/protos/ledger/queryresult"
	pb "github.com/hyperledger/fabric/protos/peer"
)

// Chaincode interface must be implemented by all chaincodes. The fabric runs
// the transactions by calling these functions as specified.
type Chaincode interface {
	// Init is called during Instantiate transaction after the chaincode container
	// has been established for the first time, allowing the chaincode to
	// initialize its internal data
	Init(stub ChaincodeStubInterface) pb.Response

	// Invoke is called to update or query the ledger in a proposal transaction.
	// Updated state variables are not committed to the ledger until the
	// transaction is committed.
	Invoke(stub ChaincodeStubInterface) pb.Response
}

// ChaincodeStubInterface 链码接口,用于部署链码app来访问和修改账本信息
type ChaincodeStubInterface interface {
    
	// GetArgs 返回链码交易参数,返回类型是 [][]byte
	GetArgs() [][]byte

    // GetStringArgs 获取链码交易的指定参数,返回类型是string数组
    // # {"Args":["set","tom","100"]}
    // args = stub.GetStringArgs()
    // fmt.Println(args)
    // # 输出结果
    // ["set","tom","100"]
	GetStringArgs() []string

    // 获取调用链码交易中的参数,其中第一个参数作为被调用的函数名称,
    // 其余的参数作为函数的执行参数,是一个string数组
    // # {"Args":["set","tom","100"]}
    // fn, args := stub.GetFunctionAndParameters()
    // fmt.Println(fn, args)
    // # 输出结果
    // set ["tom", "100"]
	GetFunctionAndParameters() (string, []string)

	// GetArgsSlice 返回链码交易参数,返回类型是 byte数组
	GetArgsSlice() ([]byte, error)

    // GetTxID 获取当前交易的tx_id,每一笔交易和每一个客户端是唯一的
	GetTxID() string

	// GetChannelID 返回处理链码提议的通道channel
	GetChannelID() string

	// InvokeChaincode locally calls the specified chaincode `Invoke` using the
	// same transaction context; that is, chaincode calling chaincode doesn't
	// create a new transaction message.
	// If the called chaincode is on the same channel, it simply adds the called
	// chaincode read set and write set to the calling transaction.
	// If the called chaincode is on a different channel,
	// only the Response is returned to the calling chaincode; any PutState calls
	// from the called chaincode will not have any effect on the ledger; that is,
	// the called chaincode on a different channel will not have its read set
	// and write set applied to the transaction. Only the calling chaincode's
	// read set and write set will be applied to the transaction. Effectively
	// the called chaincode on a different channel is a `Query`, which does not
	// participate in state validation checks in subsequent commit phase.
	// If `channel` is empty, the caller's channel is assumed.
    // 调用另一个链码中的 Invoke 方法,也就是不同链码之间进行通信的方式
    // InvokeChaincode 使用相同的交易上下文本地调用指定的链码Invoke。
    // 也就是说链码调用不创建一笔新的交易.
    // (1) 如果被调用的链码在相同的channel中,可以简化为 被调用链码的读集和写集 追加到 调用链码的交易中
    // (2) 如果是在不同的chanel中, 只有被调用链码的响应结果 追加到调用链码交易中。
    // 任何被调用链码的PutState不会写入到账本,也就是说不同通道的被调用链码不会产生交易读写集。
    // 只有调用链码的读写集才会写入到交易。
    // 实际上,不同channel的链码调用只是一个Query查询,不参加提交阶段的世界状态的验证。
	InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response

    // GetState 负责查询账本,返回指定key的对应value值
    // 注意GetState不是从(writeset)写集 中读取数据,所以读取不到尚未提交的数据,
    // 也读取不到被PutState修改了但是尚未提交的数据
    // 如果key在账本中不存在,返回nil
    
    // strValue , err := stub.GetState("str")
    // if err != nil {
    //     fmt.Println("str GetState error: "+err.Error()) }else {
    //     fmt.Printf("str value: %s \n",string(strValue))
    // }
    // # 输出结果
    // str value: hello
    
	GetState(key string) ([]byte, error)

    
    // PutState设置一对指定的 `key` 和 `value` 到交易写集(writeset) 作为一个数据写提议。
    // 只有这笔交易被验证并且成功提交后才会写入到账本。
    //简单的key值不能是空字符串,并且不能以null字符开头,
    // 如果使用CouchDB,keys的值只能包含有效的UTF-8字符串,并且不能以"_"开头
    // 在账本中添加或更新一对键值。key是string类型,value是byte数组
    
    // err := stub.PutState("str",[]byte("hello"))
    // if err != nil {
    //     fmt.Println("str PutState error: "+err.Error()) }
    //  else{
    //     fmt.Println("str PutState success!")
    // }
    
	PutState(key string, value []byte) error

    
	// DelState records the specified `key` to be deleted in the writeset of
	// the transaction proposal. The `key` and its value will be deleted from
	// the ledger when the transaction is validated and successfully committed.    
    // DelState 交易提议的写集(writeset)中指定key的记录将会被删除。
    // key和key对应的value将会从账本中被删除,当交易被验证通过并成功提交后。
	DelState(key string) error

	// SetStateValidationParameter sets the key-level endorsement policy for `key`.
	SetStateValidationParameter(key string, ep []byte) error

	// GetStateValidationParameter retrieves the key-level endorsement policy
	// for `key`. Note that this will introduce a read dependency on `key` in
	// the transaction's readset.
	GetStateValidationParameter(key string) ([]byte, error)

	// GetStateByRange returns a range iterator over a set of keys in the
	// ledger. The iterator can be used to iterate over all keys
	// between the startKey (inclusive) and endKey (exclusive).
	// However, if the number of keys between startKey and endKey is greater than the
	// totalQueryLimit (defined in core.yaml), this iterator cannot be used
	// to fetch all keys (results will be capped by the totalQueryLimit).
	// The keys are returned by the iterator in lexical order. Note
	// that startKey and endKey can be empty string, which implies unbounded range
	// query on start or end.
	// Call Close() on the returned StateQueryIteratorInterface object when done.
	// The query is re-executed during validation phase to ensure result set
	// has not changed since transaction endorsement (phantom reads detected).
    // GetStateByRange 查询指定范围内的键值,startKey 为起始 key,endKey为终止 key
	GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error)

	// GetStateByRangeWithPagination returns a range iterator over a set of keys in the
	// ledger. The iterator can be used to fetch keys between the startKey (inclusive)
	// and endKey (exclusive).
	// When an empty string is passed as a value to the bookmark argument, the returned
	// iterator can be used to fetch the first `pageSize` keys between the startKey
	// (inclusive) and endKey (exclusive).
	// When the bookmark is a non-emptry string, the iterator can be used to fetch
	// the first `pageSize` keys between the bookmark (inclusive) and endKey (exclusive).
	// Note that only the bookmark present in a prior page of query results (ResponseMetadata)
	// can be used as a value to the bookmark argument. Otherwise, an empty string must
	// be passed as bookmark.
	// The keys are returned by the iterator in lexical order. Note
	// that startKey and endKey can be empty string, which implies unbounded range
	// query on start or end.
	// Call Close() on the returned StateQueryIteratorInterface object when done.
	// This call is only supported in a read only transaction.
	GetStateByRangeWithPagination(startKey, endKey string, pageSize int32,
		bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)

	// GetStateByPartialCompositeKey queries the state in the ledger based on
	// a given partial composite key. This function returns an iterator
	// which can be used to iterate over all composite keys whose prefix matches
	// the given partial composite key. However, if the number of matching composite
	// keys is greater than the totalQueryLimit (defined in core.yaml), this iterator
	// cannot be used to fetch all matching keys (results will be limited by the totalQueryLimit).
	// The `objectType` and attributes are expected to have only valid utf8 strings and
	// should not contain U+0000 (nil byte) and U+10FFFF (biggest and unallocated code point).
	// See related functions SplitCompositeKey and CreateCompositeKey.
	// Call Close() on the returned StateQueryIteratorInterface object when done.
	// The query is re-executed during validation phase to ensure result set
	// has not changed since transaction endorsement (phantom reads detected).
	GetStateByPartialCompositeKey(objectType string, keys []string) (StateQueryIteratorInterface, error)

	// GetStateByPartialCompositeKeyWithPagination queries the state in the ledger based on
	// a given partial composite key. This function returns an iterator
	// which can be used to iterate over the composite keys whose
	// prefix matches the given partial composite key.
	// When an empty string is passed as a value to the bookmark argument, the returned
	// iterator can be used to fetch the first `pageSize` composite keys whose prefix
	// matches the given partial composite key.
	// When the bookmark is a non-emptry string, the iterator can be used to fetch
	// the first `pageSize` keys between the bookmark (inclusive) and the last matching
	// composite key.
	// Note that only the bookmark present in a prior page of query result (ResponseMetadata)
	// can be used as a value to the bookmark argument. Otherwise, an empty string must
	// be passed as bookmark.
	// The `objectType` and attributes are expected to have only valid utf8 strings
	// and should not contain U+0000 (nil byte) and U+10FFFF (biggest and unallocated
	// code point). See related functions SplitCompositeKey and CreateCompositeKey.
	// Call Close() on the returned StateQueryIteratorInterface object when done.
	// This call is only supported in a read only transaction.
	GetStateByPartialCompositeKeyWithPagination(objectType string, keys []string,
		pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)

	// CreateCompositeKey combines the given `attributes` to form a composite
	// key. The objectType and attributes are expected to have only valid utf8
	// strings and should not contain U+0000 (nil byte) and U+10FFFF
	// (biggest and unallocated code point).
	// The resulting composite key can be used as the key in PutState().
    // 给定一组属性attributes,将这些属性组合起来构造一个复合键
    //对象类型和熟悉值只能是有效的utf8字符串,并且不能包含 U+0000 (nil byte) and U+10FFFF
	CreateCompositeKey(objectType string, attributes []string) (string, error)

	// SplitCompositeKey splits the specified key into attributes on which the
	// composite key was formed. Composite keys found during range queries
	// or partial composite key queries can therefore be split into their
	// composite parts.
    // 给定一个复合键,将其拆分为复合键所用的属性
    // 组合键常用于范围查询或者部分组合键查询
	SplitCompositeKey(compositeKey string) (string, []string, error)

	// GetQueryResult performs a "rich" query against a state database. It is
	// only supported for state databases that support rich query,
	// e.g.CouchDB. The query string is in the native syntax
	// of the underlying state database. An iterator is returned
	// which can be used to iterate over all keys in the query result set.
	// However, if the number of keys in the query result set is greater than the
	// totalQueryLimit (defined in core.yaml), this iterator cannot be used
	// to fetch all keys in the query result set (results will be limited by
	// the totalQueryLimit).
	// The query is NOT re-executed during validation phase, phantom reads are
	// not detected. That is, other committed transactions may have added,
	// updated, or removed keys that impact the result set, and this would not
	// be detected at validation/commit time.  Applications susceptible to this
	// should therefore not use GetQueryResult as part of transactions that update
	// ledger, and should limit use to read-only chaincode operations.
    // GetQueryResult 是对世界状态数据库进行富查询,仅有 couchDB 支持
    // 查询语句采用 底层状态数据库的语法。返回的StateQueryIterator可用于遍历查询 结果集。
	GetQueryResult(query string) (StateQueryIteratorInterface, error)

	// GetQueryResultWithPagination performs a "rich" query against a state database.
	// It is only supported for state databases that support rich query,
	// e.g., CouchDB. The query string is in the native syntax
	// of the underlying state database. An iterator is returned
	// which can be used to iterate over keys in the query result set.
	// When an empty string is passed as a value to the bookmark argument, the returned
	// iterator can be used to fetch the first `pageSize` of query results.
	// When the bookmark is a non-emptry string, the iterator can be used to fetch
	// the first `pageSize` keys between the bookmark and the last key in the query result.
	// Note that only the bookmark present in a prior page of query results (ResponseMetadata)
	// can be used as a value to the bookmark argument. Otherwise, an empty string
	// must be passed as bookmark.
	// This call is only supported in a read only transaction.
	GetQueryResultWithPagination(query string, pageSize int32,
		bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)

	// GetHistoryForKey returns a history of key values across time.
	// For each historic key update, the historic value and associated
	// transaction id and timestamp are returned. The timestamp is the
	// timestamp provided by the client in the proposal header.
	// GetHistoryForKey requires peer configuration
	// core.ledger.history.enableHistoryDatabase to be true.
	// The query is NOT re-executed during validation phase, phantom reads are
	// not detected. That is, other committed transactions may have updated
	// the key concurrently, impacting the result set, and this would not be
	// detected at validation/commit time. Applications susceptible to this
	// should therefore not use GetHistoryForKey as part of transactions that
	// update ledger, and should limit use to read-only chaincode operations.
    // 返回某个key的历史记录
    // 对应key的每一次历史更新,相关的交易id和timestamp时间戳的历史记录value值都会返回
    // timestamp 是客户端proposal header中的timestamp
    // peer配置中 core.ledger.history.enableHistoryDatabase=true 才生效
	GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)

	// GetPrivateData returns the value of the specified `key` from the specified
	// `collection`. Note that GetPrivateData doesn't read data from the
	// private writeset, which has not been committed to the `collection`. In
	// other words, GetPrivateData doesn't consider data modified by PutPrivateData
	// that has not been committed.
    // 返回指定指定集合collection中的指定key的value值
	GetPrivateData(collection, key string) ([]byte, error)

	// GetPrivateDataHash returns the hash of the value of the specified `key` from the specified `collection`
	// 返回指定指定集合collection中的指定key的hash
	GetPrivateDataHash(collection, key string) ([]byte, error)

	// PutPrivateData puts the specified `key` and `value` into the transaction's
	// private writeset. Note that only hash of the private writeset goes into the
	// transaction proposal response (which is sent to the client who issued the
	// transaction) and the actual private writeset gets temporarily stored in a
	// transient store. PutPrivateData doesn't effect the `collection` until the
	// transaction is validated and successfully committed. Simple keys must not
	// be an empty string and must not start with a null character (0x00) in order
	// to avoid range query collisions with composite keys, which internally get
	// prefixed with 0x00 as composite key namespace. In addition, if using
	// CouchDB, keys can only contain valid UTF-8 strings and cannot begin with an
	// an underscore ("_").
    // PutPrivateData 将指定的key和value对写入到交易私有写集(private writeset)
    // 注意只有 私有写集private writeset 的hash进入到交易提案的响应,
    // 事实上 私有写集private writeset临时存储了数据
    // PutPrivateData不会写入到 collection中,直到交易被验证和成功提交。
	PutPrivateData(collection string, key string, value []byte) error

	// DelState records the specified `key` to be deleted in the private writeset of
	// the transaction. Note that only hash of the private writeset goes into the
	// transaction proposal response (which is sent to the client who issued the
	// transaction) and the actual private writeset gets temporarily stored in a
	// transient store. The `key` and its value will be deleted from the collection
	// when the transaction is validated and successfully committed.
    // DelState 删除 交易私有写集private writeset 中指定key对应的记录
	DelPrivateData(collection, key string) error

	// SetPrivateDataValidationParameter sets the key-level endorsement policy
	// for the private data specified by `key`.
	SetPrivateDataValidationParameter(collection, key string, ep []byte) error

	// GetPrivateDataValidationParameter retrieves the key-level endorsement
	// policy for the private data specified by `key`. Note that this introduces
	// a read dependency on `key` in the transaction's readset.
	GetPrivateDataValidationParameter(collection, key string) ([]byte, error)

	// GetPrivateDataByRange returns a range iterator over a set of keys in a
	// given private collection. The iterator can be used to iterate over all keys
	// between the startKey (inclusive) and endKey (exclusive).
	// The keys are returned by the iterator in lexical order. Note
	// that startKey and endKey can be empty string, which implies unbounded range
	// query on start or end.
	// Call Close() on the returned StateQueryIteratorInterface object when done.
	// The query is re-executed during validation phase to ensure result set
	// has not changed since transaction endorsement (phantom reads detected).
	GetPrivateDataByRange(collection, startKey, endKey string) (StateQueryIteratorInterface, error)

	// GetPrivateDataByPartialCompositeKey queries the state in a given private
	// collection based on a given partial composite key. This function returns
	// an iterator which can be used to iterate over all composite keys whose prefix
	// matches the given partial composite key. The `objectType` and attributes are
	// expected to have only valid utf8 strings and should not contain
	// U+0000 (nil byte) and U+10FFFF (biggest and unallocated code point).
	// See related functions SplitCompositeKey and CreateCompositeKey.
	// Call Close() on the returned StateQueryIteratorInterface object when done.
	// The query is re-executed during validation phase to ensure result set
	// has not changed since transaction endorsement (phantom reads detected).
	GetPrivateDataByPartialCompositeKey(collection, objectType string, keys []string) (StateQueryIteratorInterface, error)

	// GetPrivateDataQueryResult performs a "rich" query against a given private
	// collection. It is only supported for state databases that support rich query,
	// e.g.CouchDB. The query string is in the native syntax
	// of the underlying state database. An iterator is returned
	// which can be used to iterate (next) over the query result set.
	// The query is NOT re-executed during validation phase, phantom reads are
	// not detected. That is, other committed transactions may have added,
	// updated, or removed keys that impact the result set, and this would not
	// be detected at validation/commit time.  Applications susceptible to this
	// should therefore not use GetQueryResult as part of transactions that update
	// ledger, and should limit use to read-only chaincode operations.
	GetPrivateDataQueryResult(collection, query string) (StateQueryIteratorInterface, error)

	// GetCreator returns `SignatureHeader.Creator` (e.g. an identity)
	// of the `SignedProposal`. This is the identity of the agent (or user)
	// submitting the transaction.
    // 查询 `SignedProposal`的`SignatureHeader.Creator`
	GetCreator() ([]byte, error)

	// GetTransient returns the `ChaincodeProposalPayload.Transient` field.
	// It is a map that contains data (e.g. cryptographic material)
	// that might be used to implement some form of application-level
	// confidentiality. The contents of this field, as prescribed by
	// `ChaincodeProposalPayload`, are supposed to always
	// be omitted from the transaction and excluded from the ledger.
	GetTransient() (map[string][]byte, error)

	// GetBinding returns the transaction binding, which is used to enforce a
	// link between application data (like those stored in the transient field
	// above) to the proposal itself. This is useful to avoid possible replay
	// attacks.
	GetBinding() ([]byte, error)

	// GetDecorations returns additional data (if applicable) about the proposal
	// that originated from the peer. This data is set by the decorators of the
	// peer, which append or mutate the chaincode input passed to the chaincode.
	GetDecorations() map[string][]byte

	// GetSignedProposal returns the SignedProposal object, which contains all
	// data elements part of a transaction proposal.
	GetSignedProposal() (*pb.SignedProposal, error)

	// GetTxTimestamp returns the timestamp when the transaction was created. This
	// is taken from the transaction ChannelHeader, therefore it will indicate the
	// client's timestamp and will have the same value across all endorsers.
	GetTxTimestamp() (*timestamp.Timestamp, error)

	// SetEvent allows the chaincode to set an event on the response to the
	// proposal to be included as part of a transaction. The event will be
	// available within the transaction in the committed block regardless of the
	// validity of the transaction.
	SetEvent(name string, payload []byte) error
}

// CommonIteratorInterface allows a chaincode to check whether any more result
// to be fetched from an iterator and close it when done.
type CommonIteratorInterface interface {
	// HasNext returns true if the range query iterator contains additional keys
	// and values.
	HasNext() bool

	// Close closes the iterator. This should be called when done
	// reading from the iterator to free up resources.
	Close() error
}

// StateQueryIteratorInterface allows a chaincode to iterate over a set of
// key/value pairs returned by range and execute query.
type StateQueryIteratorInterface interface {
	// Inherit HasNext() and Close()
	CommonIteratorInterface

	// Next returns the next key and value in the range and execute query iterator.
	Next() (*queryresult.KV, error)
}

// HistoryQueryIteratorInterface allows a chaincode to iterate over a set of
// key/value pairs returned by a history query.
type HistoryQueryIteratorInterface interface {
	// Inherit HasNext() and Close()
	CommonIteratorInterface

	// Next returns the next key and value in the history query iterator.
	Next() (*queryresult.KeyModification, error)
}

// MockQueryIteratorInterface allows a chaincode to iterate over a set of
// key/value pairs returned by range query.
// TODO: Once the execute query and history query are implemented in MockStub,
// we need to update this interface
type MockQueryIteratorInterface interface {
	StateQueryIteratorInterface
}

常用的接口API

  • GetArgs() [][]byte

    GetArgs 返回链码交易参数,返回类型是 [][]byte

  • GetStringArgs() []string

    GetStringArgs 获取链码交易的指定参数,返回类型是string数组

    {"Args":["set","tom","100"]}
    args = stub.GetStringArgs()
    fmt.Println(args)
    # 输出结果
    ["set","tom","100"]
    
  • GetFunctionAndParameters() (string, []string)

​ 获取调用链码交易中的参数,其中第一个参数作为被调用的函数名称,其余的参数作为函数的执行参数,是一个string数组

# {"Args":["set","tom","100"]}
fn, args := stub.GetFunctionAndParameters()
fmt.Println(fn, args)
# 输出结果
set ["tom", "100"]
  • GetArgsSlice() ([]byte, error)

    返回链码交易参数,返回类型是 byte数组

  • GetTxID() string

    获取当前交易的tx_id,每一笔交易和每一个客户端是唯一的

  • GetChannelID() string

    返回处理链码提议的通道channel

  • InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response

    调用另一个链码中的 Invoke 方法,也就是不同链码之间进行通信的方式
    InvokeChaincode 使用相同的交易上下文本地调用指定的链码Invoke。
    也就是说链码调用不创建一笔新的交易.
    (1) 如果被调用的链码在相同的channel中,可以简化为 被调用链码的读集和写集 追加到 调用链码的交易中
    (2) 如果是在不同的chanel中, 只有被调用链码的响应结果 追加到调用链码交易中。
    任何被调用链码的PutState不会写入到账本,也就是说不同通道的被调用链码不会产生交易读写集。
    只有调用链码的读写集才会写入到交易。
    实际上,不同channel的链码调用只是一个Query查询,不参加提交阶段的世界状态的验证。

    trans:=[][]byte{[]byte("invoke"),[]byte("a"),[]byte("b"),[]byte("11")}
    stub.InvokeChaincode("mycc",trans,"mychannel")
    
  • GetState(key string) ([]byte, error)

    GetState 负责查询账本,返回指定key的对应value值
    注意GetState不是从(writeset)写集 中读取数据,所以读取不到尚未提交的数据,
    也读取不到被PutState修改了但是尚未提交的数据
    如果key在账本中不存在,返回nil

    strValue , err := stub.GetState("str")
    if err != nil {
        fmt.Println("str GetState error: "+err.Error()) }else {
         fmt.Printf("str value: %s \n",string(strValue))
    }
    // # 输出结果
     str value: hello
    
  • PutState(key string, value []byte) error

    PutState设置一对指定的 keyvalue 到交易写集(writeset) 作为一个数据写提议。
    只有这笔交易被验证并且成功提交后才会写入到账本。
    简单的key值不能是空字符串,并且不能以null字符开头,
    如果使用CouchDB,keys的值只能包含有效的UTF-8字符串,并且不能以"_"开头
    在账本中添加或更新一对键值。key是string类型,value是byte数组

     err := stub.PutState("str",[]byte("hello"))
     if err != nil {
         fmt.Println("str PutState error: "+err.Error()) }
     else{
         fmt.Println("str PutState success!")
     }
    
  • DelState(key string) error

    DelState 交易提议的写集(writeset)中指定key的记录将会被删除。

    key和key对应的value将会从账本中被删除,当交易被验证通过并成功提交后。

    err = stub.DelState("str")
    
  • GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error)

    GetStateByRange 查询指定范围内的键值,startKey 为起始 key,endKey为终止 key

    遍历 startKey (包含) and endKey (不包含)之间的所有key;

    但是,如果startKey 和endKey之间keys的数量大于totalQueryLimit (defined in core.yaml),那么遍历器不能获取到所有的keys。

    keys的集合按照字典顺序返回;

    startKey and endKey可以是空字符串,就是不限定范围的查询。

    遍历结束后要调用StateQueryIteratorInterface 的Close() 方法

    err := stub.PutState("str",[]byte("hello"))
    err = stub.PutState("str1",[]byte("hello1"))
    err = stub.PutState("str2",[]byte("hello2"))
    //startKey=str  endKey=str2
    resultIterator , err := stub.GetStateByRange("str" , "str2")
    defer resultIterator.Close()
    fmt.Println("-----start resultIterator-----")
    for resultIterator.HasNext() {
    item, _ := resultIterator.Next()
    fmt.Println(string(item.Value)) }
    fmt.Println("-----end resultIterator-----")
    # 运行结果
    -----start resultIterator-----
    hello
    hello1
    -----end resultIterator-----
    
  • GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)

    返回某个key的历史记录
    对应key的每一次历史更新,相关的交易id和timestamp时间戳的历史记录value值都会返回
    timestamp 是客户端proposal header中的timestamp
    peer配置中 core.ledger.history.enableHistoryDatabase=true 才生效

    historyIterator,err := stub.GetHistoryForKey("str")
    defer historyIterator.Close()
    fmt.Println("-----start historyIterator-----")
    for resultIterator.HasNext() {
    item, _ := historyIterator.Next()
    fmt.Println(string(item.TxId))
    fmt.Println(string(item.Value))
    }
    fmt.Println("-----end historyIterator-----")
    
  • CreateCompositeKey(objectType string, attributes []string) (string, error)

    给定一组属性attributes,将这些属性组合起来构造一个复合键
    对象类型和熟悉值只能是有效的utf8字符串,并且不能包含 U+0000 (nil byte) and U+10FFFF

    indexName := "sex~name"
    indexKey , err :=
    stub.CreateCompositeKey(indexName,[]string{"boy","xiaowang"})
    value := []byte{0x00}
    stub.PutState(indexKey,value)
    fmt.Println(indexKey)
    indexKey , err =
    stub.CreateCompositeKey(indexName,[]string{"boy","xiaoli"})
    stub.PutState(indexKey,value)
    fmt.Println(indexKey) indexKey , err =
    stub.CreateCompositeKey(indexName,[]string{"girl","xiaofang"})
    fmt.Println(indexKey)
    stub.PutState(indexKey,value)
    # 运行结果
    sex~nameboyxiaowang
    sex~nameboyxiaoli
    sex~namegirlxiaofang
    
  • GetQueryResult(query string) (StateQueryIteratorInterface, error)

    GetQueryResult 是对世界状态数据库进行富查询,仅有 couchDB 支持
    查询语句采用 底层状态数据库的语法。返回的StateQueryIterator可用于遍历查询 结果集。

    resultIterator , err = stub.GetQueryResult("{\"selector\": {\"sex\":
    \"boy\"}}" )
    defer resultIterator.Close()
    fmt.Println("-----start resultIterator-----")
    for resultIterator.HasNext() {
    item, _ := resultIterator.Next()
    fmt.Println(string(item.Value))
    }
    fmt.Println("-----end resultIterator-----")
    
  • GetPrivateData(collection, key string) ([]byte, error)

    返回指定指定集合collection中的指定key的value值, 注意该方法 不会从 私有写集合private writeset 中读取数据,换句话说,GetPrivateData 方法不考虑 PutPrivateData方法修改过但还没有提交的数据。

  • GetPrivateDataHash(collection, key string) ([]byte, error)

    返回指定指定集合collection中的指定key的hash

  • PutPrivateData(collection string, key string, value []byte) error

    PutPrivateData 将指定的key和value对写入到交易私有写集(private writeset)
    注意只有 私有写集private writeset 的hash进入到交易提案的响应,
    事实上 私有写集private writeset临时存储了数据
    PutPrivateData不会写入到 collection中,直到交易被验证和成功提交。

  • DelPrivateData(collection, key string) error
    DelState 删除 交易私有写集private writeset 中指定key对应的记录

欢迎大家关注博主订阅号“Java技术日志”,提供Java相关技术分享,从Java编程基础到Java高级技术,从JavaWeb技术基础Jsp、Servlet、JDBC到SSH、SSM开发框架,从REST风格接口设计到分布式项目实战。区块链技术从入门到高级精通,剖析主流开源技术框架,用亲身实践来谱写深度Java技术日志。
​​Java技术日志

Java技术日志

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 下面是一个简单的 Hyperledger Fabric 2.0 Go语言链码示例: ``` package main import ( "fmt" "github.com/hyperledger/fabric-chaincode-go/shim" pb "github.com/hyperledger/fabric-protos-go/peer" ) // SimpleChaincode example simple Chaincode implementation type SimpleChaincode struct { } func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { fmt.Println("ex02 Init") _, args := stub.GetFunctionAndParameters() var A, B string // Entities var Aval, Bval int // Asset holdings var err error if len(args) != 4 { return shim.Error("Incorrect number of arguments. Expecting 4") } // Initialize the chaincode A = args[0] Aval, err = strconv.Atoi(args[1]) if err != nil { return shim.Error("Expecting integer value for asset holding") } B = args[2] Bval, err = strconv.Atoi(args[3]) if err != nil { return shim.Error("Expecting integer value for asset holding") } fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) // Write the state to the ledger err = stub.PutState(A, []byte(strconv.Itoa(Aval))) if err != nil { return shim.Error(err.Error()) } err = stub.PutState(B, []byte(strconv.Itoa(Bval))) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { fmt.Println("ex02 Invoke") function, args := stub.GetFunctionAndParameters() if function == "invoke" { // Make payment of X units from A to B return t.invoke(stub, args) } else if function == "delete" { // Deletes an entity from its state return t.delete(stub, args) } else if function == "query" { // the old "Query" is now implemtned in invoke return t.query(stub, args) } return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"") } // Transaction makes payment of X units from A to B func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response { var A, B string // Entities var Aval, Bval int // Asset holdings var X int // Transaction value var err error ### 回答2: Hyperledger Fabric 是一个开源的区块链平台,可以用于构建企业级的去中心化应用程序。而 Hyperledger Fabric 2.0 是其最新版本,引入了许多新特性和改进。 编写一个 Hyperledger Fabric 2.0 的 Go 语言链码需要按照一定的流程进行: 1. 准备开发环境:首先,需要安装 Go 语言的开发环境和 Hyperledger Fabric 的相关工具,如 Hyperledger Fabric SDK 和 Hyperledger Fabric CA。 2. 编写链码逻辑:使用 Go 语言编写链码的逻辑,链码是在 Hyperledger Fabric 上运行的智能合约。可以根据项目需求和业务逻辑定义相关的数据结构和函数。 3. 定义链码接口:需要定义链码接口,包括 Init 和 Invoke 两个核心函数。Init 函数用于链码的初始化操作,而 Invoke 函数用于链码的业务逻辑执行。 4. 部署链码:将编写好的链码部署到 Hyperledger Fabric 网络中。可以使用 Hyperledger Fabric SDK 提供的工具和 API 来进行链码的部署操作。 5. 测试链码:编写相应的测试用例,对链码逻辑进行测试。可以使用模拟的 Fabric 网络进行测试,或者与实际的 Fabric 网络交互进行测试。 6. 部署链码应用程序:将编写好的链码应用程序部署到 Hyperledger Fabric 网络上。可以使用 Hyperledger Fabric SDK 提供的工具和 API 来进行链码应用程序的部署操作。 Go 语言是一种高性能的编程语言,适合于开发区块链平台和链码。编写 Hyperledger Fabric 2.0 的 Go 语言链码需要熟悉 Go 语言的基本语法和特性,以及了解 Hyperledger Fabric 的相关知识。通过合理的设计和编码,可以实现各种复杂的业务逻辑和功能。 ### 回答3: 编写一个Hyperledger Fabric 2.0的Go语言链码可以分为以下几个步骤: 1. 准备开发环境:首先,需要在开发机器上安装Go语言Hyperledger Fabric的相关依赖。可以通过配置Golang环境变量,并使用Golang包管理器安装Fabric的Go SDK。 2. 创建链码项目:使用Go语言的IDE或文本编辑器创建一个新的文件夹,作为链码项目的根目录。 3. 定义链码结构:创建一个新的Go文件,并定义链码结构。链码结构应该实现fabric的Chaincode接口,并实现Init和Invoke两个方法。 4. 实现Init方法:Init方法在链码被实例化时调用,并进行初始化设置。可以在该方法中初始化链码的状态数据和其他必要的准备工作。 5. 实现Invoke方法:Invoke方法在链码接收到调用请求时被调用。在该方法中处理具体的业务逻辑,并根据请求中的操作类型执行相应的操作。 6. 将链码打包:使用Fabric提供的命令行工具将链码打包成压缩文件,以便于后续部署和安装。 7. 部署和安装链码:使用Fabric提供的链码生命周期管理工具,将链码部署到指定的Fabric网络中,并安装到指定的通道上。 8. 实例化链码:在指定的通道上实例化链码,使其可以被其他参与方调用。 9. 调用链码:使用Fabric提供的客户端SDK或命令行工具,向链码发送调用请求,验证链码的功能和逻辑是否正确。 10. 测试链码:编写一些测试用例,用于对链码的功能和性能进行验证。 以上是一个简要的步骤,编写Hyperledger Fabric 2.0的Go语言链码还需要进一步了解链码开发的相关知识和FabricAPI,以有效地实现业务逻辑,并与Fabric网络进行交互。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值