Commit 8a87b8ae authored by manish's avatar manish
Browse files

[FAB-5654] SideDB - Tx simulation/validation/commit



This CR modifies the tranaction simulation, validation, and commit
code and delivers the end-to-end transaction flow that treats the
private data in a special manner. This CR mainly leverages the earlier
submitted independent CRs for sidedb feature for accomplishing this behavior.

This CR also allows ledger to receive the blocks and the pvt data from
another peer on the same channel (i.e., a peer catching up via state)

This CR is exceptionally large becasue of manily two reasons

1) The way currently the code (and specially the tests) is organized in
simulation/validation/commit flow, its not easy to submit such kind
of changes independently that cuase the change in the whole transaction
processing flow.

2) This CR causes a change in the existing ledger APIs which are used widely
across other packages (specially in the tests) and hence many files are included
for fixing the broken dependencies

Change-Id: Id29575176575f4c01793efd3476b68f8364cb592
Signed-off-by: default avatarmanish <manish.sethi@gmail.com>
parent d9e00048
......@@ -34,7 +34,7 @@ func TestBlockSerialization(t *testing.T) {
}
func TestExtractTxid(t *testing.T) {
txEnv, txid, _ := testutil.ConstructTransaction(t, testutil.ConstructRandomBytes(t, 50), false)
txEnv, txid, _ := testutil.ConstructTransaction(t, testutil.ConstructRandomBytes(t, 50), "", false)
txEnvBytes, _ := putils.GetBytesEnvelope(txEnv)
extractedTxid, err := extractTxID(txEnvBytes)
testutil.AssertNoError(t, err, "")
......
......@@ -53,6 +53,18 @@ func (bg *BlockGenerator) NextBlock(simulationResults [][]byte) *common.Block {
return block
}
// NextBlock constructs next block in sequence that includes a number of transactions - one per simulationResults
func (bg *BlockGenerator) NextBlockWithTxid(simulationResults [][]byte, txids []string) *common.Block {
// Length of simulationResults should be same as the length of txids.
if len(simulationResults) != len(txids) {
return nil
}
block := ConstructBlockWithTxid(bg.t, bg.blockNum, bg.previousHash, simulationResults, txids, bg.signTxs)
bg.blockNum++
bg.previousHash = block.Header.Hash()
return block
}
// NextTestBlock constructs next block in sequence block with 'numTx' number of transactions for testing
func (bg *BlockGenerator) NextTestBlock(numTx int, txSize int) *common.Block {
simulationResults := [][]byte{}
......@@ -72,7 +84,7 @@ func (bg *BlockGenerator) NextTestBlocks(numBlocks int) []*common.Block {
}
// ConstructTransaction constructs a transaction for testing
func ConstructTransaction(_ *testing.T, simulationResults []byte, sign bool) (*common.Envelope, string, error) {
func ConstructTransaction(_ *testing.T, simulationResults []byte, txid string, sign bool) (*common.Envelope, string, error) {
ccid := &pb.ChaincodeID{
Name: "foo",
Version: "v1",
......@@ -82,18 +94,30 @@ func ConstructTransaction(_ *testing.T, simulationResults []byte, sign bool) (*c
var txEnv *common.Envelope
var err error
if sign {
txEnv, txID, err = ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), ccid, nil, simulationResults, nil, nil)
txEnv, txID, err = ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), ccid, nil, simulationResults, txid, nil, nil)
} else {
txEnv, txID, err = ptestutils.ConstructUnsingedTxEnv(util.GetTestChainID(), ccid, nil, simulationResults, nil, nil)
txEnv, txID, err = ptestutils.ConstructUnsingedTxEnv(util.GetTestChainID(), ccid, nil, simulationResults, txid, nil, nil)
}
return txEnv, txID, err
}
func ConstructBlockWithTxid(t *testing.T, blockNum uint64, previousHash []byte, simulationResults [][]byte, txids []string, sign bool) *common.Block {
envs := []*common.Envelope{}
for i := 0; i < len(simulationResults); i++ {
env, _, err := ConstructTransaction(t, simulationResults[i], txids[i], sign)
if err != nil {
t.Fatalf("ConstructTestTransaction failed, err %s", err)
}
envs = append(envs, env)
}
return newBlock(envs, blockNum, previousHash)
}
// ConstructBlock constructs a single block
func ConstructBlock(t *testing.T, blockNum uint64, previousHash []byte, simulationResults [][]byte, sign bool) *common.Block {
envs := []*common.Envelope{}
for i := 0; i < len(simulationResults); i++ {
env, _, err := ConstructTransaction(t, simulationResults[i], sign)
env, _, err := ConstructTransaction(t, simulationResults[i], "", sign)
if err != nil {
t.Fatalf("ConstructTestTransaction failed, err %s", err)
}
......
......@@ -56,6 +56,21 @@ func (m *MockQueryExecutor) ExecuteQuery(namespace, query string) (ledger.Result
return nil, nil
}
func (m *MockQueryExecutor) Done() {
func (m *MockQueryExecutor) GetPrivateData(namespace, collection, key string) ([]byte, error) {
return nil, nil
}
func (m *MockQueryExecutor) GetPrivateDataMultipleKeys(namespace, collection string, keys []string) ([][]byte, error) {
return nil, nil
}
func (m *MockQueryExecutor) GetPrivateDataRangeScanIterator(namespace, collection, startKey, endKey string) (ledger.ResultsIterator, error) {
return nil, nil
}
func (m *MockQueryExecutor) ExecuteQueryOnPrivateData(namespace, collection, query string) (ledger.ResultsIterator, error) {
return nil, nil
}
func (m *MockQueryExecutor) Done() {
}
......@@ -53,10 +53,10 @@ type ccProviderContextImpl struct {
}
// GetContext returns a context for the supplied ledger, with the appropriate tx simulator
func (c *ccProviderImpl) GetContext(ledger ledger.PeerLedger) (context.Context, error) {
func (c *ccProviderImpl) GetContext(ledger ledger.PeerLedger, txid string) (context.Context, error) {
var err error
// get context for the chaincode execution
c.txsim, err = ledger.NewTxSimulator()
c.txsim, err = ledger.NewTxSimulator(txid)
if err != nil {
return nil, err
}
......
This diff is collapsed.
......@@ -19,6 +19,7 @@ package chaincode
import (
"bytes"
"encoding/json"
"errors"
"flag"
"fmt"
"math/rand"
......@@ -168,9 +169,9 @@ func finitPeer(lis net.Listener, chainIDs ...string) {
}
}
func startTxSimulation(ctxt context.Context, chainID string) (context.Context, ledger.TxSimulator, error) {
func startTxSimulation(ctxt context.Context, chainID string, txid string) (context.Context, ledger.TxSimulator, error) {
lgr := peer.GetLedger(chainID)
txsim, err := lgr.NewTxSimulator()
txsim, err := lgr.NewTxSimulator(txid)
if err != nil {
return nil, nil, err
}
......@@ -184,7 +185,7 @@ func startTxSimulation(ctxt context.Context, chainID string) (context.Context, l
return ctxt, txsim, nil
}
func endTxSimulationCDS(chainID string, _ string, txsim ledger.TxSimulator, payload []byte, commit bool, cds *pb.ChaincodeDeploymentSpec, blockNumber uint64) error {
func endTxSimulationCDS(chainID string, txid string, txsim ledger.TxSimulator, payload []byte, commit bool, cds *pb.ChaincodeDeploymentSpec, blockNumber uint64) error {
// get serialized version of the signer
ss, err := signer.Serialize()
if err != nil {
......@@ -206,7 +207,7 @@ func endTxSimulationCDS(chainID string, _ string, txsim ledger.TxSimulator, payl
return endTxSimulation(chainID, lsccid, txsim, payload, commit, prop, blockNumber)
}
func endTxSimulationCIS(chainID string, ccid *pb.ChaincodeID, _ string, txsim ledger.TxSimulator, payload []byte, commit bool, cis *pb.ChaincodeInvocationSpec, blockNumber uint64) error {
func endTxSimulationCIS(chainID string, ccid *pb.ChaincodeID, txid string, txsim ledger.TxSimulator, payload []byte, commit bool, cis *pb.ChaincodeInvocationSpec, blockNumber uint64) error {
// get serialized version of the signer
ss, err := signer.Serialize()
if err != nil {
......@@ -214,10 +215,13 @@ func endTxSimulationCIS(chainID string, ccid *pb.ChaincodeID, _ string, txsim le
}
// get a proposal - we need it to get a transaction
prop, _, err := putils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, chainID, cis, ss)
prop, returnedTxid, err := putils.CreateProposalFromCISAndTxid(txid, common.HeaderType_ENDORSER_TRANSACTION, chainID, cis, ss)
if err != nil {
return err
}
if returnedTxid != txid {
return errors.New("txids are not same")
}
return endTxSimulation(chainID, ccid, txsim, payload, commit, prop, blockNumber)
}
......@@ -236,16 +240,22 @@ func endTxSimulation(chainID string, ccid *pb.ChaincodeID, txsim ledger.TxSimula
txsim.Done()
if lgr := peer.GetLedger(chainID); lgr != nil {
if commit {
var txSimulationResults []byte
var txSimulationResults *ledger.TxSimulationResults
var txSimulationBytes []byte
var err error
txsim.Done()
//get simulation results
if txSimulationResults, err = txsim.GetTxSimulationResults(); err != nil {
return err
}
if txSimulationBytes, err = txSimulationResults.GetPubSimulationBytes(); err != nil {
return nil
}
// assemble a (signed) proposal response message
resp, err := putils.CreateProposalResponse(prop.Header, prop.Payload, &pb.Response{Status: 200}, txSimulationResults, nil, ccid, nil, signer)
resp, err := putils.CreateProposalResponse(prop.Header, prop.Payload, &pb.Response{Status: 200},
txSimulationBytes, nil, ccid, nil, signer)
if err != nil {
return err
}
......@@ -321,15 +331,13 @@ func deploy2(ctx context.Context, cccid *ccprovider.CCContext, chaincodeDeployme
return nil, fmt.Errorf("Error creating lscc spec : %s\n", err)
}
ctx, txsim, err := startTxSimulation(ctx, cccid.ChainID)
uuid := util.GenerateUUID()
cccid.TxID = uuid
ctx, txsim, err := startTxSimulation(ctx, cccid.ChainID, cccid.TxID)
if err != nil {
return nil, fmt.Errorf("Failed to get handle to simulator: %s ", err)
}
uuid := util.GenerateUUID()
cccid.TxID = uuid
defer func() {
//no error, lets try commit
if err == nil {
......@@ -372,7 +380,7 @@ func invokeWithVersion(ctx context.Context, chainID string, version string, spec
uuid = util.GenerateUUID()
var txsim ledger.TxSimulator
ctx, txsim, err = startTxSimulation(ctx, chainID)
ctx, txsim, err = startTxSimulation(ctx, chainID, uuid)
if err != nil {
return nil, uuid, nil, fmt.Errorf("Failed to get handle to simulator: %s ", err)
}
......@@ -542,7 +550,8 @@ func _(chainID string, _ string) error {
// Check the correctness of the final state after transaction execution.
func checkFinalState(cccid *ccprovider.CCContext, a int, b int) error {
_, txsim, err := startTxSimulation(context.Background(), cccid.ChainID)
txid := util.GenerateUUID()
_, txsim, err := startTxSimulation(context.Background(), cccid.ChainID, txid)
if err != nil {
return fmt.Errorf("Failed to get handle to simulator: %s ", err)
}
......
......@@ -1231,7 +1231,7 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) {
Payload: []byte(payload), Txid: msg.Txid}
return
}
txsim2, err2 := lgr.NewTxSimulator()
txsim2, err2 := lgr.NewTxSimulator(msg.Txid)
if err2 != nil {
triggerNextStateMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR,
Payload: []byte(err2.Error()), Txid: msg.Txid}
......
......@@ -61,15 +61,13 @@ func upgrade2(ctx context.Context, cccid *ccprovider.CCContext,
return nil, fmt.Errorf("Error creating lscc spec : %s\n", err)
}
ctx, txsim, err := startTxSimulation(ctx, cccid.ChainID)
uuid := util.GenerateUUID()
cccid.TxID = uuid
ctx, txsim, err := startTxSimulation(ctx, cccid.ChainID, cccid.TxID)
if err != nil {
return nil, fmt.Errorf("Failed to get handle to simulator: %s ", err)
}
uuid := util.GenerateUUID()
cccid.TxID = uuid
defer func() {
//no error, lets try commit
if err == nil {
......
......@@ -24,6 +24,7 @@ import (
"github.com/hyperledger/fabric/common/ledger/testutil"
"github.com/hyperledger/fabric/common/tools/configtxgen/localconfig"
"github.com/hyperledger/fabric/common/tools/configtxgen/provisional"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
"github.com/hyperledger/fabric/core/mocks/validator"
"github.com/hyperledger/fabric/protos/common"
......@@ -50,14 +51,16 @@ func TestKVLedgerBlockStorage(t *testing.T) {
testutil.AssertEquals(t, bcInfo, &common.BlockchainInfo{
Height: 1, CurrentBlockHash: gbHash, PreviousBlockHash: nil})
simulator, _ := ledger.NewTxSimulator()
txid := util.GenerateUUID()
simulator, _ := ledger.NewTxSimulator(txid)
simulator.SetState("ns1", "key1", []byte("value1"))
simulator.SetState("ns1", "key2", []byte("value2"))
simulator.SetState("ns1", "key3", []byte("value3"))
simulator.Done()
simRes, _ := simulator.GetTxSimulationResults()
block1 := testutil.ConstructBlock(t, 1, gbHash, [][]byte{simRes}, true)
simResBytes, _ := simRes.GetPubSimulationBytes()
block1 := testutil.ConstructBlock(t, 1, gbHash, [][]byte{simResBytes}, true)
err = committer.Commit(block1)
assert.NoError(t, err)
......
......@@ -49,15 +49,16 @@ func TestBlockValidation(t *testing.T) {
ledger, _ := ledgermgmt.CreateLedger(gb)
defer ledger.Close()
simulator, _ := ledger.NewTxSimulator()
txid := util2.GenerateUUID()
simulator, _ := ledger.NewTxSimulator(txid)
simulator.SetState("ns1", "key1", []byte("value1"))
simulator.SetState("ns1", "key2", []byte("value2"))
simulator.SetState("ns1", "key3", []byte("value3"))
simulator.Done()
simRes, _ := simulator.GetTxSimulationResults()
_, err := testutil.ConstructBytesProposalResponsePayload("v1", simRes)
pubSimulationResBytes, _ := simRes.GetPubSimulationBytes()
_, err := testutil.ConstructBytesProposalResponsePayload("v1", pubSimulationResBytes)
if err != nil {
t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err)
}
......@@ -69,7 +70,7 @@ func TestBlockValidation(t *testing.T) {
testutil.AssertEquals(t, bcInfo, &common.BlockchainInfo{
Height: 1, CurrentBlockHash: gbHash, PreviousBlockHash: nil})
block := testutil.ConstructBlock(t, 1, gbHash, [][]byte{simRes}, true)
block := testutil.ConstructBlock(t, 1, gbHash, [][]byte{pubSimulationResBytes}, true)
tValidator.Validate(block)
......
......@@ -600,7 +600,7 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
}
func (v *vsccValidatorImpl) VSCCValidateTxForCC(envBytes []byte, txid, chid, vsccName, vsccVer string, policy []byte) error {
ctxt, err := v.ccprovider.GetContext(v.support.Ledger())
ctxt, err := v.ccprovider.GetContext(v.support.Ledger(), txid)
if err != nil {
msg := fmt.Sprintf("Cannot obtain context for txid=%s, err %s", txid, err)
logger.Errorf(msg)
......
......@@ -69,10 +69,10 @@ func createRWset(t *testing.T, ccnames ...string) []byte {
for _, ccname := range ccnames {
rwsetBuilder.AddToWriteSet(ccname, "key", []byte("value"))
}
rwset := rwsetBuilder.GetTxReadWriteSet()
rws, err := rwset.ToProtoBytes()
rwset, err := rwsetBuilder.GetTxSimulationResults()
assert.NoError(t, err)
return rws
rwsetBytes, err := rwset.GetPubSimulationBytes()
return rwsetBytes
}
func getProposal(ccID string) (*peer.Proposal, error) {
......@@ -116,14 +116,17 @@ func putCCInfoWithVSCCAndVer(theLedger ledger.PeerLedger, ccname, vscc, ver stri
cdbytes := utils.MarshalOrPanic(cd)
simulator, err := theLedger.NewTxSimulator()
txid := util.GenerateUUID()
simulator, err := theLedger.NewTxSimulator(txid)
assert.NoError(t, err)
simulator.SetState("lscc", ccname, cdbytes)
simulator.Done()
simRes, err := simulator.GetTxSimulationResults()
assert.NoError(t, err)
block0 := testutil.ConstructBlock(t, 1, []byte("hash"), [][]byte{simRes}, true)
pubSimulationBytes, err := simRes.GetPubSimulationBytes()
assert.NoError(t, err)
block0 := testutil.ConstructBlock(t, 1, []byte("hash"), [][]byte{pubSimulationBytes}, true)
err = theLedger.Commit(block0)
assert.NoError(t, err)
}
......@@ -422,7 +425,7 @@ func (m *mockLedger) GetTxValidationCodeByTxID(txID string) (peer.TxValidationCo
}
// NewTxSimulator creates new transaction simulator
func (m *mockLedger) NewTxSimulator() (ledger.TxSimulator, error) {
func (m *mockLedger) NewTxSimulator(txid string) (ledger.TxSimulator, error) {
args := m.Called()
return args.Get(0).(ledger.TxSimulator), nil
}
......@@ -439,6 +442,33 @@ func (m *mockLedger) NewHistoryQueryExecutor() (ledger.HistoryQueryExecutor, err
return args.Get(0).(ledger.HistoryQueryExecutor), nil
}
// GetPvtDataAndBlockByNum retrieves pvt data and block
func (m *mockLedger) GetPvtDataAndBlockByNum(blockNum uint64, filter ledger.PvtNsCollFilter) (*ledger.BlockAndPvtData, error) {
args := m.Called()
return args.Get(0).(*ledger.BlockAndPvtData), nil
}
// GetPvtDataByNum retrieves the pvt data
func (m *mockLedger) GetPvtDataByNum(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) {
args := m.Called()
return args.Get(0).([]*ledger.TxPvtData), nil
}
// CommitWithPvtData commits the block and the corresponding pvt data in an atomic operation
func (m *mockLedger) CommitWithPvtData(pvtDataAndBlock *ledger.BlockAndPvtData) error {
return nil
}
// PurgePrivateData purges the private data
func (m *mockLedger) PurgePrivateData(maxBlockNumToRetain uint64) error {
return nil
}
// PrivateDataMinBlockNum returns the lowest retained endorsement block height
func (m *mockLedger) PrivateDataMinBlockNum() (uint64, error) {
return 0, nil
}
// Prune prune using policy
func (m *mockLedger) Prune(policy ledger2.PrunePolicy) error {
return nil
......@@ -498,6 +528,26 @@ func (exec *mockQueryExecutor) ExecuteQuery(namespace, query string) (ledger2.Re
return args.Get(0).(ledger2.ResultsIterator), args.Error(1)
}
func (exec *mockQueryExecutor) GetPrivateData(namespace, collection, key string) ([]byte, error) {
args := exec.Called(namespace, collection, key)
return args.Get(0).([]byte), args.Error(1)
}
func (exec *mockQueryExecutor) GetPrivateDataMultipleKeys(namespace, collection string, keys []string) ([][]byte, error) {
args := exec.Called(namespace, collection, keys)
return args.Get(0).([][]byte), args.Error(1)
}
func (exec *mockQueryExecutor) GetPrivateDataRangeScanIterator(namespace, collection, startKey, endKey string) (ledger2.ResultsIterator, error) {
args := exec.Called(namespace, collection, startKey, endKey)
return args.Get(0).(ledger2.ResultsIterator), args.Error(1)
}
func (exec *mockQueryExecutor) ExecuteQueryOnPrivateData(namespace, collection, query string) (ledger2.ResultsIterator, error) {
args := exec.Called(namespace, collection, query)
return args.Get(0).(ledger2.ResultsIterator), args.Error(1)
}
func (exec *mockQueryExecutor) Done() {
}
......
......@@ -424,7 +424,7 @@ func (*ChaincodeData) ProtoMessage() {}
// should be added below if necessary
type ChaincodeProvider interface {
// GetContext returns a ledger context
GetContext(ledger ledger.PeerLedger) (context.Context, error)
GetContext(ledger ledger.PeerLedger, txid string) (context.Context, error)
// GetCCContext returns an opaque chaincode context
GetCCContext(cid, name, version, txid string, syscc bool, signedProp *pb.SignedProposal, prop *pb.Proposal) interface{}
// GetCCValidationInfoFromLSCC returns the VSCC and the policy listed by LSCC for the supplied chaincode
......
......@@ -78,12 +78,12 @@ func (*Endorser) checkEsccAndVscc(prop *pb.Proposal) error {
return nil
}
func (*Endorser) getTxSimulator(ledgername string) (ledger.TxSimulator, error) {
func (*Endorser) getTxSimulator(ledgername string, txid string) (ledger.TxSimulator, error) {
lgr := peer.GetLedger(ledgername)
if lgr == nil {
return nil, fmt.Errorf("channel does not exist: %s", ledgername)
}
return lgr.NewTxSimulator()
return lgr.NewTxSimulator(txid)
}
func (*Endorser) getHistoryQueryExecutor(ledgername string) (ledger.HistoryQueryExecutor, error) {
......@@ -188,7 +188,6 @@ func (e *Endorser) disableJavaCCInst(cid *pb.ChaincodeID, cis *pb.ChaincodeInvoc
if argNo >= len(cis.ChaincodeSpec.Input.Args) {
return errors.New("Too few arguments passed")
}
//the inner dep spec will contain the type
cds, err := putils.GetChaincodeDeploymentSpec(cis.ChaincodeSpec.Input.Args[argNo])
if err != nil {
......@@ -245,7 +244,8 @@ func (e *Endorser) simulateProposal(ctx context.Context, chainID string, txid st
}
//---3. execute the proposal and get simulation results
var simResult []byte
var simResult *ledger.TxSimulationResults
var pubSimResBytes []byte
var res *pb.Response
var ccevent *pb.ChaincodeEvent
res, ccevent, err = e.callChaincode(ctx, chainID, version, txid, signedProp, prop, cis, cid, txsim)
......@@ -258,9 +258,12 @@ func (e *Endorser) simulateProposal(ctx context.Context, chainID string, txid st
if simResult, err = txsim.GetTxSimulationResults(); err != nil {
return nil, nil, nil, nil, err
}
}
return cdLedger, res, simResult, ccevent, nil
if pubSimResBytes, err = simResult.GetPubSimulationBytes(); err != nil {
return nil, nil, nil, nil, err
}
}
return cdLedger, res, pubSimResBytes, ccevent, nil
}
func (e *Endorser) getCDSFromLSCC(ctx context.Context, chainID string, txid string, signedProp *pb.SignedProposal, prop *pb.Proposal, chaincodeID string, txsim ledger.TxSimulator) (*ccprovider.ChaincodeData, error) {
......@@ -434,7 +437,7 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro
var txsim ledger.TxSimulator
var historyQueryExecutor ledger.HistoryQueryExecutor
if chainID != "" {
if txsim, err = e.getTxSimulator(chainID); err != nil {
if txsim, err = e.getTxSimulator(chainID, txid); err != nil {
return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
}
if historyQueryExecutor, err = e.getHistoryQueryExecutor(chainID); err != nil {
......
......@@ -43,18 +43,22 @@ func ConstructAppInstance(ledger ledger.PeerLedger) *App {
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 {
if txSimulator, err = app.ledger.NewTxSimulator(util.GenerateUUID()); err != nil {
return nil, err
}
defer txSimulator.Done()
for accountID, bal := range initialBalances {
txSimulator.SetState(app.name, accountID, toBytes(bal))
}
var txSimulationResults []byte
var txSimulationResults *ledger.TxSimulationResults
var pubSimBytes []byte
if txSimulationResults, err = txSimulator.GetTxSimulationResults(); err != nil {
return nil, err
}
tx := constructTransaction(txSimulationResults)
if pubSimBytes, err = txSimulationResults.GetPubSimulationBytes(); err != nil {
return nil, err
}
tx := constructTransaction(pubSimBytes)
return tx, nil
}
......@@ -63,7 +67,7 @@ func (app *App) TransferFunds(fromAccount string, toAccount string, transferAmt
// act as endorsing peer shim code to simulate a transaction on behalf of chaincode
var txSimulator ledger.TxSimulator
var err error
if txSimulator, err = app.ledger.NewTxSimulator(); err != nil {
if txSimulator, err = app.ledger.NewTxSimulator(util.GenerateUUID()); err != nil {
return nil, err
}
defer txSimulator.Done()
......@@ -84,14 +88,17 @@ func (app *App) TransferFunds(fromAccount string, toAccount string, transferAmt
balTo := toInt(balToBytes)
txSimulator.SetState(app.name, fromAccount, toBytes(balFrom-transferAmt))
txSimulator.SetState(app.name, toAccount, toBytes(balTo+transferAmt))
var txSimulationResults []byte
var txSimulationResults *ledger.TxSimulationResults
if txSimulationResults, err = txSimulator.GetTxSimulationResults(); err != nil {
return nil, err
}
var pubSimBytes []byte
if pubSimBytes, err = txSimulationResults.GetPubSimulationBytes(); err != nil {
return nil, err
}
// act as endorsing peer to create an Action with the SimulationResults
// then act as SDK to create a Transaction with the EndorsedAction
tx := constructTransaction(txSimulationResults)
tx := constructTransaction(pubSimBytes)
return tx, nil
}
......@@ -120,7 +127,7 @@ func constructTransaction(simulationResults []byte) *common.Envelope {
Version: "v1",
}
response := &pb.Response{Status: 200}
txEnv, _, _ := ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), ccid, response, simulationResults, nil, nil)
txEnv, _, _ := ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), ccid, response, simulationResults, "", nil, nil)
return txEnv
}
......
......@@ -22,6 +22,7 @@ import (
"strconv"
"strings"
"github.com/hyperledger/fabric/common/util"
ledger "github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/protos/common"
......@@ -62,19 +63,23 @@ func (marbleApp *MarbleApp) CreateMarble(args []string) (*common.Envelope, error
}
var txSimulator ledger.TxSimulator
if txSimulator, err = marbleApp.ledger.NewTxSimulator(); err != nil {
if txSimulator, err = marbleApp.ledger.NewTxSimulator(util.GenerateUUID()); err != nil {
return nil, err
}
defer txSimulator.Done()
txSimulator.SetState(marbleApp.name, marbleName, marbleJsonBytes)
var txSimulationResults []byte
var txSimulationResults *ledger.TxSimulationResults
if txSimulationResults, err = txSimulator.GetTxSimulationResults(); err != nil {
return nil, err
}
logger.Debugf("CreateMarble() simulation done, packaging into a transaction...")
tx := constructTransaction(txSimulationResults)
var pubSimBytes []byte