Skip to content

Commit

Permalink
[FAB-2024] Add valid indicator to GetTransactionById
Browse files Browse the repository at this point in the history
When clients retrieve a transaction from ledger, they need to know whether the
transaction was validated or invalidated by committing peer.

GetTransactionByID API needs to retrieve the transaction Envelope
from block storage, and return it to a client, and indicate whether the
transaction was validated or invalidated by committing peer. So that the
originally submitted transaction Envelope is not modified, a new
ProcessedTransaction wrapper is returned.

Also removed InvalidTransaction, since it is not used.

Change-Id: I7a4ec2b56b120f5df4ef18f0df415bab1a7dc9d1
Signed-off-by: denyeart <enyeart@us.ibm.com>
  • Loading branch information
denyeart committed Feb 11, 2017
1 parent d58349a commit f8dd7a3
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 85 deletions.
20 changes: 18 additions & 2 deletions core/ledger/kvledger/kv_ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr"
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/peer"
logging "github.com/op/go-logging"
)

Expand Down Expand Up @@ -199,8 +200,23 @@ func recommitLostBlocks(l *kvLedger, savepoint uint64, blockHeight uint64, recov
}

// GetTransactionByID retrieves a transaction by id
func (l *kvLedger) GetTransactionByID(txID string) (*common.Envelope, error) {
return l.blockStore.RetrieveTxByID(txID)
func (l *kvLedger) GetTransactionByID(txID string) (*peer.ProcessedTransaction, error) {

tranEnv, err := l.blockStore.RetrieveTxByID(txID)
if err != nil {
return nil, err
}

// Hardocde to Valid:true for now
processedTran := &peer.ProcessedTransaction{TransactionEnvelope: tranEnv, Valid: true}

// TODO subsequent changeset will retrieve validation bit array on the block to indicate
// whether the tran was validated or invalidated. It is possible to retreive both the tran
// and the block (with bit array) from storage and combine the results. But it would be
// more efficient to refactor block storage to retrieve the tran and the validation bit
// in one operation.

return processedTran, nil
}

// GetBlockchainInfo returns basic info about blockchain
Expand Down
15 changes: 15 additions & 0 deletions core/ledger/kvledger/kv_ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
ledgertestutil "github.com/hyperledger/fabric/core/ledger/testutil"
"github.com/hyperledger/fabric/protos/common"
putils "github.com/hyperledger/fabric/protos/utils"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -81,6 +82,20 @@ func TestKVLedgerBlockStorage(t *testing.T) {

b2, _ = ledger.GetBlockByNumber(2)
testutil.AssertEquals(t, b2, block2)

// get the tran id from the 2nd block, then use it to test GetTransactionByID()
txEnvBytes2 := block2.Data.Data[0]
txEnv2, err := putils.GetEnvelopeFromBlock(txEnvBytes2)
testutil.AssertNoError(t, err, "Error upon GetEnvelopeFromBlock")
payload2, err := putils.GetPayload(txEnv2)
testutil.AssertNoError(t, err, "Error upon GetPayload")
txID2 := payload2.Header.ChannelHeader.TxId
processedTran2, err := ledger.GetTransactionByID(txID2)
testutil.AssertNoError(t, err, "Error upon GetTransactionByID")
// get the tran envelope from the retrieved ProcessedTransaction
retrievedTxEnv2 := processedTran2.TransactionEnvelope
testutil.AssertEquals(t, retrievedTxEnv2, txEnv2)

}

func TestKVLedgerDBRecovery(t *testing.T) {
Expand Down
3 changes: 2 additions & 1 deletion core/ledger/ledger_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package ledger
import (
commonledger "github.com/hyperledger/fabric/common/ledger"
"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/peer"
)

// PeerLedgerProvider provides handle to ledger instances
Expand All @@ -40,7 +41,7 @@ type PeerLedgerProvider interface {
type PeerLedger interface {
commonledger.Ledger
// GetTransactionByID retrieves a transaction by id
GetTransactionByID(txID string) (*common.Envelope, error)
GetTransactionByID(txID string) (*peer.ProcessedTransaction, error)
// GetBlockByHash returns a block given it's hash
GetBlockByHash(blockHash []byte) (*common.Block, error)
// NewTxSimulator gives handle to a transaction simulator.
Expand Down
7 changes: 3 additions & 4 deletions core/scc/qscc/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,13 @@ func getTransactionByID(vledger ledger.PeerLedger, tid []byte) pb.Response {
if tid == nil {
return shim.Error("Transaction ID must not be nil.")
}
txEnvelope, err := vledger.GetTransactionByID(string(tid))

processedTran, err := vledger.GetTransactionByID(string(tid))
if err != nil {
return shim.Error(fmt.Sprintf("Failed to get transaction with id %s, error %s", string(tid), err))
}
// TODO In the returned transaction, need to replace binary simulation results with a proto
// structure including write set, so that clients know what this transaction wrote

bytes, err := utils.Marshal(txEnvelope)
bytes, err := utils.Marshal(processedTran)
if err != nil {
return shim.Error(err.Error())
}
Expand Down
2 changes: 1 addition & 1 deletion protos/peer/admin.pb.go

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

121 changes: 52 additions & 69 deletions protos/peer/transaction.pb.go

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

21 changes: 13 additions & 8 deletions protos/peer/transaction.proto
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package protos;

import "google/protobuf/timestamp.proto";
import "peer/proposal_response.proto";
import "common/common.proto";

// This message is necessary to facilitate the verification of the signature
// (in the signature field) over the bytes of the transaction (in the
Expand All @@ -38,14 +39,18 @@ message SignedTransaction {
bytes signature = 2;
}

// This is used to wrap an invalid Transaction with the cause
message InvalidTransaction {
enum Cause {
TX_ID_ALREADY_EXISTS = 0;
RW_CONFLICT_DURING_COMMIT = 1;
}
Transaction transaction = 1;
Cause cause = 2;
// ProcessedTransaction wraps an Envelope that includes a transaction along with an indication
// of whether the transaction was validated or invalidated by committing peer.
// The use case is that GetTransactionByID API needs to retrieve the transaction Envelope
// from block storage, and return it to a client, and indicate whether the transaction
// was validated or invalidated by committing peer. So that the originally submitted
// transaction Envelope is not modified, the ProcessedTransaction wrapper is returned.
message ProcessedTransaction {
// An Envelope which includes a processed transaction
common.Envelope transactionEnvelope = 1;

// An indication of whether the transaction was validated or invalidated by committing peer
bool valid = 2;
}

// The transaction to be sent to the ordering service. A transaction contains
Expand Down

0 comments on commit f8dd7a3

Please sign in to comment.