// TestDeletes tests deteles func TestDeletes(t *testing.T, db statedb.VersionedDB) { db.Open() defer db.Close() batch := statedb.NewUpdateBatch() vv1 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)} vv2 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 2)} vv3 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 3)} vv4 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 4)} batch.Put("ns", "key1", vv1.Value, vv1.Version) batch.Put("ns", "key2", vv2.Value, vv2.Version) batch.Put("ns", "key3", vv2.Value, vv3.Version) batch.Put("ns", "key4", vv2.Value, vv4.Version) batch.Delete("ns", "key3", version.NewHeight(1, 5)) savePoint := version.NewHeight(1, 5) err := db.ApplyUpdates(batch, savePoint) testutil.AssertNoError(t, err, "") vv, _ := db.GetState("ns", "key2") testutil.AssertEquals(t, vv, &vv2) vv, err = db.GetState("ns", "key3") testutil.AssertNoError(t, err, "") testutil.AssertNil(t, vv) batch = statedb.NewUpdateBatch() batch.Delete("ns", "key2", version.NewHeight(1, 6)) err = db.ApplyUpdates(batch, savePoint) testutil.AssertNoError(t, err, "") vv, err = db.GetState("ns", "key2") testutil.AssertNoError(t, err, "") testutil.AssertNil(t, vv) }
// TestIterator tests the iterator func TestIterator(t *testing.T, db statedb.VersionedDB) { db.Open() defer db.Close() batch := statedb.NewUpdateBatch() batch.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1)) batch.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2)) batch.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 3)) batch.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 4)) batch.Put("ns2", "key5", []byte("value5"), version.NewHeight(1, 5)) batch.Put("ns2", "key6", []byte("value6"), version.NewHeight(1, 6)) batch.Put("ns3", "key7", []byte("value7"), version.NewHeight(1, 7)) savePoint := version.NewHeight(2, 5) db.ApplyUpdates(batch, savePoint) itr1, _ := db.GetStateRangeScanIterator("ns1", "key1", "") testItr(t, itr1, []string{"key1", "key2", "key3", "key4"}) itr2, _ := db.GetStateRangeScanIterator("ns1", "key2", "key3") testItr(t, itr2, []string{"key2"}) itr3, _ := db.GetStateRangeScanIterator("ns1", "", "") testItr(t, itr3, []string{"key1", "key2", "key3", "key4"}) itr4, _ := db.GetStateRangeScanIterator("ns2", "", "") testItr(t, itr4, []string{"key5", "key6"}) }
// TestBasicRW tests basic read-write func TestBasicRW(t *testing.T, db statedb.VersionedDB) { db.Open() defer db.Close() val, err := db.GetState("ns", "key1") testutil.AssertNoError(t, err, "") testutil.AssertNil(t, val) batch := statedb.NewUpdateBatch() vv1 := statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)} vv2 := statedb.VersionedValue{Value: []byte("value2"), Version: version.NewHeight(1, 2)} vv3 := statedb.VersionedValue{Value: []byte("value3"), Version: version.NewHeight(1, 3)} vv4 := statedb.VersionedValue{Value: []byte{}, Version: version.NewHeight(1, 4)} batch.Put("ns1", "key1", vv1.Value, vv1.Version) batch.Put("ns1", "key2", vv2.Value, vv2.Version) batch.Put("ns2", "key3", vv3.Value, vv3.Version) batch.Put("ns2", "key4", vv4.Value, vv4.Version) savePoint := version.NewHeight(2, 5) db.ApplyUpdates(batch, savePoint) vv, _ := db.GetState("ns1", "key1") testutil.AssertEquals(t, vv, &vv1) vv, _ = db.GetState("ns2", "key4") testutil.AssertEquals(t, vv, &vv4) sp, err := db.GetLatestSavePoint() testutil.AssertNoError(t, err, "") testutil.AssertEquals(t, sp, savePoint) }
// ValidateAndPrepareBatch implements method in Validator interface func (v *Validator) ValidateAndPrepareBatch(block *common.Block, doMVCCValidation bool) (*statedb.UpdateBatch, error) { logger.Debugf("New block arrived for validation:%#v, doMVCCValidation=%t", block, doMVCCValidation) var valid bool updates := statedb.NewUpdateBatch() logger.Debugf("Validating a block with [%d] transactions", len(block.Data.Data)) txsFilter := util.NewFilterBitArrayFromBytes(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) for txIndex, envBytes := range block.Data.Data { if txsFilter.IsSet(uint(txIndex)) { // Skiping invalid transaction logger.Debug("Skipping transaction marked as invalid, txIndex=", txIndex) continue } // extract actions from the envelope message respPayload, err := putils.GetActionFromEnvelope(envBytes) if err != nil { return nil, err } //preparation for extracting RWSet from transaction txRWSet := &rwset.TxReadWriteSet{} // Get the Result from the Action // and then Unmarshal it into a TxReadWriteSet using custom unmarshalling if err = txRWSet.Unmarshal(respPayload.Results); err != nil { return nil, err } // trace the first 2000 characters of RWSet only, in case it is huge if logger.IsEnabledFor(logging.DEBUG) { txRWSetString := txRWSet.String() if len(txRWSetString) < 2000 { logger.Debugf("validating txRWSet:[%s]", txRWSetString) } else { logger.Debugf("validating txRWSet:[%s...]", txRWSetString[0:2000]) } } if !doMVCCValidation { valid = true } else if valid, err = v.validateTx(txRWSet, updates); err != nil { return nil, err } if valid { committingTxHeight := version.NewHeight(block.Header.Number, uint64(txIndex+1)) addWriteSetToBatch(txRWSet, committingTxHeight, updates) } else { // Unset bit in byte array corresponded to the invalid transaction txsFilter.Set(uint(txIndex)) } } block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter.ToBytes() return updates, nil }
func TestValidator(t *testing.T) { testDBEnv := stateleveldb.NewTestVDBEnv(t, testDBPath) defer testDBEnv.Cleanup() db := testDBEnv.DB //populate db with initial data batch := statedb.NewUpdateBatch() batch.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1)) batch.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2)) batch.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 3)) batch.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 4)) batch.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 5)) db.ApplyUpdates(batch, version.NewHeight(1, 5)) validator := NewValidator(db) //rwset1 should be valid rwset1 := rwset.NewRWSet() rwset1.AddToReadSet("ns1", "key1", version.NewHeight(1, 1)) rwset1.AddToReadSet("ns2", "key2", nil) checkValidation(t, validator, []*rwset.RWSet{rwset1}, []int{}) //rwset2 should not be valid rwset2 := rwset.NewRWSet() rwset2.AddToReadSet("ns1", "key1", version.NewHeight(1, 2)) checkValidation(t, validator, []*rwset.RWSet{rwset2}, []int{0}) //rwset3 should not be valid rwset3 := rwset.NewRWSet() rwset3.AddToReadSet("ns1", "key1", nil) checkValidation(t, validator, []*rwset.RWSet{rwset3}, []int{0}) // rwset4 and rwset5 within same block - rwset4 should be valid and makes rwset5 as invalid rwset4 := rwset.NewRWSet() rwset4.AddToReadSet("ns1", "key1", version.NewHeight(1, 1)) rwset4.AddToWriteSet("ns1", "key1", []byte("value1_new")) rwset5 := rwset.NewRWSet() rwset5.AddToReadSet("ns1", "key1", version.NewHeight(1, 1)) checkValidation(t, validator, []*rwset.RWSet{rwset4, rwset5}, []int{1}) }