github.com/ewagmig/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/validator/statebasedval/state_based_validator_test.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package statebasedval 18 19 import ( 20 "fmt" 21 "os" 22 "testing" 23 24 "github.com/hyperledger/fabric-protos-go/ledger/rwset/kvrwset" 25 "github.com/hyperledger/fabric-protos-go/peer" 26 "github.com/hyperledger/fabric/bccsp/sw" 27 "github.com/hyperledger/fabric/common/flogging" 28 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/privacyenabledstate" 29 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" 30 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb" 31 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/validator/internal" 32 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" 33 "github.com/hyperledger/fabric/core/ledger/util" 34 "github.com/stretchr/testify/assert" 35 ) 36 37 type keyValue struct { 38 namespace string 39 collection string 40 key string 41 keyHash []byte 42 value []byte 43 version *version.Height 44 } 45 46 const ( 47 levelDBtestEnvName = "levelDB_LockBasedTxMgr" 48 couchDBtestEnvName = "couchDB_LockBasedTxMgr" 49 ) 50 51 // Tests will be run against each environment in this array 52 // For example, to skip CouchDB tests, remove &couchDBLockBasedEnv{} 53 var testEnvs = map[string]privacyenabledstate.TestEnv{ 54 levelDBtestEnvName: &privacyenabledstate.LevelDBCommonStorageTestEnv{}, 55 couchDBtestEnvName: &privacyenabledstate.CouchDBCommonStorageTestEnv{}, 56 } 57 58 func TestMain(m *testing.M) { 59 flogging.ActivateSpec("statevalidator,statebasedval,statecouchdb=debug") 60 exitCode := m.Run() 61 for _, testEnv := range testEnvs { 62 testEnv.StopExternalResource() 63 } 64 os.Exit(exitCode) 65 } 66 67 func TestValidatorBulkLoadingOfCache(t *testing.T) { 68 testDBEnv := testEnvs[couchDBtestEnvName] 69 testDBEnv.Init(t) 70 defer testDBEnv.Cleanup() 71 db := testDBEnv.GetDBHandle("testdb") 72 73 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 74 assert.NoError(t, err) 75 76 validator := &Validator{DB: db, Hasher: cryptoProvider} 77 78 //populate db with initial data 79 batch := privacyenabledstate.NewUpdateBatch() 80 81 // Create two public KV pairs 82 pubKV1 := keyValue{namespace: "ns1", key: "key1", value: []byte("value1"), version: version.NewHeight(1, 0)} 83 pubKV2 := keyValue{namespace: "ns1", key: "key2", value: []byte("value2"), version: version.NewHeight(1, 1)} 84 85 // Create two hashed KV pairs 86 hashedKV1 := keyValue{namespace: "ns2", collection: "col1", key: "hashedPvtKey1", 87 keyHash: util.ComputeStringHash("hashedPvtKey1"), value: []byte("value1"), 88 version: version.NewHeight(1, 2)} 89 hashedKV2 := keyValue{namespace: "ns2", collection: "col2", key: "hashedPvtKey2", 90 keyHash: util.ComputeStringHash("hashedPvtKey2"), value: []byte("value2"), 91 version: version.NewHeight(1, 3)} 92 93 // Store the public and hashed KV pairs to DB 94 batch.PubUpdates.Put(pubKV1.namespace, pubKV1.key, pubKV1.value, pubKV1.version) 95 batch.PubUpdates.Put(pubKV2.namespace, pubKV2.key, pubKV2.value, pubKV2.version) 96 batch.HashUpdates.Put(hashedKV1.namespace, hashedKV1.collection, hashedKV1.keyHash, hashedKV1.value, hashedKV1.version) 97 batch.HashUpdates.Put(hashedKV2.namespace, hashedKV2.collection, hashedKV2.keyHash, hashedKV2.value, hashedKV2.version) 98 99 db.ApplyPrivacyAwareUpdates(batch, version.NewHeight(1, 4)) 100 101 // Construct read set for transaction 1. It contains two public KV pairs (pubKV1, pubKV2) and two 102 // hashed KV pairs (hashedKV1, hashedKV2). 103 rwsetBuilder1 := rwsetutil.NewRWSetBuilder() 104 rwsetBuilder1.AddToReadSet(pubKV1.namespace, pubKV1.key, pubKV1.version) 105 rwsetBuilder1.AddToReadSet(pubKV2.namespace, pubKV2.key, pubKV2.version) 106 rwsetBuilder1.AddToHashedReadSet(hashedKV1.namespace, hashedKV1.collection, hashedKV1.key, hashedKV1.version) 107 rwsetBuilder1.AddToHashedReadSet(hashedKV2.namespace, hashedKV2.collection, hashedKV2.key, hashedKV2.version) 108 109 // Construct read set for transaction 1. It contains KV pairs which are not in the state db. 110 rwsetBuilder2 := rwsetutil.NewRWSetBuilder() 111 rwsetBuilder2.AddToReadSet("ns3", "key1", nil) 112 rwsetBuilder2.AddToHashedReadSet("ns3", "col1", "hashedPvtKey1", nil) 113 114 // Construct internal block 115 transRWSets := getTestPubSimulationRWSet(t, rwsetBuilder1, rwsetBuilder2) 116 var trans []*internal.Transaction 117 for i, tranRWSet := range transRWSets { 118 tx := &internal.Transaction{ 119 ID: fmt.Sprintf("txid-%d", i), 120 IndexInBlock: i, 121 ValidationCode: peer.TxValidationCode_VALID, 122 RWSet: tranRWSet, 123 } 124 trans = append(trans, tx) 125 } 126 block := &internal.Block{Num: 1, Txs: trans} 127 128 if validator.DB.IsBulkOptimizable() { 129 130 commonStorageDB := validator.DB.(*privacyenabledstate.CommonStorageDB) 131 bulkOptimizable, _ := commonStorageDB.VersionedDB.(statedb.BulkOptimizable) 132 133 // Clear cache loaded during ApplyPrivacyAwareUpdates() 134 validator.DB.ClearCachedVersions() 135 136 validator.preLoadCommittedVersionOfRSet(block) 137 138 // pubKV1 should be found in cache 139 version, keyFound := bulkOptimizable.GetCachedVersion(pubKV1.namespace, pubKV1.key) 140 assert.True(t, keyFound) 141 assert.Equal(t, pubKV1.version, version) 142 143 // pubKV2 should be found in cache 144 version, keyFound = bulkOptimizable.GetCachedVersion(pubKV2.namespace, pubKV2.key) 145 assert.True(t, keyFound) 146 assert.Equal(t, pubKV2.version, version) 147 148 // [ns3, key1] should be found in cache as it was in the readset of transaction 1 though it is 149 // not in the state db but the version would be nil 150 version, keyFound = bulkOptimizable.GetCachedVersion("ns3", "key1") 151 assert.True(t, keyFound) 152 assert.Nil(t, version) 153 154 // [ns4, key1] should not be found in cache as it was not loaded 155 version, keyFound = bulkOptimizable.GetCachedVersion("ns4", "key1") 156 assert.False(t, keyFound) 157 assert.Nil(t, version) 158 159 // hashedKV1 should be found in cache 160 version, keyFound = validator.DB.GetCachedKeyHashVersion(hashedKV1.namespace, 161 hashedKV1.collection, hashedKV1.keyHash) 162 assert.True(t, keyFound) 163 assert.Equal(t, hashedKV1.version, version) 164 165 // hashedKV2 should be found in cache 166 version, keyFound = validator.DB.GetCachedKeyHashVersion(hashedKV2.namespace, 167 hashedKV2.collection, hashedKV2.keyHash) 168 assert.True(t, keyFound) 169 assert.Equal(t, hashedKV2.version, version) 170 171 // [ns3, col1, hashedPvtKey1] should be found in cache as it was in the readset of transaction 2 though it is 172 // not in the state db 173 version, keyFound = validator.DB.GetCachedKeyHashVersion("ns3", "col1", util.ComputeStringHash("hashedPvtKey1")) 174 assert.True(t, keyFound) 175 assert.Nil(t, version) 176 177 // [ns4, col, key1] should not be found in cache as it was not loaded 178 version, keyFound = validator.DB.GetCachedKeyHashVersion("ns4", "col1", util.ComputeStringHash("key1")) 179 assert.False(t, keyFound) 180 assert.Nil(t, version) 181 182 // Clear cache 183 validator.DB.ClearCachedVersions() 184 185 // pubKV1 should not be found in cache as cahce got emptied 186 version, keyFound = bulkOptimizable.GetCachedVersion(pubKV1.namespace, pubKV1.key) 187 assert.False(t, keyFound) 188 assert.Nil(t, version) 189 190 // [ns3, col1, key1] should not be found in cache as cahce got emptied 191 version, keyFound = validator.DB.GetCachedKeyHashVersion("ns3", "col1", util.ComputeStringHash("hashedPvtKey1")) 192 assert.False(t, keyFound) 193 assert.Nil(t, version) 194 } 195 } 196 197 func TestValidator(t *testing.T) { 198 testDBEnv := testEnvs[levelDBtestEnvName] 199 testDBEnv.Init(t) 200 defer testDBEnv.Cleanup() 201 db := testDBEnv.GetDBHandle("TestDB") 202 203 //populate db with initial data 204 batch := privacyenabledstate.NewUpdateBatch() 205 batch.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0)) 206 batch.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1)) 207 batch.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2)) 208 batch.PubUpdates.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3)) 209 batch.PubUpdates.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4)) 210 db.ApplyPrivacyAwareUpdates(batch, version.NewHeight(1, 4)) 211 212 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 213 assert.NoError(t, err) 214 validator := &Validator{DB: db, Hasher: cryptoProvider} 215 216 //rwset1 should be valid 217 rwsetBuilder1 := rwsetutil.NewRWSetBuilder() 218 rwsetBuilder1.AddToReadSet("ns1", "key1", version.NewHeight(1, 0)) 219 rwsetBuilder1.AddToReadSet("ns2", "key2", nil) 220 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder1), []int{}) 221 222 //rwset2 should not be valid 223 rwsetBuilder2 := rwsetutil.NewRWSetBuilder() 224 rwsetBuilder2.AddToReadSet("ns1", "key1", version.NewHeight(1, 1)) 225 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder2), []int{0}) 226 227 //rwset3 should not be valid 228 rwsetBuilder3 := rwsetutil.NewRWSetBuilder() 229 rwsetBuilder3.AddToReadSet("ns1", "key1", nil) 230 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder3), []int{0}) 231 232 // rwset4 and rwset5 within same block - rwset4 should be valid and makes rwset5 as invalid 233 rwsetBuilder4 := rwsetutil.NewRWSetBuilder() 234 rwsetBuilder4.AddToReadSet("ns1", "key1", version.NewHeight(1, 0)) 235 rwsetBuilder4.AddToWriteSet("ns1", "key1", []byte("value1_new")) 236 237 rwsetBuilder5 := rwsetutil.NewRWSetBuilder() 238 rwsetBuilder5.AddToReadSet("ns1", "key1", version.NewHeight(1, 0)) 239 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder4, rwsetBuilder5), []int{1}) 240 } 241 242 func TestPhantomValidation(t *testing.T) { 243 testDBEnv := testEnvs[levelDBtestEnvName] 244 testDBEnv.Init(t) 245 defer testDBEnv.Cleanup() 246 db := testDBEnv.GetDBHandle("TestDB") 247 248 //populate db with initial data 249 batch := privacyenabledstate.NewUpdateBatch() 250 batch.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0)) 251 batch.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1)) 252 batch.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2)) 253 batch.PubUpdates.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3)) 254 batch.PubUpdates.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4)) 255 db.ApplyPrivacyAwareUpdates(batch, version.NewHeight(1, 4)) 256 257 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 258 assert.NoError(t, err) 259 validator := &Validator{DB: db, Hasher: cryptoProvider} 260 261 //rwset1 should be valid 262 rwsetBuilder1 := rwsetutil.NewRWSetBuilder() 263 rqi1 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: true} 264 rwsetutil.SetRawReads(rqi1, []*kvrwset.KVRead{ 265 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 266 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2))}) 267 rwsetBuilder1.AddToRangeQuerySet("ns1", rqi1) 268 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder1), []int{}) 269 270 //rwset2 should not be valid - Version of key4 changed 271 rwsetBuilder2 := rwsetutil.NewRWSetBuilder() 272 rqi2 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false} 273 rwsetutil.SetRawReads(rqi2, []*kvrwset.KVRead{ 274 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 275 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)), 276 rwsetutil.NewKVRead("key4", version.NewHeight(1, 2))}) 277 rwsetBuilder2.AddToRangeQuerySet("ns1", rqi2) 278 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder2), []int{0}) 279 280 //rwset3 should not be valid - simulate key3 got committed to db 281 rwsetBuilder3 := rwsetutil.NewRWSetBuilder() 282 rqi3 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false} 283 rwsetutil.SetRawReads(rqi3, []*kvrwset.KVRead{ 284 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 285 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3))}) 286 rwsetBuilder3.AddToRangeQuerySet("ns1", rqi3) 287 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder3), []int{0}) 288 289 // //Remove a key in rwset4 and rwset5 should become invalid 290 rwsetBuilder4 := rwsetutil.NewRWSetBuilder() 291 rwsetBuilder4.AddToWriteSet("ns1", "key3", nil) 292 rwsetBuilder5 := rwsetutil.NewRWSetBuilder() 293 rqi5 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false} 294 rwsetutil.SetRawReads(rqi5, []*kvrwset.KVRead{ 295 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 296 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)), 297 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3))}) 298 rwsetBuilder5.AddToRangeQuerySet("ns1", rqi5) 299 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder4, rwsetBuilder5), []int{1}) 300 301 //Add a key in rwset6 and rwset7 should become invalid 302 rwsetBuilder6 := rwsetutil.NewRWSetBuilder() 303 rwsetBuilder6.AddToWriteSet("ns1", "key2_1", []byte("value2_1")) 304 305 rwsetBuilder7 := rwsetutil.NewRWSetBuilder() 306 rqi7 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key4", ItrExhausted: false} 307 rwsetutil.SetRawReads(rqi7, []*kvrwset.KVRead{ 308 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 309 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)), 310 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3))}) 311 rwsetBuilder7.AddToRangeQuerySet("ns1", rqi7) 312 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder6, rwsetBuilder7), []int{1}) 313 } 314 315 func TestPhantomHashBasedValidation(t *testing.T) { 316 testDBEnv := testEnvs[levelDBtestEnvName] 317 testDBEnv.Init(t) 318 defer testDBEnv.Cleanup() 319 db := testDBEnv.GetDBHandle("TestDB") 320 321 //populate db with initial data 322 batch := privacyenabledstate.NewUpdateBatch() 323 batch.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0)) 324 batch.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1)) 325 batch.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2)) 326 batch.PubUpdates.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3)) 327 batch.PubUpdates.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4)) 328 batch.PubUpdates.Put("ns1", "key6", []byte("value6"), version.NewHeight(1, 5)) 329 batch.PubUpdates.Put("ns1", "key7", []byte("value7"), version.NewHeight(1, 6)) 330 batch.PubUpdates.Put("ns1", "key8", []byte("value8"), version.NewHeight(1, 7)) 331 batch.PubUpdates.Put("ns1", "key9", []byte("value9"), version.NewHeight(1, 8)) 332 db.ApplyPrivacyAwareUpdates(batch, version.NewHeight(1, 8)) 333 334 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 335 assert.NoError(t, err) 336 validator := &Validator{DB: db, Hasher: cryptoProvider} 337 338 rwsetBuilder1 := rwsetutil.NewRWSetBuilder() 339 rqi1 := &kvrwset.RangeQueryInfo{StartKey: "key2", EndKey: "key9", ItrExhausted: true} 340 kvReadsDuringSimulation1 := []*kvrwset.KVRead{ 341 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 342 rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)), 343 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3)), 344 rwsetutil.NewKVRead("key5", version.NewHeight(1, 4)), 345 rwsetutil.NewKVRead("key6", version.NewHeight(1, 5)), 346 rwsetutil.NewKVRead("key7", version.NewHeight(1, 6)), 347 rwsetutil.NewKVRead("key8", version.NewHeight(1, 7)), 348 } 349 rwsetutil.SetMerkelSummary(rqi1, buildTestHashResults(t, 2, kvReadsDuringSimulation1)) 350 rwsetBuilder1.AddToRangeQuerySet("ns1", rqi1) 351 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder1), []int{}) 352 353 rwsetBuilder2 := rwsetutil.NewRWSetBuilder() 354 rqi2 := &kvrwset.RangeQueryInfo{StartKey: "key1", EndKey: "key9", ItrExhausted: false} 355 kvReadsDuringSimulation2 := []*kvrwset.KVRead{ 356 rwsetutil.NewKVRead("key1", version.NewHeight(1, 0)), 357 rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)), 358 rwsetutil.NewKVRead("key3", version.NewHeight(1, 1)), 359 rwsetutil.NewKVRead("key4", version.NewHeight(1, 3)), 360 rwsetutil.NewKVRead("key5", version.NewHeight(1, 4)), 361 rwsetutil.NewKVRead("key6", version.NewHeight(1, 5)), 362 rwsetutil.NewKVRead("key7", version.NewHeight(1, 6)), 363 rwsetutil.NewKVRead("key8", version.NewHeight(1, 7)), 364 rwsetutil.NewKVRead("key9", version.NewHeight(1, 8)), 365 } 366 rwsetutil.SetMerkelSummary(rqi2, buildTestHashResults(t, 2, kvReadsDuringSimulation2)) 367 rwsetBuilder2.AddToRangeQuerySet("ns1", rqi2) 368 checkValidation(t, validator, getTestPubSimulationRWSet(t, rwsetBuilder2), []int{0}) 369 } 370 371 func checkValidation(t *testing.T, val *Validator, transRWSets []*rwsetutil.TxRwSet, expectedInvalidTxIndexes []int) { 372 var trans []*internal.Transaction 373 for i, tranRWSet := range transRWSets { 374 tx := &internal.Transaction{ 375 ID: fmt.Sprintf("txid-%d", i), 376 IndexInBlock: i, 377 ValidationCode: peer.TxValidationCode_VALID, 378 RWSet: tranRWSet, 379 } 380 trans = append(trans, tx) 381 } 382 block := &internal.Block{Num: 1, Txs: trans} 383 _, err := val.ValidateAndPrepareBatch(block, true) 384 assert.NoError(t, err) 385 t.Logf("block.Txs[0].ValidationCode = %d", block.Txs[0].ValidationCode) 386 var invalidTxs []int 387 for _, tx := range block.Txs { 388 if tx.ValidationCode != peer.TxValidationCode_VALID { 389 invalidTxs = append(invalidTxs, tx.IndexInBlock) 390 } 391 } 392 assert.Equal(t, len(expectedInvalidTxIndexes), len(invalidTxs)) 393 assert.ElementsMatch(t, invalidTxs, expectedInvalidTxIndexes) 394 } 395 396 func buildTestHashResults(t *testing.T, maxDegree int, kvReads []*kvrwset.KVRead) *kvrwset.QueryReadsMerkleSummary { 397 if len(kvReads) <= maxDegree { 398 t.Fatal("This method should be called with number of KVReads more than maxDegree; Else, hashing won't be performedrwset") 399 } 400 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 401 assert.NoError(t, err) 402 helper, _ := rwsetutil.NewRangeQueryResultsHelper(true, uint32(maxDegree), cryptoProvider) 403 for _, kvRead := range kvReads { 404 helper.AddResult(kvRead) 405 } 406 _, h, err := helper.Done() 407 assert.NoError(t, err) 408 assert.NotNil(t, h) 409 return h 410 } 411 412 func getTestPubSimulationRWSet(t *testing.T, builders ...*rwsetutil.RWSetBuilder) []*rwsetutil.TxRwSet { 413 var pubRWSets []*rwsetutil.TxRwSet 414 for _, b := range builders { 415 s, e := b.GetTxSimulationResults() 416 assert.NoError(t, e) 417 sBytes, err := s.GetPubSimulationBytes() 418 assert.NoError(t, err) 419 pubRWSet := &rwsetutil.TxRwSet{} 420 assert.NoError(t, pubRWSet.FromProtoBytes(sBytes)) 421 pubRWSets = append(pubRWSets, pubRWSet) 422 } 423 return pubRWSets 424 }