github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/core/multiple_psm_test.go (about)

     1  package core
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"math/big"
     7  	"testing"
     8  
     9  	"github.com/kisexp/xdchain/common"
    10  	"github.com/kisexp/xdchain/consensus/ethash"
    11  	"github.com/kisexp/xdchain/core/mps"
    12  	"github.com/kisexp/xdchain/core/rawdb"
    13  	"github.com/kisexp/xdchain/core/state"
    14  	"github.com/kisexp/xdchain/core/types"
    15  	"github.com/kisexp/xdchain/core/vm"
    16  	"github.com/kisexp/xdchain/crypto"
    17  	"github.com/kisexp/xdchain/params"
    18  	"github.com/kisexp/xdchain/private"
    19  	"github.com/kisexp/xdchain/private/engine"
    20  	"github.com/kisexp/xdchain/rpc"
    21  	"github.com/golang/mock/gomock"
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  const (
    26  	// testCode is the testing contract binary code which will initialises some
    27  	// variables in constructor
    28  	testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032"
    29  
    30  	// testGas is the gas required for contract deployment.
    31  	testGas = 144109
    32  )
    33  
    34  var (
    35  	testKey, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    36  	testAddress = crypto.PubkeyToAddress(testKey.PublicKey)
    37  )
    38  
    39  func buildTestChain(n int, config *params.ChainConfig) ([]*types.Block, map[common.Hash]*types.Block, *BlockChain) {
    40  	testdb := rawdb.NewMemoryDatabase()
    41  	genesis := GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000))
    42  	blocks, _ := GenerateChain(config, genesis, ethash.NewFaker(), testdb, n, func(i int, block *BlockGen) {
    43  		block.SetCoinbase(common.Address{0})
    44  
    45  		signer := types.QuorumPrivateTxSigner{}
    46  		tx, err := types.SignTx(types.NewContractCreation(block.TxNonce(testAddress), big.NewInt(0), testGas, nil, common.FromHex(testCode)), signer, testKey)
    47  		if err != nil {
    48  			panic(err)
    49  		}
    50  		block.AddTx(tx)
    51  	})
    52  
    53  	hashes := make([]common.Hash, n+1)
    54  	hashes[len(hashes)-1] = genesis.Hash()
    55  	blockm := make(map[common.Hash]*types.Block, n+1)
    56  	blockm[genesis.Hash()] = genesis
    57  	for i, b := range blocks {
    58  		hashes[len(hashes)-i-2] = b.Hash()
    59  		blockm[b.Hash()] = b
    60  	}
    61  
    62  	blockchain, _ := NewBlockChain(testdb, nil, config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
    63  	return blocks, blockm, blockchain
    64  }
    65  
    66  func TestMultiplePSMRStateCreated(t *testing.T) {
    67  	mockCtrl := gomock.NewController(t)
    68  	defer mockCtrl.Finish()
    69  
    70  	mockptm := private.NewMockPrivateTransactionManager(mockCtrl)
    71  
    72  	saved := private.P
    73  	defer func() {
    74  		private.P = saved
    75  	}()
    76  	private.P = mockptm
    77  
    78  	mockpsm := mps.NewMockPrivateStateManager(mockCtrl)
    79  
    80  	mockptm.EXPECT().Receive(gomock.Not(common.EncryptedPayloadHash{})).Return("", []string{"psi1", "psi2"}, common.FromHex(testCode), nil, nil).AnyTimes()
    81  	mockptm.EXPECT().Receive(common.EncryptedPayloadHash{}).Return("", []string{}, common.EncryptedPayloadHash{}.Bytes(), nil, nil).AnyTimes()
    82  	mockptm.EXPECT().HasFeature(engine.MultiplePrivateStates).Return(true)
    83  	mockptm.EXPECT().Groups().Return(PrivacyGroups, nil).AnyTimes()
    84  
    85  	mockpsm.EXPECT().ResolveForManagedParty("psi1").Return(&PSI1PSM, nil).AnyTimes()
    86  	mockpsm.EXPECT().ResolveForManagedParty("psi2").Return(&PSI2PSM, nil).AnyTimes()
    87  	mockpsm.EXPECT().PSIs().Return([]types.PrivateStateIdentifier{PSI1PSM.ID, PSI2PSM.ID, types.DefaultPrivateStateIdentifier, types.ToPrivateStateIdentifier("other")}).AnyTimes()
    88  
    89  	blocks, blockmap, blockchain := buildTestChain(2, params.QuorumMPSTestChainConfig)
    90  	cache := state.NewDatabase(blockchain.db)
    91  	blockchain.privateStateManager = mockpsm
    92  
    93  	for _, block := range blocks {
    94  		parent := blockmap[block.ParentHash()]
    95  		statedb, _ := state.New(parent.Root(), blockchain.StateCache(), nil)
    96  		mockpsm.EXPECT().StateRepository(gomock.Any()).Return(mps.NewMultiplePrivateStateRepository(blockchain.db, cache, common.Hash{})).AnyTimes()
    97  
    98  		privateStateRepo, err := blockchain.PrivateStateManager().StateRepository(parent.Root())
    99  		assert.NoError(t, err)
   100  
   101  		publicReceipts, privateReceipts, _, _, _ := blockchain.Processor().Process(block, statedb, privateStateRepo, vm.Config{})
   102  
   103  		//managed states tests
   104  		for _, privateReceipt := range privateReceipts {
   105  			expectedContractAddress := privateReceipt.ContractAddress
   106  
   107  			emptyState, _ := privateStateRepo.DefaultState()
   108  			assert.True(t, emptyState.Exist(expectedContractAddress))
   109  			assert.Equal(t, emptyState.GetCodeSize(expectedContractAddress), 0)
   110  			ps1, _ := privateStateRepo.StatePSI(types.PrivateStateIdentifier("psi1"))
   111  			assert.True(t, ps1.Exist(expectedContractAddress))
   112  			assert.NotEqual(t, ps1.GetCodeSize(expectedContractAddress), 0)
   113  			ps2, _ := privateStateRepo.StatePSI(types.PrivateStateIdentifier("psi2"))
   114  			assert.True(t, ps2.Exist(expectedContractAddress))
   115  			assert.NotEqual(t, ps2.GetCodeSize(expectedContractAddress), 0)
   116  
   117  		}
   118  		//CommitAndWrite to db
   119  		privateStateRepo.CommitAndWrite(false, block)
   120  
   121  		//managed states test
   122  		for _, privateReceipt := range privateReceipts {
   123  			expectedContractAddress := privateReceipt.ContractAddress
   124  			latestBlockRoot := block.Root()
   125  			_, privDb, _ := blockchain.StateAtPSI(latestBlockRoot, types.ToPrivateStateIdentifier("empty"))
   126  			assert.True(t, privDb.Exist(expectedContractAddress))
   127  			assert.Equal(t, privDb.GetCodeSize(expectedContractAddress), 0)
   128  			//contract exists on both psi states
   129  			_, privDb, _ = blockchain.StateAtPSI(latestBlockRoot, types.PrivateStateIdentifier("psi1"))
   130  			assert.True(t, privDb.Exist(expectedContractAddress))
   131  			assert.NotEqual(t, privDb.GetCodeSize(expectedContractAddress), 0)
   132  			_, privDb, _ = blockchain.StateAtPSI(latestBlockRoot, types.PrivateStateIdentifier("psi2"))
   133  			assert.True(t, privDb.Exist(expectedContractAddress))
   134  			assert.NotEqual(t, privDb.GetCodeSize(expectedContractAddress), 0)
   135  			//contract should exist on default private state but no contract code
   136  			_, privDb, _ = blockchain.StateAtPSI(latestBlockRoot, types.DefaultPrivateStateIdentifier)
   137  			assert.True(t, privDb.Exist(expectedContractAddress))
   138  			assert.Equal(t, privDb.GetCodeSize(expectedContractAddress), 0)
   139  			//contract should exist on random state but no contract code
   140  			_, privDb, _ = blockchain.StateAtPSI(latestBlockRoot, types.ToPrivateStateIdentifier("other"))
   141  			assert.True(t, privDb.Exist(expectedContractAddress))
   142  			assert.Equal(t, privDb.GetCodeSize(expectedContractAddress), 0)
   143  		}
   144  
   145  		//mergeReceipts test
   146  		for _, pubReceipt := range publicReceipts {
   147  			assert.Equal(t, 0, len(pubReceipt.PSReceipts))
   148  		}
   149  		for _, privReceipt := range privateReceipts {
   150  			assert.Equal(t, 2, len(privReceipt.PSReceipts))
   151  			assert.NotEqual(t, nil, privReceipt.PSReceipts["psi1"])
   152  			assert.NotEqual(t, nil, privReceipt.PSReceipts["psi2"])
   153  		}
   154  
   155  		allReceipts := privateStateRepo.MergeReceipts(publicReceipts, privateReceipts)
   156  		for _, receipt := range allReceipts {
   157  			assert.Equal(t, 3, len(receipt.PSReceipts))
   158  			assert.NotEqual(t, nil, receipt.PSReceipts["empty"])
   159  			assert.NotEqual(t, nil, receipt.PSReceipts["psi1"])
   160  			assert.NotEqual(t, nil, receipt.PSReceipts["psi2"])
   161  		}
   162  	}
   163  }
   164  
   165  func TestMPSReset(t *testing.T) {
   166  	mockCtrl := gomock.NewController(t)
   167  	defer mockCtrl.Finish()
   168  
   169  	mockptm := private.NewMockPrivateTransactionManager(mockCtrl)
   170  
   171  	saved := private.P
   172  	defer func() {
   173  		private.P = saved
   174  	}()
   175  	private.P = mockptm
   176  
   177  	mockpsm := mps.NewMockPrivateStateManager(mockCtrl)
   178  
   179  	mockptm.EXPECT().Receive(gomock.Not(common.EncryptedPayloadHash{})).Return("", []string{"psi1", "psi2"}, common.FromHex(testCode), nil, nil).AnyTimes()
   180  	mockptm.EXPECT().Receive(common.EncryptedPayloadHash{}).Return("", []string{}, common.EncryptedPayloadHash{}.Bytes(), nil, nil).AnyTimes()
   181  	mockptm.EXPECT().HasFeature(engine.MultiplePrivateStates).Return(true)
   182  	mockptm.EXPECT().Groups().Return(PrivacyGroups, nil).AnyTimes()
   183  
   184  	mockpsm.EXPECT().ResolveForManagedParty("psi1").Return(&PSI1PSM, nil).AnyTimes()
   185  	mockpsm.EXPECT().ResolveForManagedParty("psi2").Return(&PSI2PSM, nil).AnyTimes()
   186  	mockpsm.EXPECT().PSIs().Return([]types.PrivateStateIdentifier{PSI1PSM.ID, PSI2PSM.ID}).AnyTimes()
   187  
   188  	blocks, blockmap, blockchain := buildTestChain(2, params.QuorumMPSTestChainConfig)
   189  	blockchain.privateStateManager = mockpsm
   190  	cache := state.NewDatabase(blockchain.db)
   191  
   192  	for _, block := range blocks {
   193  		parent := blockmap[block.ParentHash()]
   194  		statedb, _ := state.New(parent.Root(), blockchain.StateCache(), nil)
   195  		mockpsm.EXPECT().StateRepository(gomock.Any()).Return(mps.NewMultiplePrivateStateRepository(blockchain.db, cache, common.Hash{})).AnyTimes()
   196  
   197  		privateStateRepo, err := blockchain.PrivateStateManager().StateRepository(parent.Root())
   198  		assert.NoError(t, err)
   199  
   200  		_, privateReceipts, _, _, _ := blockchain.Processor().Process(block, statedb, privateStateRepo, vm.Config{})
   201  
   202  		for _, privateReceipt := range privateReceipts {
   203  			expectedContractAddress := privateReceipt.ContractAddress
   204  
   205  			emptyState, _ := privateStateRepo.DefaultState()
   206  			assert.True(t, emptyState.Exist(expectedContractAddress))
   207  			assert.Equal(t, emptyState.GetCodeSize(expectedContractAddress), 0)
   208  			ps1, _ := privateStateRepo.StatePSI(types.PrivateStateIdentifier("psi1"))
   209  			assert.True(t, ps1.Exist(expectedContractAddress))
   210  			assert.NotEqual(t, ps1.GetCodeSize(expectedContractAddress), 0)
   211  			ps2, _ := privateStateRepo.StatePSI(types.PrivateStateIdentifier("psi2"))
   212  			assert.True(t, ps2.Exist(expectedContractAddress))
   213  			assert.NotEqual(t, ps2.GetCodeSize(expectedContractAddress), 0)
   214  
   215  			privateStateRepo.Reset()
   216  
   217  			emptyState, _ = privateStateRepo.DefaultState()
   218  			assert.False(t, emptyState.Exist(expectedContractAddress))
   219  			assert.Equal(t, emptyState.GetCodeSize(expectedContractAddress), 0)
   220  			ps1, _ = privateStateRepo.StatePSI(types.PrivateStateIdentifier("psi1"))
   221  			assert.False(t, ps1.Exist(expectedContractAddress))
   222  			assert.Equal(t, ps1.GetCodeSize(expectedContractAddress), 0)
   223  			ps2, _ = privateStateRepo.StatePSI(types.PrivateStateIdentifier("psi2"))
   224  			assert.False(t, ps2.Exist(expectedContractAddress))
   225  			assert.Equal(t, ps2.GetCodeSize(expectedContractAddress), 0)
   226  		}
   227  	}
   228  }
   229  
   230  func TestPrivateStateMetadataResolver(t *testing.T) {
   231  	mockCtrl := gomock.NewController(t)
   232  	defer mockCtrl.Finish()
   233  
   234  	mockptm := private.NewMockPrivateTransactionManager(mockCtrl)
   235  
   236  	saved := private.P
   237  	defer func() {
   238  		private.P = saved
   239  	}()
   240  	private.P = mockptm
   241  
   242  	mockptm.EXPECT().Receive(gomock.Not(common.EncryptedPayloadHash{})).Return("", []string{"AAA", "CCC"}, common.FromHex(testCode), nil, nil).AnyTimes()
   243  	mockptm.EXPECT().Receive(common.EncryptedPayloadHash{}).Return("", []string{}, common.EncryptedPayloadHash{}.Bytes(), nil, nil).AnyTimes()
   244  	mockptm.EXPECT().HasFeature(engine.MultiplePrivateStates).Return(true)
   245  	mockptm.EXPECT().Groups().Return(PrivacyGroups, nil).AnyTimes()
   246  
   247  	_, _, blockchain := buildTestChain(1, params.QuorumMPSTestChainConfig)
   248  
   249  	mpsm := blockchain.privateStateManager
   250  
   251  	psm1, _ := mpsm.ResolveForManagedParty("AAA")
   252  	psm2, _ := mpsm.ResolveForManagedParty("CCC")
   253  	_, err := mpsm.ResolveForManagedParty("TEST")
   254  	assert.Equal(t, psm1, privacyGroupToPrivateStateMetadata(PG1))
   255  	assert.Equal(t, psm2, privacyGroupToPrivateStateMetadata(PG2))
   256  	assert.Error(t, err, "unable to find private state metadata for managed party TEST")
   257  
   258  	ctx := rpc.WithPrivateStateIdentifier(context.Background(), types.ToPrivateStateIdentifier("RG1"))
   259  	psm1, _ = mpsm.ResolveForUserContext(ctx)
   260  	assert.Equal(t, psm1, privacyGroupToPrivateStateMetadata(PG1))
   261  	ctx = rpc.WithPrivateStateIdentifier(context.Background(), types.ToPrivateStateIdentifier("OTHER"))
   262  	_, err = mpsm.ResolveForUserContext(ctx)
   263  	assert.Error(t, err, "unable to find private state for context psi OTHER")
   264  	_, err = mpsm.ResolveForUserContext(context.Background())
   265  	assert.Error(t, err, "unable to find private state for context psi private")
   266  
   267  	assert.Contains(t, mpsm.PSIs(), types.PrivateStateIdentifier("RG1"))
   268  	assert.Contains(t, mpsm.PSIs(), types.PrivateStateIdentifier("RG2"))
   269  	assert.Contains(t, mpsm.PSIs(), types.PrivateStateIdentifier("LEGACY1"))
   270  }
   271  
   272  var PSI1PSM = mps.PrivateStateMetadata{
   273  	ID:          "psi1",
   274  	Name:        "psi1",
   275  	Description: "private state 1",
   276  	Type:        mps.Resident,
   277  	Addresses:   nil,
   278  }
   279  
   280  var PSI2PSM = mps.PrivateStateMetadata{
   281  	ID:          "psi2",
   282  	Name:        "psi2",
   283  	Description: "private state 2",
   284  	Type:        mps.Resident,
   285  	Addresses:   nil,
   286  }
   287  
   288  var PG1 = engine.PrivacyGroup{
   289  	Type:           "RESIDENT",
   290  	Name:           "RG1",
   291  	PrivacyGroupId: "RG1",
   292  	Description:    "Resident Group 1",
   293  	From:           "",
   294  	Members:        []string{"AAA", "BBB"},
   295  }
   296  
   297  var PG2 = engine.PrivacyGroup{
   298  	Type:           "RESIDENT",
   299  	Name:           "RG2",
   300  	PrivacyGroupId: "RG2",
   301  	Description:    "Resident Group 2",
   302  	From:           "",
   303  	Members:        []string{"CCC", "DDD"},
   304  }
   305  
   306  var PrivacyGroups = []engine.PrivacyGroup{
   307  	{
   308  		Type:           "RESIDENT",
   309  		Name:           "RG1",
   310  		PrivacyGroupId: base64.StdEncoding.EncodeToString([]byte("RG1")),
   311  		Description:    "Resident Group 1",
   312  		From:           "",
   313  		Members:        []string{"AAA", "BBB"},
   314  	},
   315  	{
   316  		Type:           "RESIDENT",
   317  		Name:           "RG2",
   318  		PrivacyGroupId: base64.StdEncoding.EncodeToString([]byte("RG2")),
   319  		Description:    "Resident Group 2",
   320  		From:           "",
   321  		Members:        []string{"CCC", "DDD"},
   322  	},
   323  	{
   324  		Type:           "LEGACY",
   325  		Name:           "LEGACY1",
   326  		PrivacyGroupId: "LEGACY1",
   327  		Description:    "Legacy Group 1",
   328  		From:           "",
   329  		Members:        []string{"LEG1", "LEG2"},
   330  	},
   331  }