github.com/renegr87/renegr87@v2.1.1+incompatible/core/ledger/kvledger/tests/customtx_processor_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package tests
     8  
     9  import (
    10  	"fmt"
    11  	"testing"
    12  
    13  	"github.com/hyperledger/fabric-protos-go/common"
    14  	protopeer "github.com/hyperledger/fabric-protos-go/peer"
    15  	"github.com/hyperledger/fabric/bccsp/sw"
    16  	"github.com/hyperledger/fabric/core/ledger"
    17  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
    18  	"github.com/hyperledger/fabric/core/ledger/mock"
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  func TestReadWriteCustomTxProcessor(t *testing.T) {
    23  	fakeTxProcessor := &mock.CustomTxProcessor{}
    24  
    25  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    26  	assert.NoError(t, err)
    27  
    28  	env := newEnvWithInitializer(
    29  		t,
    30  		&ledgermgmt.Initializer{
    31  			CustomTxProcessors: map[common.HeaderType]ledger.CustomTxProcessor{
    32  				100: fakeTxProcessor,
    33  			},
    34  			Hasher: cryptoProvider,
    35  		},
    36  	)
    37  	defer env.cleanup()
    38  	env.initLedgerMgmt()
    39  
    40  	h := env.newTestHelperCreateLgr("ledger1", t)
    41  	h.simulateDataTx("tx0", func(s *simulator) {
    42  		s.setState("ns", "key1", "value1")
    43  		s.setState("ns", "key2", "value2")
    44  		s.setState("ns", "key3", "value3")
    45  	})
    46  	h.cutBlockAndCommitLegacy() // commit block-1 to populate initial state
    47  
    48  	valueCounter := 0
    49  	fakeTxProcessor.GenerateSimulationResultsStub =
    50  		// tx processor reads and modifies key1
    51  		func(txEnvelop *common.Envelope, s ledger.TxSimulator, initializingLedger bool) error {
    52  			valKey1, err := s.GetState("ns", "key1")
    53  			assert.NoError(t, err)
    54  			assert.Equal(t, []byte("value1"), valKey1)
    55  			valueCounter++
    56  			return s.SetState("ns", "key1", []byte(fmt.Sprintf("value1_%d", valueCounter)))
    57  		}
    58  
    59  	// block-2 with two post order transactions
    60  	h.addPostOrderTx("tx1", 100)
    61  	h.addPostOrderTx("tx2", 100)
    62  	h.cutBlockAndCommitLegacy()
    63  
    64  	// Tx1 should be valid and tx2 should be marked as invalid because, tx1 has already modified key1
    65  	// in the same block
    66  	h.verifyTxValidationCode("tx1", protopeer.TxValidationCode_VALID)
    67  	h.verifyTxValidationCode("tx2", protopeer.TxValidationCode_MVCC_READ_CONFLICT)
    68  	h.verifyPubState("ns", "key1", "value1_1")
    69  }
    70  
    71  func TestRangeReadAndWriteCustomTxProcessor(t *testing.T) {
    72  	fakeTxProcessor1 := &mock.CustomTxProcessor{}
    73  	fakeTxProcessor2 := &mock.CustomTxProcessor{}
    74  	fakeTxProcessor3 := &mock.CustomTxProcessor{}
    75  
    76  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    77  	assert.NoError(t, err)
    78  
    79  	env := newEnvWithInitializer(
    80  		t,
    81  		&ledgermgmt.Initializer{
    82  			CustomTxProcessors: map[common.HeaderType]ledger.CustomTxProcessor{
    83  				101: fakeTxProcessor1,
    84  				102: fakeTxProcessor2,
    85  				103: fakeTxProcessor3,
    86  			},
    87  			Hasher: cryptoProvider,
    88  		},
    89  	)
    90  	defer env.cleanup()
    91  	env.initLedgerMgmt()
    92  
    93  	h := env.newTestHelperCreateLgr("ledger1", t)
    94  	h.simulateDataTx("tx0", func(s *simulator) {
    95  		s.setState("ns", "key1", "value1")
    96  		s.setState("ns", "key2", "value2")
    97  		s.setState("ns", "key3", "value3")
    98  	})
    99  	h.cutBlockAndCommitLegacy() // commit block-1 to populate initial state
   100  
   101  	fakeTxProcessor1.GenerateSimulationResultsStub =
   102  		// tx processor for txtype 101 sets key1
   103  		func(txEnvelop *common.Envelope, s ledger.TxSimulator, initializingLedger bool) error {
   104  			return s.SetState("ns", "key1", []byte("value1_new"))
   105  		}
   106  
   107  	fakeTxProcessor2.GenerateSimulationResultsStub =
   108  		// tx processor for txtype 102 reads a range (that covers key1) and sets key2
   109  		func(txEnvelop *common.Envelope, s ledger.TxSimulator, initializingLedger bool) error {
   110  			itr, err := s.GetStateRangeScanIterator("ns", "key1", "key2")
   111  			assert.NoError(t, err)
   112  			for {
   113  				res, err := itr.Next()
   114  				assert.NoError(t, err)
   115  				if res == nil {
   116  					break
   117  				}
   118  			}
   119  			return s.SetState("ns", "key2", []byte("value2_new"))
   120  		}
   121  
   122  	fakeTxProcessor3.GenerateSimulationResultsStub =
   123  		// tx processor for txtype 103 reads a range (that does not include key1) and sets key2
   124  		func(txEnvelop *common.Envelope, s ledger.TxSimulator, initializingLedger bool) error {
   125  			itr, err := s.GetStateRangeScanIterator("ns", "key2", "key3")
   126  			assert.NoError(t, err)
   127  			for {
   128  				res, err := itr.Next()
   129  				assert.NoError(t, err)
   130  				if res == nil {
   131  					break
   132  				}
   133  			}
   134  			return s.SetState("ns", "key3", []byte("value3_new"))
   135  		}
   136  
   137  	// block-2 with three post order transactions
   138  	h.addPostOrderTx("tx1", 101)
   139  	h.addPostOrderTx("tx2", 102)
   140  	h.addPostOrderTx("tx3", 103)
   141  	h.cutBlockAndCommitLegacy()
   142  
   143  	// Tx1 should be valid and tx2 should be marked as invalid because, tx1 has already modified key1
   144  	// in the same block (and tx2 does a range iteration that includes key1)
   145  	// However, tx3 should be fine as this performs a range itertaes that does not include key1
   146  	h.verifyTxValidationCode("tx1", protopeer.TxValidationCode_VALID)
   147  	h.verifyTxValidationCode("tx2", protopeer.TxValidationCode_PHANTOM_READ_CONFLICT)
   148  	h.verifyTxValidationCode("tx3", protopeer.TxValidationCode_VALID)
   149  	h.verifyPubState("ns", "key1", "value1_new")
   150  	h.verifyPubState("ns", "key2", "value2")
   151  	h.verifyPubState("ns", "key3", "value3_new")
   152  }