Commit 64e6ce4c authored by manish's avatar manish
Browse files

Fixes in ledger code for new transaction structure

https://jira.hyperledger.org/browse/FAB-1199



This commit fixes the ledger code as per new transaction structure.
Also removed the explicit dependency on the msp security code by moving
the code to a separate testutil for a better reuse.

Change-Id: I60d3968ae26684747435c195bbe45a78697f4803
Signed-off-by: default avatarmanish <manish.sethi@gmail.com>
parent 61affa05
......@@ -24,29 +24,10 @@ import (
"github.com/hyperledger/fabric/core/ledger/testutil"
"github.com/stretchr/testify/assert"
"fmt"
"github.com/hyperledger/fabric/core/crypto/primitives"
"github.com/hyperledger/fabric/msp"
pb "github.com/hyperledger/fabric/protos/peer"
)
func TestKVLedgerBlockStorage(t *testing.T) {
primitives.SetSecurityLevel("SHA2", 256)
// setup the MSP manager so that we can sign/verify
mspMgrConfigFile := "../../msp/peer-config.json"
msp.GetManager().Setup(mspMgrConfigFile)
mspId := "DEFAULT"
id := "PEER"
signingIdentity := &msp.IdentityIdentifier{Mspid: msp.ProviderIdentifier{Value: mspId}, Value: id}
signer, err := msp.GetManager().GetSigningIdentity(signingIdentity)
if err != nil {
os.Exit(-1)
fmt.Printf("Could not initialize msp/signer")
return
}
conf := kvledger.NewConf("/tmp/tests/ledger/", 0)
defer os.RemoveAll("/tmp/tests/ledger/")
......@@ -70,7 +51,7 @@ func TestKVLedgerBlockStorage(t *testing.T) {
simulator.Done()
simRes, _ := simulator.GetTxSimulationResults()
block1 := testutil.ConstructBlockForSimulationResults(t, [][]byte{simRes}, signer)
block1 := testutil.ConstructBlockForSimulationResults(t, [][]byte{simRes}, true)
err = committer.CommitBlock(block1)
assert.NoError(t, err)
......
......@@ -25,9 +25,10 @@ import (
"github.com/hyperledger/fabric/core/ledger/blkstorage"
"github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/core/ledger/util/db"
"github.com/op/go-logging"
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
putil "github.com/hyperledger/fabric/protos/utils"
"github.com/op/go-logging"
)
var logger = logging.MustGetLogger("kvledger")
......@@ -466,16 +467,12 @@ func (mgr *blockfileMgr) fetchSerBlock(lp *fileLocPointer) (*pb.SerBlock2, error
}
func (mgr *blockfileMgr) fetchTransaction(lp *fileLocPointer) (*pb.Transaction, error) {
txBytes, err := mgr.fetchRawBytes(lp)
if err != nil {
return nil, err
}
tx := &pb.Transaction{}
err = proto.Unmarshal(txBytes, tx)
if err != nil {
var err error
var txEnvelopeBytes []byte
if txEnvelopeBytes, err = mgr.fetchRawBytes(lp); err != nil {
return nil, err
}
return tx, nil
return extractTransaction(txEnvelopeBytes)
}
func (mgr *blockfileMgr) fetchBlockBytes(lp *fileLocPointer) ([]byte, error) {
......@@ -560,6 +557,24 @@ func scanForLastCompleteBlock(rootDir string, fileNum int, startingOffset int64)
return blockStream.currentOffset, numBlocks, errRead
}
func extractTransaction(txEnvelopeBytes []byte) (*pb.Transaction, error) {
var err error
var txEnvelope *common.Envelope
var txPayload *common.Payload
var tx *pb.Transaction
if txEnvelope, err = putil.GetEnvelope(txEnvelopeBytes); err != nil {
return nil, err
}
if txPayload, err = putil.GetPayload(txEnvelope); err != nil {
return nil, err
}
if tx, err = putil.GetTransaction(txPayload.Data); err != nil {
return nil, err
}
return tx, nil
}
// checkpointInfo
type checkpointInfo struct {
latestFileChunkSuffixNum int
......
......@@ -143,13 +143,12 @@ func TestBlockfileMgrGetTxById(t *testing.T) {
blocks := testutil.ConstructTestBlocks(t, 10)
blkfileMgrWrapper.addBlocks(blocks)
for i, blk := range blocks {
for j, txBytes := range blk.Transactions {
for j, txEnvelopeBytes := range blk.Transactions {
// blockNum starts with 1
txID := constructTxID(uint64(i+1), j)
txFromFileMgr, err := blkfileMgrWrapper.blockfileMgr.retrieveTransactionByID(txID)
testutil.AssertNoError(t, err, "Error while retrieving tx from blkfileMgr")
tx := &pb.Transaction{}
err = proto.Unmarshal(txBytes, tx)
tx, err := extractTransaction(txEnvelopeBytes)
testutil.AssertNoError(t, err, "Error while unmarshalling tx")
testutil.AssertEquals(t, txFromFileMgr, tx)
}
......
......@@ -20,11 +20,8 @@ import (
"fmt"
"testing"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/ledger/blkstorage"
"github.com/hyperledger/fabric/core/ledger/testutil"
pb "github.com/hyperledger/fabric/protos/peer"
)
type noopIndex struct {
......@@ -144,8 +141,8 @@ func testBlockIndexSelectiveIndexing(t *testing.T, indexItems []blkstorage.Index
tx, err := blockfileMgr.retrieveTransactionByID(constructTxID(1, 0))
if testutil.Contains(indexItems, blkstorage.IndexableAttrTxID) {
testutil.AssertNoError(t, err, "Error while retrieving tx by id")
txOrig := &pb.Transaction{}
proto.Unmarshal(blocks[0].Transactions[0], txOrig)
txOrig, err := extractTransaction(blocks[0].Transactions[0])
testutil.AssertNoError(t, err, "")
testutil.AssertEquals(t, tx, txOrig)
} else {
testutil.AssertSame(t, err, blkstorage.ErrAttrNotIndexed)
......
......@@ -22,9 +22,9 @@ import (
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/util"
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
putils "github.com/hyperledger/fabric/protos/utils"
ptestutils "github.com/hyperledger/fabric/protos/testutils"
)
// App - a sample fund transfer app
......@@ -39,7 +39,7 @@ func ConstructAppInstance(ledger ledger.ValidatedLedger) *App {
}
// Init simulates init transaction
func (app *App) Init(initialBalances map[string]int) (*pb.Transaction, error) {
func (app *App) Init(initialBalances map[string]int) (*common.Envelope, error) {
var txSimulator ledger.TxSimulator
var err error
if txSimulator, err = app.ledger.NewTxSimulator(); err != nil {
......@@ -58,8 +58,7 @@ func (app *App) Init(initialBalances map[string]int) (*pb.Transaction, error) {
}
// TransferFunds simulates a transaction for transferring fund from fromAccount to toAccount
func (app *App) TransferFunds(fromAccount string, toAccount string, transferAmt int) (*pb.Transaction, error) {
func (app *App) TransferFunds(fromAccount string, toAccount string, transferAmt int) (*common.Envelope, error) {
// act as endorsing peer shim code to simulate a transaction on behalf of chaincode
var txSimulator ledger.TxSimulator
var err error
......@@ -102,6 +101,7 @@ func (app *App) QueryBalances(accounts []string) ([]int, error) {
if queryExecutor, err = app.ledger.NewQueryExecutor(); err != nil {
return nil, err
}
defer queryExecutor.Done()
balances := make([]int, len(accounts))
for i := 0; i < len(accounts); i++ {
var balBytes []byte
......@@ -113,9 +113,9 @@ func (app *App) QueryBalances(accounts []string) ([]int, error) {
return balances, nil
}
func constructTransaction(simulationResults []byte) *pb.Transaction {
tx, _ := putils.CreateTx(common.HeaderType_ENDORSER_TRANSACTION, nil, nil, simulationResults, []*pb.Endorsement{})
return tx
func constructTransaction(simulationResults []byte) *common.Envelope {
txEnv, _ := ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GenerateUUID(), "foo", simulationResults, nil, nil)
return txEnv
}
func toBytes(balance int) []byte {
......
......@@ -19,6 +19,7 @@ package example
import (
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
)
......@@ -32,7 +33,7 @@ func ConstructConsenter() *Consenter {
}
// ConstructBlock constructs a block from a list of transactions
func (c *Consenter) ConstructBlock(transactions ...*pb.Transaction) *pb.Block2 {
func (c *Consenter) ConstructBlock(transactions ...*common.Envelope) *pb.Block2 {
logger.Debugf("Construct a block based on the transactions")
block := &pb.Block2{}
for _, tx := range transactions {
......
......@@ -24,8 +24,7 @@ import (
ledger "github.com/hyperledger/fabric/core/ledger"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/common"
logging "github.com/op/go-logging"
)
......@@ -55,7 +54,7 @@ type Marble struct {
}
// CreateMarble simulates init transaction
func (marbleApp *MarbleApp) CreateMarble(args []string) (*pb.Transaction, error) {
func (marbleApp *MarbleApp) CreateMarble(args []string) (*common.Envelope, error) {
// 0 1 2 3
// "asdf", "blue", "35", "bob"
logger.Debugf("===COUCHDB=== Entering ----------CreateMarble()----------")
......@@ -126,8 +125,7 @@ func init_marble(args []string) ([]byte, error) {
}
// TransferMarble simulates transfer transaction
func (marbleApp *MarbleApp) TransferMarble(args []string) (*pb.Transaction, error) {
func (marbleApp *MarbleApp) TransferMarble(args []string) (*common.Envelope, error) {
// 0 1
// "name", "bob"
if len(args) < 2 {
......
......@@ -20,31 +20,10 @@ import (
"testing"
"github.com/hyperledger/fabric/core/ledger/testutil"
"fmt"
"os"
"github.com/hyperledger/fabric/core/crypto/primitives"
"github.com/hyperledger/fabric/msp"
pb "github.com/hyperledger/fabric/protos/peer"
)
func TestKVLedgerBlockStorage(t *testing.T) {
primitives.SetSecurityLevel("SHA2", 256)
// setup the MSP manager so that we can sign/verify
mspMgrConfigFile := "../../../msp/peer-config.json"
msp.GetManager().Setup(mspMgrConfigFile)
mspId := "DEFAULT"
id := "PEER"
signingIdentity := &msp.IdentityIdentifier{Mspid: msp.ProviderIdentifier{Value: mspId}, Value: id}
signer, err := msp.GetManager().GetSigningIdentity(signingIdentity)
if err != nil {
os.Exit(-1)
fmt.Printf("Could not initialize msp/signer")
return
}
env := newTestEnv(t)
defer env.cleanup()
ledger, _ := NewKVLedger(env.conf)
......@@ -60,7 +39,7 @@ func TestKVLedgerBlockStorage(t *testing.T) {
simulator.SetState("ns1", "key3", []byte("value3"))
simulator.Done()
simRes, _ := simulator.GetTxSimulationResults()
block1 := testutil.ConstructBlockForSimulationResults(t, [][]byte{simRes}, signer)
block1 := testutil.ConstructBlockForSimulationResults(t, [][]byte{simRes}, false)
ledger.RemoveInvalidTransactionsAndPrepare(block1)
ledger.Commit()
......@@ -76,7 +55,7 @@ func TestKVLedgerBlockStorage(t *testing.T) {
simulator.SetState("ns1", "key3", []byte("value6"))
simulator.Done()
simRes, _ = simulator.GetTxSimulationResults()
block2 := testutil.ConstructBlockForSimulationResults(t, [][]byte{simRes}, signer)
block2 := testutil.ConstructBlockForSimulationResults(t, [][]byte{simRes}, false)
ledger.RemoveInvalidTransactionsAndPrepare(block2)
ledger.Commit()
......
......@@ -20,19 +20,17 @@ import (
"testing"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/util"
"github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
putils "github.com/hyperledger/fabric/protos/utils"
ptestutils "github.com/hyperledger/fabric/protos/testutils"
)
// ConstructBlockForSimulationResults constructs a block that includes a number of transactions - one per simulationResults
func ConstructBlockForSimulationResults(t *testing.T, simulationResults [][]byte, signer msp.SigningIdentity) *pb.Block2 {
func ConstructBlockForSimulationResults(t *testing.T, simulationResults [][]byte, sign bool) *pb.Block2 {
envs := []*common.Envelope{}
for i := 0; i < len(simulationResults); i++ {
env, err := ConstructTestTransaction(t, simulationResults[i], signer)
env, err := ConstructTestTransaction(t, simulationResults[i], sign)
if err != nil {
t.Fatalf("ConstructTestTransaction failed, err %s", err)
}
......@@ -52,38 +50,22 @@ func ConstructTestBlocks(t *testing.T, numBlocks int) []*pb.Block2 {
// ConstructTestBlock constructs a block with 'numTx' number of transactions for testing
func ConstructTestBlock(t *testing.T, numTx int, txSize int, startingTxID int) *pb.Block2 {
txs := []*pb.Transaction{}
txEnvs := []*common.Envelope{}
for i := startingTxID; i < numTx+startingTxID; i++ {
tx, _ := putils.CreateTx(common.HeaderType_ENDORSER_TRANSACTION, []byte{}, []byte{}, ConstructRandomBytes(t, txSize), []*pb.Endorsement{})
txs = append(txs, tx)
txEnv, _ := ConstructTestTransaction(t, ConstructRandomBytes(t, txSize), false)
txEnvs = append(txEnvs, txEnv)
}
return newBlock(txs)
return newBlockEnv(txEnvs)
}
// ConstructTestTransaction constructs a transaction for testing
func ConstructTestTransaction(t *testing.T, simulationResults []byte, signer msp.SigningIdentity) (*common.Envelope, error) {
ss, err := signer.Serialize()
if err != nil {
return nil, err
}
uuid := util.GenerateUUID()
prop, err := putils.CreateChaincodeProposal(uuid, &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeID: &pb.ChaincodeID{Name: "foo"}}}, ss)
if err != nil {
return nil, err
}
presp, err := putils.CreateProposalResponse(prop.Header, prop.Payload, simulationResults, nil, nil, signer)
if err != nil {
return nil, err
}
env, err := putils.CreateSignedTx(prop, signer, presp)
if err != nil {
return nil, err
func ConstructTestTransaction(t *testing.T, simulationResults []byte, sign bool) (*common.Envelope, error) {
ccName := "foo"
txID := util.GenerateUUID()
if sign {
return ptestutils.ConstructSingedTxEnvWithDefaultSigner(txID, ccName, simulationResults, nil, nil)
}
return env, nil
return ptestutils.ConstructUnsingedTxEnv(txID, ccName, simulationResults, nil, nil)
}
// ComputeBlockHash computes the crypto-hash of a block
......@@ -93,16 +75,6 @@ func ComputeBlockHash(t testing.TB, block *pb.Block2) []byte {
return serBlock.ComputeHash()
}
func newBlock(txs []*pb.Transaction) *pb.Block2 {
block := &pb.Block2{}
block.PreviousBlockHash = []byte{}
for i := 0; i < len(txs); i++ {
txBytes, _ := proto.Marshal(txs[i])
block.Transactions = append(block.Transactions, txBytes)
}
return block
}
func newBlockEnv(env []*common.Envelope) *pb.Block2 {
block := &pb.Block2{}
block.PreviousBlockHash = []byte{}
......
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testutils
import (
"fmt"
"os"
"path/filepath"
"github.com/hyperledger/fabric/core/crypto/primitives"
"github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
putils "github.com/hyperledger/fabric/protos/utils"
)
var (
signingIdentity *msp.IdentityIdentifier
signer msp.SigningIdentity
)
func init() {
var err error
primitives.SetSecurityLevel("SHA2", 256)
// setup the MSP manager so that we can sign/verify
mspMgrConfigFile, err := getMSPMgrConfigFile()
if err != nil {
os.Exit(-1)
fmt.Printf("Could not get location of msp manager config file")
return
}
msp.GetManager().Setup(mspMgrConfigFile)
mspID := "DEFAULT"
id := "PEER"
signingIdentity = &msp.IdentityIdentifier{Mspid: msp.ProviderIdentifier{Value: mspID}, Value: id}
signer, err = msp.GetManager().GetSigningIdentity(signingIdentity)
if err != nil {
os.Exit(-1)
fmt.Printf("Could not initialize msp/signer")
return
}
}
func getMSPMgrConfigFile() (string, error) {
var pwd string
var err error
if pwd, err = os.Getwd(); err != nil {
return "", err
}
path := pwd
dir := ""
for {
path, dir = filepath.Split(path)
path = filepath.Clean(path)
fmt.Printf("path=%s, dir=%s\n", path, dir)
if dir == "fabric" {
break
}
}
filePath := filepath.Join(path, "fabric/msp/peer-config.json")
fmt.Printf("filePath=%s\n", filePath)
return filePath, nil
}
// ConstructSingedTxEnvWithDefaultSigner constructs a transaction envelop for tests with a default signer.
// This method helps other modules to construct a transaction with supplied parameters
func ConstructSingedTxEnvWithDefaultSigner(txid string, ccName string, simulationResults []byte, events []byte, visibility []byte) (*common.Envelope, error) {
return ConstructSingedTxEnv(txid, ccName, simulationResults, events, visibility, signer)
}
// ConstructSingedTxEnv constructs a transaction envelop for tests
func ConstructSingedTxEnv(txid string, ccName string, simulationResults []byte, events []byte, visibility []byte, signer msp.SigningIdentity) (*common.Envelope, error) {
ss, err := signer.Serialize()
if err != nil {
return nil, err
}
prop, err := putils.CreateChaincodeProposal(txid, &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeID: &pb.ChaincodeID{Name: ccName}}}, ss)
if err != nil {
return nil, err
}
presp, err := putils.CreateProposalResponse(prop.Header, prop.Payload, simulationResults, nil, nil, signer)
if err != nil {
return nil, err
}
env, err := putils.CreateSignedTx(prop, signer, presp)
if err != nil {
return nil, err
}
return env, nil
}
// ConstructUnsingedTxEnv creates a Transaction envelope from given inputs
func ConstructUnsingedTxEnv(txid string, ccName string, simulationResults []byte, events []byte, visibility []byte) (*common.Envelope, error) {
prop, err := putils.CreateChaincodeProposal(txid, &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeID: &pb.ChaincodeID{Name: ccName}}}, nil)
if err != nil {
return nil, err
}
presp, err := putils.ConstructUnsignedProposalResponse(prop.Header, prop.Payload, simulationResults, nil, nil)
if err != nil {
return nil, err
}
env, err := putils.ConstructUnsignedTxEnvelope(prop, presp)
if err != nil {
return nil, err
}
return env, nil
}
......@@ -59,59 +59,54 @@ func GetPayloads(txActions *peer.TransactionAction) (*peer.ChaincodeActionPayloa
return ccPayload, respPayload, nil
}
// CreateTx creates a Transaction from given inputs
func CreateTx(typ common.HeaderType, ccPropPayload []byte, ccEvents []byte, simulationResults []byte, endorsements []*peer.Endorsement) (*peer.Transaction, error) {
if typ != common.HeaderType_ENDORSER_TRANSACTION {
panic("-----Only CHAINCODE Type is supported-----")
// GetEndorserTxFromBlock gets Transaction2 from Block.Data.Data
func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error) {
//Block always begins with an envelope
var err error
env := &common.Envelope{}
if err = proto.Unmarshal(data, env); err != nil {
return nil, fmt.Errorf("Error getting envelope(%s)\n", err)
}
ext := &peer.ChaincodeAction{Results: simulationResults, Events: ccEvents}
extBytes, err := proto.Marshal(ext)
return env, nil
}
// CreateSignedTx assembles an Envelope message from proposal, endorsements and a signer.
// This function should be called by a client when it has collected enough endorsements
// for a proposal to create a transaction and submit it to peers for ordering
func CreateSignedTx(proposal *peer.Proposal, signer msp.SigningIdentity, resps ...*peer.ProposalResponse) (*common.Envelope, error) {
// the original header
hdr, err := GetHeader(proposal.Header)
if err != nil {
return nil, err
return nil, fmt.Errorf("Could not unmarshal the proposal header")
}
pRespPayload := &peer.ProposalResponsePayload{ProposalHash: ccPropPayload, Extension: extBytes}
pRespPayloadBytes, err := proto.Marshal(pRespPayload)
// check that the signer is the same that is referenced in the header
// TODO: maybe worth removing?
signerBytes, err := signer.Serialize()
if err != nil {
return nil, err
}
ceAction := &peer.ChaincodeEndorsedAction{ProposalResponsePayload: pRespPayloadBytes, Endorsements: endorsements}
caPayload := &peer.ChaincodeActionPayload{ChaincodeProposalPayload: []byte("marshalled payload here"), Action: ceAction}
actionBytes, err := proto.Marshal(caPayload)
if err != nil {
return nil, err
if bytes.Compare(signerBytes, hdr.SignatureHeader.Creator) != 0 {
return nil, fmt.Errorf("The signer needs to be the same as the one referenced in the header")
}
hdr := &common.Header{ChainHeader: &common.ChainHeader{Type: int32(common.HeaderType_ENDORSER_TRANSACTION)}}
hdrBytes, err := proto.Marshal(hdr)
// create the payload
txEnvelope, err := ConstructUnsignedTxEnvelope(proposal, resps...)
if err != nil {
return nil, err
}
tx := &peer.Transaction{}
tx.Actions = []*peer.TransactionAction{&peer.TransactionAction{Header: hdrBytes, Payload: actionBytes}}
return tx, nil
}
// GetEndorserTxFromBlock gets Transaction from Block.Data.Data
func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error) {
//Block always begins with an envelope
var err error
env := &common.Envelope{}
if err = proto.Unmarshal(data, env); err != nil {
return nil, fmt.Errorf("Error getting envelope(%s)\n", err)
// sign the payload
sig, err := signer.Sign(txEnvelope.Payload)
if err != nil {
return nil, err
}
return env, nil
txEnvelope.Signature = sig
return txEnvelope, nil
}
// assemble an Envelope message from proposal, endorsements and a signer.
// This function should be called by a client when it has collected enough endorsements
// for a proposal to create a transaction and submit it to peers for ordering
func CreateSignedTx(proposal *peer.Proposal, signer msp.SigningIdentity, resps ...*peer.ProposalResponse) (*common.Envelope, error) {
// ConstructUnsignedTxEnvelope constructs payload for the transaction from proposal and endorsements.
func ConstructUnsignedTxEnvelope(proposal *peer.Proposal, resps ...*peer.ProposalResponse) (*common.Envelope, error) {
if len(resps) == 0 {