Skip to content

Provenance

Gennady Laventman edited this page Sep 7, 2020 · 11 revisions

Provenance and Transactions Proofs

Provenance API give user access to

  • key->value history
  • raw transaction data
  • block header data
  • transaction existence in block proof
  • block(s) existence in ledger proof
// Provenance access to historical data and data integrity proofs
type Provenance interface {
	// GetTxProof returns proof that tx with give id is part of blocks merkle tree (path to root)
	GetTxProof(txId []byte) (*types.TxProof, error)
	// GetBlocksProof returns proof that each block in list of blocks connected to another
	// by providing shortest path in skip list between blocks in list
	GetBlocksProof(blocks []uint64) (*types.BlockProof, error)
	// GetHistory return full history for given key in db
	GetHistory(dbName, key string) (HistoryIterator, error)
	// GetTransaction returns transaction envelope by its id
	GetTransaction(txId []byte) (*types.TransactionEnvelope, error)
	// GetBlockHeader returns block header
	GetBlockHeader(number uint64) (*types.BlockHeader, error)
	// GetLstBlockHeader returns block header of last known block in ledger
	GetLastBlockHeader() (*types.BlockHeader, error)
}

type HistoryIterator interface {
	Next() (*api.HistoricalData, error)
	Close()
}

One extra API, to be discussed

// GetSparseBlock returns sparse block, contains only tx visible be user 
// and Merkle tree paths for these tx
GetSparseBlock(number uint64) (*types.SparseBlock, error)

Based on this API, we can check

  • ledger integrity by accessing block headers and validating consistency of ledger merkle list
  • with GetSparseBlock() , even with partial data it returns, we can check past and current database state consistency
  • transaction existence proof composed of merkle tree path to transaction in block and block existence proof: GetTxProof() and GetBlocksProof()
  • block existence proof algorithm described in Transaction-Proofs-Skiplist, proof data accessed using GetBlockProof() API
  • proof of active and past states can be done by proving existence of all transactions that caused state changes
    • retrieve key->value history by using GetHistory() API and provide proofs for all transaction references returned
      • referenced blocks existence proof in this case can be done by single call to GetBlockProof() with (genesis, history referenced blocks, last block) argument
message TxProof {
  BlockHeader header = 1;
  repeated bytes path = 2;
}

message BlockProof {
  uint64 block_number = 1;
  repeated BlockHeader path = 2;
}

GetHistory API provides all values of specific keys over time, including references to transactions that change this key. It is possible form this data, using GetTxProof, GetBlockProof and GetTransactions API, to provide proof of change of specific key at specific time.

As we can see here, the API is Blockchain DB installation level API, not single DB level API and it exposed by DBConnector, but this need to be discussed.

// DBConnector handle connectivity between sdk and Blockchain Database cluster
type DBConnector interface {
	...
	// GetProvenance returns blockchain db provenance interface
	GetProvenance() Provenance
}

If not mentioned otherwise, this document describes skip list based proofs for ledger consistency and integrity. For more detailed explanation, see Transaction-Proofs-Skiplist

As mentioned in Transaction document, during provenance data creation phase, {Key, newValue, BlockTime, BlockNumber, TxTime, TxId, ClientId, IsDelete, IsOk} tuple stored as provenance data for each key in WSet.

GetHistory returns slice of history values based on data stored in provenance tuple

message HistoricalValue {
  // DB key
  string key = 1;
  // Historical value
  bytes value = 2;
  // Sequencer time when block was created
  google.protobuf.Timestamp blocktime = 3;
  // Transaction that did the change
  bytes txId = 4;
  // Block number that holds changing tx
  uint64 blocknumber = 5;
  // Is this tx deleted this key
  bool isDelete = 6;
}

Access to provenance data

For now, we go with the simplest approach - if user now have read access to given key, it can access its historical data as well, even if it didn't has access to this key in the past.

Transaction time

To eliminate difference between client clocks, Transaction time set to be equal to block time. We need to add time to block header.

Clone this wiki locally