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
}
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设置一对指定的 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!")
}
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技术日志