Documentation ¶
Overview ¶
Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0
Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0
Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0
Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0
Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0
Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0
Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0
Index ¶
- Constants
- Variables
- func AdminExists(adminID string, adminSet []*types.Admin) (bool, int)
- func CalculateValueHash(dbName, key string, value []byte) ([]byte, error)
- func NodeExists(nodeID string, nodeSet []*types.NodeConfig) (bool, int)
- func PeerExists(nodeID string, peerSet []*types.PeerConfig) (bool, int)
- type BCDB
- type BlockHeaderDelivererService
- type BlockHeaderDeliveryConfig
- type ConfigTxContext
- type DBSession
- type DBsTxContext
- type DataTxContext
- type ErrorNotFound
- type ErrorTxValidation
- type HttpClient
- type Iterator
- type Ledger
- type LedgerPath
- type LoadedDataTxContext
- type ProofVerificationError
- type Provenance
- type Query
- type QueryExecutor
- func (t QueryExecutor) CommittedTxEnvelope() (proto.Message, error)
- func (q *QueryExecutor) ExecuteJSONQuery(dbName, query string) ([]*types.KVWithMetadata, error)
- func (q *QueryExecutor) GetDataByRange(dbName, startKey, endKey string, limit uint64) (Iterator, error)
- func (t QueryExecutor) TxID() string
- type RangeQueryIterator
- type RangeQueryResponse
- type ResponseEnvelop
- type ResponseWithHeader
- type RestClient
- type ServerTimeout
- type SignatureVerifier
- type Signer
- type TxContext
- type TxContextOption
- type TxProof
- type UsersTxContext
Constants ¶
const GenesisBlockNumber = 1
Variables ¶
var ErrTxNotFinalized = errors.New("can't access tx envelope, transaction not finalized")
var ErrTxSpent = errors.New("transaction committed or aborted")
Functions ¶
func CalculateValueHash ¶
CalculateValueHash creates unique hash for specific value, by hashing concatenation of database name, key and value hashes
func NodeExists ¶
func NodeExists(nodeID string, nodeSet []*types.NodeConfig) (bool, int)
func PeerExists ¶
func PeerExists(nodeID string, peerSet []*types.PeerConfig) (bool, int)
Types ¶
type BCDB ¶
type BCDB interface { // Session instantiates session to the database Session(config *config.SessionConfig) (DBSession, error) }
BCDB Blockchain Database interface, defines set of APIs required to operate with BCDB instance
type BlockHeaderDelivererService ¶
type BlockHeaderDelivererService interface { // Receive returns // - *types.BlockHeader if IncludeTxIDs is set to false in the delivery config // - *types.AugmentedBlockHeader if IncludeTxIDs is set to true in the delivery config // - nil if service has been stopped either by the caller or due to an error Receive() interface{} // Stop stops the delivery service Stop() // Error returns any accumulated error Error() error }
BlockHeaderDelivererService deliverys block header to the caller
type BlockHeaderDeliveryConfig ¶
type BlockHeaderDeliveryConfig struct { // StartBlockNumber informs the service to start deliverying // block from this given block number StartBlockNumber uint64 // RetryInterval denotes how long to wait before the retrying // the lastt failed retrieval of the block headerr RetryInterval time.Duration // Capacity denotes the maximum numberr of block headers to be // kept in the buffer Capacity int // IncludeTxIDs denotes whether the block header should include // transactions' ID or not IncludeTxIDs bool }
BlockHeaderDeliveryConfig holds the configuration of the delivery service
type ConfigTxContext ¶
type ConfigTxContext interface { // TxContext embeds the general abstraction. TxContext // AddAdmin add admin record. // The operation is applied to the pending config. // If the pending config is not set yet, it will be cloned from the current config. AddAdmin(admin *types.Admin) error // DeleteAdmin delete admin record. // The operation is applied to the pending config. // If the pending config is not set yet, it will be cloned from the current config. DeleteAdmin(adminID string) error // UpdateAdmin update admin record. // The operation is applied to the pending config. // If the pending config is not set yet, it will be cloned from the current config. UpdateAdmin(admin *types.Admin) error // UpdateCAConfig update the CAConfig record. // The operation is applied to the pending config. // If the pending config is not set yet, it will be cloned from the current config. UpdateCAConfig(caConfig *types.CAConfig) error // AddClusterNode add cluster node record. // The operation is applied to the pending config. // If the pending config is not set yet, it will be cloned from the current config. AddClusterNode(node *types.NodeConfig, peer *types.PeerConfig) error // DeleteClusterNode delete cluster node record. // The operation is applied to the pending config. // If the pending config is not set yet, it will be cloned from the current config. DeleteClusterNode(nodeID string) error // UpdateClusterNode Update cluster node record. // The operation is applied to the pending config. // If the pending config is not set yet, it will be cloned from the current config. UpdateClusterNode(node *types.NodeConfig, peer *types.PeerConfig) error // UpdateRaftConfig Update the raft configuration parameters. // The operation is applied to the pending config. // If the pending config is not set yet, it will be cloned from the current config. UpdateRaftConfig(raftConfig *types.RaftConfig) error // GetClusterConfig returns the current cluster config. // A ConfigTxContext only gets the current config once, subsequent calls return a cached value. // The value returned is a deep clone of the cached value and can be manipulated. GetClusterConfig() (*types.ClusterConfig, error) // SetClusterConfig sets a new cluster config object that was possibly manipulated as the pending config // object. The object is deep-cloned, so further manipulation to the input will not be reflected on the pending // config. Setting a new config is only possible if there isn't any pending config. Using any of the write methods after a // pending config was set is permitted. Those methods are applied to the pending config (e.g. AddAdmin() will add // an admin, etc.). SetClusterConfig(newConfig *types.ClusterConfig) error }
ConfigTxContext transaction context to operate with configuration management related transactions.
When a ConfigTxContext is created, it gets the current cluster config once. To update the cluster's config it is possible to get that config (using GetClusterConfig), manipulate it, set it as the pending config (using SetClusterConfig), and commit.
It is also possible to manipulate directly certain elements of the config: - Add, delete and update an admin record; - Manipulate the CA configuration; - Add, delete and update a cluster node & peer config. These methods operate on the pending config. If a pending config object does not exist yet, a clone of the current config becomes the pending config.
Reading and updating the cluster's config is only possible from a session of an admin user.
type DBSession ¶
type DBSession interface { UsersTx() (UsersTxContext, error) DataTx(options ...TxContextOption) (DataTxContext, error) LoadDataTx(*types.DataTxEnvelope) (LoadedDataTxContext, error) DBsTx() (DBsTxContext, error) ConfigTx() (ConfigTxContext, error) Provenance() (Provenance, error) Ledger() (Ledger, error) Query() (Query, error) // ReplicaSet returns the set of replicas the session is currently using. If `refresh` is `true`, the session will // also query the cluster for the most recent replica set before returning. // Note that when a DBSession is first created, it queries the cluster for the most recent replica set. ReplicaSet(refresh bool) ([]*config.Replica, error) }
DBSession captures user's session
type DBsTxContext ¶
type DBsTxContext interface { TxContext // CreateDB creates new database along with index definition for the query. // The index is a map of attributes/fields in json document, i.e., value associated // with the key, to its value type. For example, map["name"]types.IndexAttributeType_STRING // denotes that "name" attribute in all json documents to be stored in the given // database to be indexed for queries. Note that only indexed attributes can be // used as predicates in the query string. Currently, we support the following three // value types: STRING, BOOLEAN, and INT64 CreateDB(dbName string, index map[string]types.IndexAttributeType) error // DeleteDB deletes database DeleteDB(dbName string) error // Exists checks whenever database is already created Exists(dbName string) (bool, error) // GetDBIndex returns the index definition associated with the given database. // The index definition is of form map["name"]types.IndexAttributeType where // name denotes the field name in the JSON document and types.IndexAttributeType // denotes one of the three value types: STRING, BOOLEAN, and INT64. When a database // does not have an index definition, GetDBIndex would return a nil map GetDBIndex(dbName string) (map[string]types.IndexAttributeType, error) }
DBsTxContext abstraction for database management transaction context
type DataTxContext ¶
type DataTxContext interface { // Embed general abstraction TxContext // Put new value to key Put(dbName string, key string, value []byte, acl *types.AccessControl) error // Get existing key value Get(dbName, key string) ([]byte, *types.Metadata, error) // Delete value for key Delete(dbName, key string) error // AssertRead insert a key-version to the transaction assert map AssertRead(dbName string, key string, version *types.Version) error // AddMustSignUser adds userID to the multi-sign data transaction's // MustSignUserIDs set. All users in the MustSignUserIDs set must co-sign // the transaction for it to be valid. Note that, in addition, when a // transaction modifies keys which have multiple users in the write ACL, // or when a transaction modifies keys where each key has different user // in the write ACL, the signature of additional users may be required. // AddMustSignUser can be used to add users whose signatures is required, // on top of those mandates by the ACLs of the keys in the write-set of // the transaction. The userID of the initiating client is always in // the MustSignUserIDs set." AddMustSignUser(userID string) // SignConstructedTxEnvelopeAndCloseTx returns a signed transaction envelope and // also closes the transaction context. When a transaction requires // signatures from multiple users, an initiating user prepares the // transaction and calls SignConstructedTxEnvelopeAndCloseTx in order to // sign it and construct the envelope. The envelope must then be // circulated among all the users that need to co-sign it." SignConstructedTxEnvelopeAndCloseTx() (proto.Message, error) }
type ErrorNotFound ¶
type ErrorNotFound struct {
Message string
}
func (*ErrorNotFound) Error ¶
func (e *ErrorNotFound) Error() string
type ErrorTxValidation ¶
func (*ErrorTxValidation) Error ¶
func (e *ErrorTxValidation) Error() string
type Iterator ¶
type Iterator interface { // Next returns the next record. If there is no more records, it would return a nil value // and a false value. Next() (*types.KVWithMetadata, bool, error) }
Iterator implements methods to iterate over a set records
type Ledger ¶
type Ledger interface { // GetBlockHeader returns block header from ledger GetBlockHeader(blockNum uint64) (*types.BlockHeader, error) // GetLastBlockHeader returns last block from ledger GetLastBlockHeader() (*types.BlockHeader, error) // GetLedgerPath returns cryptographically verifiable path between any block pairs in ledger skip list GetLedgerPath(startBlock, endBlock uint64) (*LedgerPath, error) // GetTransactionProof returns intermediate hashes from hash(tx, validating info) to root of // tx merkle tree stored in block header GetTransactionProof(blockNum uint64, txIndex int) (*TxProof, error) // GetTransactionReceipt return block header where tx is stored and tx index inside block GetTransactionReceipt(txId string) (*types.TxReceipt, error) // GetDataProof returns proof of existence of value associated with key in block Merkle-Patricia Trie // Proof itself is a path from node that contains value to root node in MPTrie GetDataProof(blockNum uint64, dbName, key string, isDeleted bool) (*state.Proof, error) // GetFullTxProofAndVerify do full tx existence and validity proof by fetching and validating two ledger skip list paths and one Merkle tree path. // First, it fetches the Merkle tree path within the block with the transaction. // Next, the ledger path from the block with the transaction to the genesis block is fetched. // Then, the ledger path from the last know (a-priori) block to the block with the transaction is fetched. // Finally, these three proofs are validated. // Returns // TxProof - the Merkle tree path within the block with the transaction. // LedgerPath - two concatenated ledger paths [last... block... genesis] // error - in case if verification failed, nil otherwise GetFullTxProofAndVerify(txReceipt *types.TxReceipt, lastKnownBlockHeader *types.BlockHeader, tx proto.Message) (*TxProof, *LedgerPath, error) // NewBlockHeaderDeliveryService creates a delivery service to deliver block header // from a given starting block number present in the config to all the future block // till the service is stopped NewBlockHeaderDeliveryService(conf *BlockHeaderDeliveryConfig) BlockHeaderDelivererService // GetTxContent returns the transaction envelope associated with the block number and transaction index, along // with the validation info and version. Only users that had signed the transaction correctly can get the // transaction content. GetTxContent(blockNum, txIndex uint64) (*types.GetTxResponse, error) }
type LedgerPath ¶
type LedgerPath struct { // Path keeps all block headers in ledger path. // Keep in mind that the skip list in the ledger is organized and validated backwards, from end of chain to genesis block, // so Path is sorted from higher block numbers to lower, for example the path from block 8 to block 1 is (8, 7, 5, 1). Path []*types.BlockHeader }
LedgerPath contains a skip list path in ledger, in form of block headers. It is used to make ledger path validation easier.
func (*LedgerPath) Verify ¶
func (lp *LedgerPath) Verify(begin, end *types.BlockHeader) (bool, error)
Verify ledger path correctness. begin is lower block number and end is higher, opposite to how path is actually sorted. This order makes it easier to the caller. Please, keep in mind that Path of one single block is correct by definition
type LoadedDataTxContext ¶
type LoadedDataTxContext interface { // Embed general abstraction TxContext // MustSignUsers returns all the users in the MustSignUsers set of the // loaded multi-sign data tx. All those users must sign the transaction // for it to be valid. Note that, in addition, the signature of some // additional users may be needed, depending on the write ACLs of the // keys in the write-set." MustSignUsers() []string // SignedUsers returns all users who have signed the transaction envelope SignedUsers() []string // VerifySignatures verifies the existing signature on the loaded data transactions VerifySignatures() error // Reads return all read operations performed by the load data transaction on // different databases Reads() map[string][]*types.DataRead // Writes return all write operations performed by the load data transaction on // different databases Writes() map[string][]*types.DataWrite // Deletes return all delete operations performed by the load data transaction on // different databases Deletes() map[string][]*types.DataDelete // CoSignTxEnvelopeAndCloseTx adds the signature of the transaction's user to // the envelope, closes the transaction, and return the co-signed // transaction envelope CoSignTxEnvelopeAndCloseTx() (proto.Message, error) }
LoadedDataTxContext provides methods to realize multi-sign transaction. When a user receives a pre-compiled transaction envelope, the loaded transaction context can be used to load the pre-compiled envelope, inspect the operations performed by the transaction, and either co-sign the transaction to get the transaction envelope (maybe to pass it on to other users) or issue commit (which would internally co-sign the transaction).
type ProofVerificationError ¶
type ProofVerificationError struct {
// contains filtered or unexported fields
}
func (*ProofVerificationError) Error ¶
func (e *ProofVerificationError) Error() string
type Provenance ¶
type Provenance interface { // GetHistoricalData return all historical values for specific dn and key // Value returned with its associated metadata, including block number, tx index, etc GetHistoricalData(dbName, key string) ([]*types.ValueWithMetadata, error) // GetHistoricalDataAt returns value for specific version, if exist GetHistoricalDataAt(dbName, key string, version *types.Version) (*types.ValueWithMetadata, error) // GetPreviousHistoricalData returns value precedes given version, including its metadata, i.e version GetPreviousHistoricalData(dbName, key string, version *types.Version) ([]*types.ValueWithMetadata, error) // GetNextHistoricalData returns value succeeds given version, including its metadata GetNextHistoricalData(dbName, key string, version *types.Version) ([]*types.ValueWithMetadata, error) // GetDataReadByUser returns all user reads grouped by databases GetDataReadByUser(userID string) (map[string]*types.KVsWithMetadata, error) // GetDataWrittenByUser returns all user writes grouped by databases GetDataWrittenByUser(userID string) (map[string]*types.KVsWithMetadata, error) // GetReaders returns all users who read value associated with the key GetReaders(dbName, key string) ([]string, error) // GetWriters returns all users who wrote value associated with the key GetWriters(dbName, key string) ([]string, error) // GetTxIDsSubmittedByUser IDs of all tx submitted by user GetTxIDsSubmittedByUser(userID string) ([]string, error) }
type Query ¶
type Query interface { // ExecuteJSONQuery executes a given JSON query on a given database. // The JSON query is a json string which must contain predicates under the field // selector. The first field in the selector can be a combinational operator // such as "$and" or "$or" followed by a list of attributes and a list of // conditions per attributes. A query example is shown below // // { // "selector": { // "$and": { -- top level combinational operator // "attr1": { -- a field in the json document // "$gte": "a", -- value criteria for the field // "$lt": "b" -- value criteria for the field // }, // "attr2": { -- a field in the json document // "$eq": true -- value criteria for the field // }, // "attr3": { -- a field in the json document // "$lt": "a2" -- a field in the json document // } // } // } // } ExecuteJSONQuery(dbName, query string) ([]*types.KVWithMetadata, error) // GetDataByRange executes a range query on a given database. The startKey is // inclusive but endKey is not. When the startKey is an empty string, it denotes // `fetch keys from the beginning` while an empty endKey denotes `fetch keys till the // the end`. The limit denotes the number of records to be fetched in total. However, // when the limit is set to 0, it denotes no limit. The iterator returned by // GetDataByRange is used to retrieve the records. GetDataByRange(dbName, startKey, endKey string, limit uint64) (Iterator, error) }
Query provides method to execute json query and range query on a given database.
type QueryExecutor ¶
type QueryExecutor struct {
// contains filtered or unexported fields
}
func (QueryExecutor) CommittedTxEnvelope ¶
func (*QueryExecutor) ExecuteJSONQuery ¶
func (q *QueryExecutor) ExecuteJSONQuery(dbName, query string) ([]*types.KVWithMetadata, error)
func (*QueryExecutor) GetDataByRange ¶
func (q *QueryExecutor) GetDataByRange(dbName, startKey, endKey string, limit uint64) (Iterator, error)
type RangeQueryIterator ¶
type RangeQueryIterator struct {
// contains filtered or unexported fields
}
func (*RangeQueryIterator) Next ¶
func (i *RangeQueryIterator) Next() (*types.KVWithMetadata, bool, error)
type RangeQueryResponse ¶
type RangeQueryResponse struct { KVs []*types.KVWithMetadata PendingResults bool NextStartKey string }
type ResponseEnvelop ¶
type ResponseEnvelop interface {
GetSignature() []byte
}
type ResponseWithHeader ¶
type ResponseWithHeader interface {
GetHeader() *types.ResponseHeader
}
func ResponseSelector ¶
func ResponseSelector(envelop ResponseEnvelop) (ResponseWithHeader, error)
type RestClient ¶
type RestClient interface { // Query sends REST request with query semantics. // SDK will wait for `queryTimeout` for response from server and return error if no response received. // If commitTimeout set to 0, sdk will wait for http commitTimeout. Query(ctx context.Context, endpoint, httpMethod string, postData, signature []byte) (*http.Response, error) // Submit send REST request with transaction submission semantics and optional commitTimeout. // If commitTimeout set to 0, server will return immediately, without waiting for transaction processing // pipeline to complete and response will not contain transaction receipt, otherwise, server will wait // up to commitTimeout for transaction processing to complete and will return tx receipt as result. // In case of commitTimeout, http.StatusAccepted returned. Submit(ctx context.Context, endpoint string, msg proto.Message, serverTimeout time.Duration) (*http.Response, error) }
RestClient encapsulates http client with user identity signing capabilities to generalize ability to send requests to BCDB server
func NewRestClient ¶
func NewRestClient(userID string, httpClient HttpClient, signer Signer) RestClient
type ServerTimeout ¶
type ServerTimeout struct {
TxID string
}
func (*ServerTimeout) Error ¶
func (e *ServerTimeout) Error() string
type SignatureVerifier ¶
type SignatureVerifier interface { // Verify signature created by entityID for given payload Verify(entityID string, payload, signature []byte) error }
SignatureVerifier verifies servers' signatures provided within response
func NewVerifier ¶
func NewVerifier(certs map[string]*x509.Certificate, logger *logger.SugarLogger) (SignatureVerifier, error)
NewVerifier creates instance of the SignatureVerifier
type TxContext ¶
type TxContext interface { // Commit submits transaction to the server, can be sync or async. // Sync option returns tx id and tx receipt envelope and // in case of error, commitTimeout error is one of possible errors to return. // Async returns tx id, always nil as tx receipt or error Commit(sync bool) (string, *types.TxReceiptResponseEnvelope, error) // Abort cancel submission and abandon all changes // within given transaction context Abort() error // CommittedTxEnvelope returns transaction envelope, can be called only after Commit(), otherwise will return nil CommittedTxEnvelope() (proto.Message, error) // TxID gives the transaction id TxID() string }
TxContext is an abstract API to capture general purpose functionality for all types of transactions context.
type TxContextOption ¶
type TxContextOption func(svc *commonTxContext) error
TxContextOption is a function that operates on a commonTxContext and applies a configuration option.
func WithTxID ¶
func WithTxID(txID string) TxContextOption
WithTxID provides an external transaction ID (txID) to the transaction context. The given txID must be unique in the database cluster to which it is submitted. The given txID must be safe to use as a URL segment (see segment-nz at: https://www.ietf.org/rfc/rfc3986.txt).
Note that the database may reveal the transaction IDs it executed to other clients. Therefore, it is recommended not to include any sensitive information in it. It is recommended to generate the txID by hashing some identifier that includes enough entropy such that it reveals no information, e.g. `Hash(ID + Nonce)`, and convert the bytes to a URL-safe string representation.
type TxProof ¶
type TxProof struct { // IntermediateHashes are hashes between leaf (transaction) hash and tree root // for simplicity, both tx hash and tree root is part of IntermediateHashes IntermediateHashes [][]byte }
TxProof keeps Merkle tree proof for specific transaction
func (*TxProof) Verify ¶
Verify the validity of the proof with respect to the Tx and TxReceipt. receipt stores the block header and the tx-index in that block. The block header contains the Merkle tree root and the tx validation info. The validation info is indexed by the tx-index. tx stores the transaction envelope content.
type UsersTxContext ¶
type UsersTxContext interface { // Embed general abstraction TxContext // PutUser introduce new user into database PutUser(user *types.User, acl *types.AccessControl) error // GetUser obtain user's record from database GetUser(userID string) (*types.User, *types.Metadata, error) // RemoveUser delete existing user from the database RemoveUser(userID string) error }
UsersTxContext transaction context to operate with user management related transactions: 1. Add user's record 2. Get user's record 3. Delete user's record 4. Alternate user's ACLs