bcdb

package
v0.2.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 28, 2023 License: Apache-2.0 Imports: 33 Imported by: 11

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

View Source
const GenesisBlockNumber = 1

Variables

View Source
var ErrTxNotFinalized = errors.New("can't access tx envelope, transaction not finalized")
View Source
var ErrTxSpent = errors.New("transaction committed or aborted")

Functions

func AdminExists

func AdminExists(adminID string, adminSet []*types.Admin) (bool, int)

func CalculateValueHash

func CalculateValueHash(dbName, key string, value []byte) ([]byte, error)

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

func Create

func Create(connectionConfig *config.ConnectionConfig) (BCDB, error)

Create prepares connection context to work with BCDB instance loads root CA certificates

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

type ErrorTxValidation struct {
	TxID   string
	Flag   string
	Reason string
}

func (*ErrorTxValidation) Error

func (e *ErrorTxValidation) Error() string

type HttpClient

type HttpClient interface {
	Do(req *http.Request) (*http.Response, error)
}

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 (t QueryExecutor) CommittedTxEnvelope() (proto.Message, error)

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)

func (QueryExecutor) TxID added in v0.2.7

func (t QueryExecutor) TxID() string

type RangeQueryIterator

type RangeQueryIterator struct {
	// contains filtered or unexported fields
}

func (*RangeQueryIterator) Next

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 Signer

type Signer interface {
	crypto.Signer
}

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

func (p *TxProof) Verify(receipt *types.TxReceipt, tx proto.Message) (bool, error)

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

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL