Skip to content

Commit

Permalink
Return block number along with validation code (#2614)
Browse files Browse the repository at this point in the history
Add committing block number, along with validation code for a given TXID

Signed-off-by: manish <manish.sethi@gmail.com>
  • Loading branch information
manish-sethi authored Jun 1, 2021
1 parent e8e39e6 commit 9170fea
Show file tree
Hide file tree
Showing 17 changed files with 114 additions and 80 deletions.
8 changes: 4 additions & 4 deletions common/ledger/blkstorage/blockfile_mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,15 +544,15 @@ func (mgr *blockfileMgr) retrieveBlockByTxID(txID string) (*common.Block, error)
return mgr.fetchBlock(loc)
}

func (mgr *blockfileMgr) retrieveTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) {
func (mgr *blockfileMgr) retrieveTxValidationCodeByTxID(txID string) (peer.TxValidationCode, uint64, error) {
logger.Debugf("retrieveTxValidationCodeByTxID() - txID = [%s]", txID)
validationCode, err := mgr.index.getTxValidationCodeByTxID(txID)
validationCode, blkNum, err := mgr.index.getTxValidationCodeByTxID(txID)
if err == errNilValue {
return peer.TxValidationCode(-1), errors.Errorf(
return peer.TxValidationCode(-1), 0, errors.Errorf(
"details for the TXID [%s] not available. Ledger bootstrapped from a snapshot. First available block = [%d]",
txID, mgr.firstPossibleBlockNumberInBlockFiles())
}
return validationCode, err
return validationCode, blkNum, err
}

func (mgr *blockfileMgr) retrieveBlockHeaderByNumber(blockNum uint64) (*common.BlockHeader, error) {
Expand Down
9 changes: 6 additions & 3 deletions common/ledger/blkstorage/blockfile_mgr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,15 @@ func TestBlockfileMgrGetTxByIdDuplicateTxid(t *testing.T) {
blk, _ = blkFileMgr.retrieveBlockByTxID("txid-3")
require.Equal(t, block2, blk)

validationCode, _ := blkFileMgr.retrieveTxValidationCodeByTxID("txid-1")
validationCode, blkNum, _ := blkFileMgr.retrieveTxValidationCodeByTxID("txid-1")
require.Equal(t, peer.TxValidationCode_VALID, validationCode)
validationCode, _ = blkFileMgr.retrieveTxValidationCodeByTxID("txid-2")
require.Equal(t, uint64(1), blkNum)
validationCode, blkNum, _ = blkFileMgr.retrieveTxValidationCodeByTxID("txid-2")
require.Equal(t, peer.TxValidationCode_INVALID_OTHER_REASON, validationCode)
validationCode, _ = blkFileMgr.retrieveTxValidationCodeByTxID("txid-3")
require.Equal(t, uint64(1), blkNum)
validationCode, blkNum, _ = blkFileMgr.retrieveTxValidationCodeByTxID("txid-3")
require.Equal(t, peer.TxValidationCode_VALID, validationCode)
require.Equal(t, uint64(2), blkNum)

// though we do not expose an API for retrieving all the txs by same id but we may in future
// and the data is persisted to support this. below code tests this behavior internally
Expand Down
37 changes: 23 additions & 14 deletions common/ledger/blkstorage/blockindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func (index *blockIndex) getBlockLocByBlockNum(blockNum uint64) (*fileLocPointer
}

func (index *blockIndex) getTxLoc(txID string) (*fileLocPointer, error) {
v, err := index.getTxIDVal(txID)
v, _, err := index.getTxIDVal(txID)
if err != nil {
return nil, err
}
Expand All @@ -208,7 +208,7 @@ func (index *blockIndex) getTxLoc(txID string) (*fileLocPointer, error) {
}

func (index *blockIndex) getBlockLocByTxID(txID string) (*fileLocPointer, error) {
v, err := index.getTxIDVal(txID)
v, _, err := index.getTxIDVal(txID)
if err != nil {
return nil, err
}
Expand All @@ -219,12 +219,12 @@ func (index *blockIndex) getBlockLocByTxID(txID string) (*fileLocPointer, error)
return blkFLP, nil
}

func (index *blockIndex) getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) {
v, err := index.getTxIDVal(txID)
func (index *blockIndex) getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, uint64, error) {
v, blkNum, err := index.getTxIDVal(txID)
if err != nil {
return peer.TxValidationCode(-1), err
return peer.TxValidationCode(-1), 0, err
}
return peer.TxValidationCode(v.TxValidationCode), nil
return peer.TxValidationCode(v.TxValidationCode), blkNum, nil
}

func (index *blockIndex) txIDExists(txID string) (bool, error) {
Expand All @@ -245,33 +245,37 @@ func (index *blockIndex) txIDExists(txID string) (bool, error) {
return present, nil
}

func (index *blockIndex) getTxIDVal(txID string) (*TxIDIndexValue, error) {
func (index *blockIndex) getTxIDVal(txID string) (*TxIDIndexValue, uint64, error) {
if !index.isAttributeIndexed(IndexableAttrTxID) {
return nil, errors.New("transaction IDs not maintained in index")
return nil, 0, errors.New("transaction IDs not maintained in index")
}
rangeScan := constructTxIDRangeScan(txID)
itr, err := index.db.GetIterator(rangeScan.startKey, rangeScan.stopKey)
if err != nil {
return nil, errors.WithMessagef(err, "error while trying to retrieve transaction info by TXID [%s]", txID)
return nil, 0, errors.WithMessagef(err, "error while trying to retrieve transaction info by TXID [%s]", txID)
}
defer itr.Release()

present := itr.Next()
if err := itr.Error(); err != nil {
return nil, errors.Wrapf(err, "error while trying to retrieve transaction info by TXID [%s]", txID)
return nil, 0, errors.Wrapf(err, "error while trying to retrieve transaction info by TXID [%s]", txID)
}
if !present {
return nil, errors.Errorf("no such transaction ID [%s] in index", txID)
return nil, 0, errors.Errorf("no such transaction ID [%s] in index", txID)
}
valBytes := itr.Value()
if len(valBytes) == 0 {
return nil, errNilValue
return nil, 0, errNilValue
}
val := &TxIDIndexValue{}
if err := proto.Unmarshal(valBytes, val); err != nil {
return nil, errors.Wrapf(err, "unexpected error while unmarshalling bytes [%#v] into TxIDIndexValProto", valBytes)
return nil, 0, errors.Wrapf(err, "unexpected error while unmarshalling bytes [%#v] into TxIDIndexValProto", valBytes)
}
blockNum, err := retrieveBlockNum(itr.Key(), len(rangeScan.startKey))
if err != nil {
return nil, 0, errors.WithMessage(err, "error while decoding block number from txID index key")
}
return val, nil
return val, blockNum, nil
}

func (index *blockIndex) getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error) {
Expand Down Expand Up @@ -444,6 +448,11 @@ func retrieveTxID(encodedTxIDKey []byte) (string, error) {
return string(remainingBytes[:int(txIDLen)]), nil
}

func retrieveBlockNum(encodedTxIDKey []byte, BlkNumStartingIndex int) (uint64, error) {
n, _, err := util.DecodeOrderPreservingVarUint64(encodedTxIDKey[BlkNumStartingIndex:])
return n, err
}

type rangeScan struct {
startKey []byte
stopKey []byte
Expand Down
3 changes: 2 additions & 1 deletion common/ledger/blkstorage/blockindex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,13 @@ func testBlockIndexSelectiveIndexing(t *testing.T, indexItems []IndexableAttr) {
txid, err = protoutil.GetOrComputeTxIDFromEnvelope(d)
require.NoError(t, err)

reason, err := blockfileMgr.retrieveTxValidationCodeByTxID(txid)
reason, blkNum, err := blockfileMgr.retrieveTxValidationCodeByTxID(txid)

if containsAttr(indexItems, IndexableAttrTxID) {
require.NoError(t, err)
reasonFromFlags := flags.Flag(idx)
require.Equal(t, reasonFromFlags, reason)
require.Equal(t, block.Header.Number, blkNum)
} else {
require.EqualError(t, err, "transaction IDs not maintained in index")
}
Expand Down
2 changes: 1 addition & 1 deletion common/ledger/blkstorage/blockstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (store *BlockStore) RetrieveBlockByTxID(txID string) (*common.Block, error)
}

// RetrieveTxValidationCodeByTxID returns the validation code for the specified txID
func (store *BlockStore) RetrieveTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) {
func (store *BlockStore) RetrieveTxValidationCodeByTxID(txID string) (peer.TxValidationCode, uint64, error) {
return store.fileMgr.retrieveTxValidationCodeByTxID(txID)
}

Expand Down
6 changes: 4 additions & 2 deletions common/ledger/blkstorage/blockstore_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@ func checkBlocks(t *testing.T, expectedBlocks []*common.Block, store *BlockStore
retrievedTxEnv, _ = store.RetrieveTxByBlockNumTranNum(uint64(blockNum), uint64(txNum))
require.Equal(t, txEnv, retrievedTxEnv)

retrievedTxValCode, err := store.RetrieveTxValidationCodeByTxID(txid)
retrievedTxValCode, blkNum, err := store.RetrieveTxValidationCodeByTxID(txid)
require.NoError(t, err)
require.Equal(t, flags.Flag(txNum), retrievedTxValCode)
require.Equal(t, uint64(blockNum), blkNum)
}
}
}
Expand All @@ -154,8 +155,9 @@ func checkWithWrongInputs(t *testing.T, store *BlockStore, numBlocks int) {
require.Nil(t, tx)
require.EqualError(t, err, fmt.Sprintf("no such blockNumber, transactionNumber <%d, 0> in index", numBlocks+1))

txCode, err := store.RetrieveTxValidationCodeByTxID("non-existent-txid")
txCode, blkNum, err := store.RetrieveTxValidationCodeByTxID("non-existent-txid")
require.Equal(t, peer.TxValidationCode(-1), txCode)
require.Equal(t, uint64(0), blkNum)
require.EqualError(t, err, "no such transaction ID [non-existent-txid] in index")
}

Expand Down
2 changes: 1 addition & 1 deletion common/ledger/blkstorage/blockstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestTxIDIndexErrorPropagations(t *testing.T) {
return err
},
func() error {
_, err := store.RetrieveTxValidationCodeByTxID("junkTxID")
_, _, err := store.RetrieveTxValidationCodeByTxID("junkTxID")
return err
},
}
Expand Down
5 changes: 3 additions & 2 deletions common/ledger/blkstorage/snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ func verifyQueriesOnBlocksPriorToSnapshot(
_, err = bootstrappedBlockStore.RetrieveTxByID(txID)
require.EqualError(t, err, expectedErrorStr)

_, err = bootstrappedBlockStore.RetrieveTxValidationCodeByTxID(txID)
_, _, err = bootstrappedBlockStore.RetrieveTxValidationCodeByTxID(txID)
require.EqualError(t, err, expectedErrorStr)

exists, err := bootstrappedBlockStore.TxIDExists(txID)
Expand Down Expand Up @@ -550,9 +550,10 @@ func verifyQueriesOnBlocksAddedAfterBootstrapping(t *testing.T,
}

for j, validationCode := range d.validationCodes {
retrievedValidationCode, err := bootstrappedBlockStore.RetrieveTxValidationCodeByTxID(d.txIDs[j])
retrievedValidationCode, blkNum, err := bootstrappedBlockStore.RetrieveTxValidationCodeByTxID(d.txIDs[j])
require.NoError(t, err)
require.Equal(t, validationCode, retrievedValidationCode)
require.Equal(t, block.Header.Number, blkNum)
}
}
}
33 changes: 19 additions & 14 deletions core/chaincode/mock/peer_ledger.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions core/committer/txvalidator/v14/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1450,9 +1450,9 @@ func (m *mockLedger) GetBlockByTxID(txID string) (*common.Block, error) {
}

// GetTxValidationCodeByTxID returns validation code of give tx
func (m *mockLedger) GetTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) {
func (m *mockLedger) GetTxValidationCodeByTxID(txID string) (peer.TxValidationCode, uint64, error) {
args := m.Called(txID)
return args.Get(0).(peer.TxValidationCode), nil
return args.Get(0).(peer.TxValidationCode), args.Get(1).(uint64), nil
}

// NewTxSimulator creates new transaction simulator
Expand Down
8 changes: 4 additions & 4 deletions core/ledger/kvledger/kv_ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ func (l *kvLedger) GetTransactionByID(txID string) (*peer.ProcessedTransaction,
if err != nil {
return nil, err
}
txVResult, err := l.blockStore.RetrieveTxValidationCodeByTxID(txID)
txVResult, _, err := l.blockStore.RetrieveTxValidationCodeByTxID(txID)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -554,11 +554,11 @@ func (l *kvLedger) GetBlockByTxID(txID string) (*common.Block, error) {
return block, err
}

func (l *kvLedger) GetTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) {
func (l *kvLedger) GetTxValidationCodeByTxID(txID string) (peer.TxValidationCode, uint64, error) {
l.blockAPIsRWLock.RLock()
defer l.blockAPIsRWLock.RUnlock()
txValidationCode, err := l.blockStore.RetrieveTxValidationCodeByTxID(txID)
return txValidationCode, err
txValidationCode, blkNum, err := l.blockStore.RetrieveTxValidationCodeByTxID(txID)
return txValidationCode, blkNum, err
}

// NewTxSimulator returns new `ledger.TxSimulator`
Expand Down
4 changes: 3 additions & 1 deletion core/ledger/kvledger/kv_ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,10 @@ func TestKVLedgerBlockStorage(t *testing.T) {
require.True(t, proto.Equal(b1, block1), "proto messages are not equal")

// get the transaction validation code for this transaction id
validCode, _ := lgr.GetTxValidationCodeByTxID(txID2)
validCode, blkNum, err := lgr.GetTxValidationCodeByTxID(txID2)
require.NoError(t, err)
require.Equal(t, peer.TxValidationCode_VALID, validCode)
require.Equal(t, uint64(1), blkNum)

exists, err = lgr.TxIDExists("random-txid")
require.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion core/ledger/kvledger/tests/snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestSnapshotGenerationAndBootstrap(t *testing.T) {
_, err = lgr.GetBlockByNumber(3)
require.EqualError(t, err, "cannot serve block [3]. The ledger is bootstrapped from a snapshot. First available block = [4]")

_, err = lgr.GetTxValidationCodeByTxID("txid-1")
_, _, err = lgr.GetTxValidationCodeByTxID("txid-1")
require.EqualError(t, err, "details for the TXID [txid-1] not available. Ledger bootstrapped from a snapshot. First available block = [4]")

testLedger.verifyTXIDExists("txid-1", "txid-2")
Expand Down
2 changes: 1 addition & 1 deletion core/ledger/ledger_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ type PeerLedger interface {
// GetBlockByTxID returns a block which contains a transaction
GetBlockByTxID(txID string) (*common.Block, error)
// GetTxValidationCodeByTxID returns reason code of transaction validation
GetTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error)
GetTxValidationCodeByTxID(txID string) (peer.TxValidationCode, uint64, error)
// NewTxSimulator gives handle to a transaction simulator.
// A client can obtain more than one 'TxSimulator's for parallel execution.
// Any snapshoting/synchronization should be performed at the implementation level if required
Expand Down
Loading

0 comments on commit 9170fea

Please sign in to comment.