func (t *SimpleChaincode) push(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// must be an invoke
var A string // Entities
var Avalue string // Transaction value
var err error
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 4, function followed by 1 names and 1 value")
}
A = args[0]
Avalue = args[1]
// Write the state back to the ledger
err = stub.PutState(A, []byte(Avalue))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil);
}
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
A := args[0]
// Delete the key from the state in ledger
err := stub.DelState(A)
if err != nil {
return shim.Error("Failed to delete state")
}
return shim.Success(nil)
}
3. 查询数据
GetState(key string) ([]byte, error)
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var A string // Entities
var err error
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
}
A = args[0]
// Get the state from the ledger
Avalbytes, err := stub.GetState(A)
if err != nil {
jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
return shim.Error(jsonResp)
}
jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
logger.Infof("Query Response:%s\n", jsonResp)
return shim.Success(Avalbytes)
}
4. 生成复合键
CreateCompositeKey(objectType string, attributes []string) (string, error)
func (t *SimpleChaincode) pushComposite(stub shim.ChaincodeStubInterface, args []string) pb.Response {
// must be an invoke
var A string // Entities
var Avalue string // Transaction value
var err error
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 4, function followed by 1 names and 1 value")
}
A = args[0]
Avalue = args[1]
ck, cerr := stub.CreateCompositeKey("CompositeKey", []string{"compositeKey", A})
if cerr != nil {
return shim.Error(cerr.Error())
}
// Write the state back to the ledger
err = stub.PutState(ck, []byte(Avalue))
if err != nil {
return shim.Error(err.Error())
}
return shim.Success(nil);
}
5. 拆分复合键
SplitCompositeKey(compositeKey string) (string, []string, error)
6. 部分复合键查询
GetStateByPartialCompositeKey(objectType string, keys []string) (StateQueryIteratorInterface, error)
func (t *SimpleChaincode) queryCompositeall(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var buffer bytes.Buffer
resultsIterator, err := stub.GetStateByPartialCompositeKey("CompositeKey", []string{"compositeKey"})
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()
for i := 0; resultsIterator.HasNext(); i++ {
responseRange, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
_, compositeKeyParts, err := stub.SplitCompositeKey(responseRange.Key)
if err != nil {
return shim.Error(err.Error())
}
returnedA := compositeKeyParts[1]
buffer.WriteString(returnedA)
buffer.Write([]byte(":"))
buffer.Write(responseRange.Value)
buffer.Write([]byte(","))
}
Avalbytes :=buffer.Bytes()
return shim.Success(Avalbytes)
}
7. Key区间查询
GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error)
查询结果不包含endKey 。
func (t *SimpleChaincode) queryRang(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var starkey string}
8. 富查询
GetQueryResult(query string) (StateQueryIteratorInterface, error)
是对Value的内容进行查询,如果是LevelDB,那么是不支持,只有CouchDB时才能用这个方法。
关于传入的query这个字符串,其实是CouchDB所使用的Mango查询,
我们可以在官方博客了解到一些信息:https://blog.couchdb.org/2016/08/03/feature-mango-query/
其基本语法可以在https://github.com/cloudant/mango 这里看到。
func (t *SimpleChaincode) queryResult(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var value string
var buffer bytes.Buffervalue = args[0]
//data[key, value]: ["*","{\"ID\":\"*\", \"Name\":\"*\"}"]
queryString := fmt.Sprintf("{\"selector\":{\"Name\":\"%s\"}}", value)}
9. 历史数据查询
GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)
func (t *SimpleChaincode) queryHistory(stub shim.ChaincodeStubInterface, args []string) pb.Response {--------------------------------------------------------------------------------------------------------------
type ChaincodeStubInterface interface {
// GetArgs returns the arguments intended for the chaincode Init and Invoke
// as an array of byte arrays.
GetArgs() [][]byte
// GetStringArgs returns the arguments intended for the chaincode Init and
// Invoke as a string array. Only use GetStringArgs if the client passes
// arguments intended to be used as strings.
GetStringArgs() []string
// GetFunctionAndParameters returns the first argument as the function
// name and the rest of the arguments as parameters in a string array.
// Only use GetFunctionAndParameters if the client passes arguments intended
// to be used as strings.
GetFunctionAndParameters() (string, []string)
// GetArgsSlice returns the arguments intended for the chaincode Init and
// Invoke as a byte array
GetArgsSlice() ([]byte, error)
// GetTxID returns the tx_id of the transaction proposal, which is unique per
// transaction and per client. See ChannelHeader in protos/common/common.proto
// for further details.
GetTxID() string
// GetChannelID returns the channel the proposal is sent to for chaincode to process.
// This would be the channel_id of the transaction proposal (see ChannelHeader
// in protos/common/common.proto) except where the chaincode is calling another on
// a different 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.
InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response
// GetState returns the value of the specified `key` from the
// ledger. Note that GetState doesn't read data from the writeset, which
// has not been committed to the ledger. In other words, GetState doesn't
// consider data modified by PutState that has not been committed.
// If the key does not exist in the state database, (nil, nil) is returned.
GetState(key string) ([]byte, error)
// PutState puts the specified `key` and `value` into the transaction's
// writeset as a data-write proposal. PutState doesn't effect the ledger
// until the transaction is validated and successfully committed.
// Simple keys must not be an empty string and must not start with null
// character (0x00), in order to avoid range query collisions with
// composite keys, which internally get prefixed with 0x00 as composite
// key namespace.
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(key string) 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).
// 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, endKey string) (StateQueryIteratorInterface, 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. 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)
// 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().
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 (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.
GetQueryResult(query string) (StateQueryIteratorInterface, 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.
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.
GetPrivateData(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 null character (0x00), in order to
// avoid range query collisions with composite keys, which internally get
// prefixed with 0x00 as composite key namespace.
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.
DelPrivateData(collection, key string) 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.
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
}