func (blockchain *blockchain) addPersistenceChangesForNewBlock(ctx context.Context, block *protos.Block, stateHash []byte, writeBatch *gorocksdb.WriteBatch) (uint64, error) { block = blockchain.buildBlock(block, stateHash) if block.NonHashData == nil { block.NonHashData = &protos.NonHashData{LocalLedgerCommitTimestamp: util.CreateUtcTimestamp()} } else { block.NonHashData.LocalLedgerCommitTimestamp = util.CreateUtcTimestamp() } blockNumber := blockchain.size blockHash, err := block.GetHash() if err != nil { return 0, err } blockBytes, blockBytesErr := block.Bytes() if blockBytesErr != nil { return 0, blockBytesErr } writeBatch.PutCF(db.GetDBHandle().BlockchainCF, encodeBlockNumberDBKey(blockNumber), blockBytes) writeBatch.PutCF(db.GetDBHandle().BlockchainCF, blockCountKey, encodeUint64(blockNumber+1)) if blockchain.indexer.isSynchronous() { blockchain.indexer.createIndexesSync(block, blockNumber, blockHash, writeBatch) } blockchain.lastProcessedBlock = &lastProcessedBlock{block, blockNumber, blockHash} return blockNumber, nil }
func (blockchain *blockchain) persistRawBlock(block *protos.Block, blockNumber uint64) error { blockBytes, blockBytesErr := block.Bytes() if blockBytesErr != nil { return blockBytesErr } writeBatch := gorocksdb.NewWriteBatch() defer writeBatch.Destroy() writeBatch.PutCF(db.GetDBHandle().BlockchainCF, encodeBlockNumberDBKey(blockNumber), blockBytes) // Need to check as we suport out of order blocks in cases such as block/state synchronization. This is // really blockchain height, not size. if blockchain.getSize() < blockNumber+1 { sizeBytes := encodeUint64(blockNumber + 1) writeBatch.PutCF(db.GetDBHandle().BlockchainCF, blockCountKey, sizeBytes) blockchain.size = blockNumber + 1 } blockHash, err := block.GetHash() if err != nil { return err } if blockchain.indexer.isSynchronous() { blockchain.indexer.createIndexesSync(block, blockNumber, blockHash, writeBatch) } opt := gorocksdb.NewDefaultWriteOptions() defer opt.Destroy() err = db.GetDBHandle().DB.Write(opt, writeBatch) if err != nil { return err } return nil }
func fetchDataNodesFromDBFor(bucketKey *bucketKey) (dataNodes, error) { logger.Debug("Fetching from DB data nodes for bucket [%s]", bucketKey) openchainDB := db.GetDBHandle() itr := openchainDB.GetStateCFIterator() defer itr.Close() minimumDataKeyBytes := minimumPossibleDataKeyBytesFor(bucketKey) var dataNodes dataNodes itr.Seek(minimumDataKeyBytes) for ; itr.Valid(); itr.Next() { k := itr.Key().Data() v := itr.Value().Data() // making a copy of key-value bytes because, underlying key bytes are reused by itr. //Did not observe the same behaviour for value but for now making copy for both key and value bytes keyBytes := statemgmt.Copy(k) valueBytes := statemgmt.Copy(v) dataKey := newDataKeyFromEncodedBytes(keyBytes) logger.Debug("Retrieved data key [%s] from DB for bucket [%s]", dataKey, bucketKey) if !dataKey.getBucketKey().equals(bucketKey) { logger.Debug("Data key [%s] from DB does not belong to bucket = [%s]. Stopping further iteration and returning results [%v]", dataKey, bucketKey, dataNodes) return dataNodes, nil } dataNode := unmarshalDataNode(dataKey, valueBytes) logger.Debug("Data node [%s] from DB belongs to bucket = [%s]. Including the key in results...", dataNode, bucketKey) dataNodes = append(dataNodes, dataNode) } logger.Debug("Returning results [%v]", dataNodes) return dataNodes, nil }
func (stateTrie *StateTrie) AddChangesForPersistence(writeBatch *gorocksdb.WriteBatch) error { if stateTrie.recomputeCryptoHash { _, err := stateTrie.ComputeCryptoHash() if err != nil { return err } } if stateTrie.trieDelta == nil { stateTrieLogger.Info("trieDelta is nil. Not writing anything to DB") return nil } openchainDB := db.GetDBHandle() lowestLevel := stateTrie.trieDelta.getLowestLevel() for level := lowestLevel; level >= 0; level-- { changedNodes := stateTrie.trieDelta.deltaMap[level] for _, changedNode := range changedNodes { if changedNode.markedForDeletion { writeBatch.DeleteCF(openchainDB.StateCF, changedNode.trieKey.getEncodedBytes()) continue } serializedContent, err := changedNode.marshal() if err != nil { return err } writeBatch.PutCF(openchainDB.StateCF, changedNode.trieKey.getEncodedBytes(), serializedContent) } } stateTrieLogger.Debug("Added changes to DB") return nil }
// CommitTxBatch - gets invoked when the current transaction-batch needs to be committed // This function returns successfully iff the transactions details and state changes (that // may have happened during execution of this transaction-batch) have been committed to permanent storage func (ledger *Ledger) CommitTxBatch(id interface{}, transactions []*protos.Transaction, proof []byte) error { err := ledger.checkValidIDCommitORRollback(id) if err != nil { return err } success := true defer ledger.resetForNextTxGroup(success) defer ledger.blockchain.blockPersistenceStatus(success) stateHash, err := ledger.state.GetHash() if err != nil { success = false return err } writeBatch := gorocksdb.NewWriteBatch() block := protos.NewBlock(transactions) newBlockNumber, err := ledger.blockchain.addPersistenceChangesForNewBlock(context.TODO(), block, stateHash, writeBatch) if err != nil { success = false return err } ledger.state.AddChangesForPersistence(newBlockNumber, writeBatch) opt := gorocksdb.NewDefaultWriteOptions() dbErr := db.GetDBHandle().DB.Write(opt, writeBatch) if dbErr != nil { success = false return dbErr } producer.Send(producer.CreateBlockEvent(block)) return nil }
func newStateSnapshotIterator(snapshot *gorocksdb.Snapshot) (*StateSnapshotIterator, error) { dbItr := db.GetDBHandle().GetStateCFSnapshotIterator(snapshot) dbItr.SeekToFirst() // skip the root key, because, the value test in Next method is misleading for root key as the value field dbItr.Next() return &StateSnapshotIterator{dbItr, nil, nil}, nil }
// Functions for persisting and retrieving index data func addIndexDataForPersistence(block *protos.Block, blockNumber uint64, blockHash []byte, writeBatch *gorocksdb.WriteBatch) error { openchainDB := db.GetDBHandle() cf := openchainDB.IndexesCF // add blockhash -> blockNumber indexLogger.Debug("Indexing block number [%d] by hash = [%x]", blockNumber, blockHash) writeBatch.PutCF(cf, encodeBlockHashKey(blockHash), encodeBlockNumber(blockNumber)) addressToTxIndexesMap := make(map[string][]uint64) addressToChaincodeIDsMap := make(map[string][]*protos.ChaincodeID) transactions := block.GetTransactions() for txIndex, tx := range transactions { // add TxUUID -> (blockNumber,indexWithinBlock) writeBatch.PutCF(cf, encodeTxUUIDKey(tx.Uuid), encodeBlockNumTxIndex(blockNumber, uint64(txIndex))) txExecutingAddress := getTxExecutingAddress(tx) addressToTxIndexesMap[txExecutingAddress] = append(addressToTxIndexesMap[txExecutingAddress], uint64(txIndex)) switch tx.Type { case protos.Transaction_CHAINCODE_NEW, protos.Transaction_CHAINCODE_UPDATE: authroizedAddresses, chaincodeID := getAuthorisedAddresses(tx) for _, authroizedAddress := range authroizedAddresses { addressToChaincodeIDsMap[authroizedAddress] = append(addressToChaincodeIDsMap[authroizedAddress], chaincodeID) } } } for address, txsIndexes := range addressToTxIndexesMap { writeBatch.PutCF(cf, encodeAddressBlockNumCompositeKey(address, blockNumber), encodeListTxIndexes(txsIndexes)) } return nil }
func TestStateSnapshotIterator(t *testing.T) { testDBWrapper.CreateFreshDB(t) stateTrieTestWrapper := newStateTrieTestWrapper(t) stateTrie := stateTrieTestWrapper.stateTrie stateDelta := statemgmt.NewStateDelta() // insert keys stateDelta.Set("chaincodeID1", "key1", []byte("value1"), nil) stateDelta.Set("chaincodeID2", "key2", []byte("value2"), nil) stateDelta.Set("chaincodeID3", "key3", []byte("value3"), nil) stateDelta.Set("chaincodeID4", "key4", []byte("value4"), nil) stateDelta.Set("chaincodeID5", "key5", []byte("value5"), nil) stateDelta.Set("chaincodeID6", "key6", []byte("value6"), nil) stateTrie.PrepareWorkingSet(stateDelta) stateTrieTestWrapper.PersistChangesAndResetInMemoryChanges() //check that the key is persisted testutil.AssertEquals(t, stateTrieTestWrapper.Get("chaincodeID1", "key1"), []byte("value1")) testutil.AssertEquals(t, stateTrieTestWrapper.Get("chaincodeID2", "key2"), []byte("value2")) testutil.AssertEquals(t, stateTrieTestWrapper.Get("chaincodeID3", "key3"), []byte("value3")) testutil.AssertEquals(t, stateTrieTestWrapper.Get("chaincodeID4", "key4"), []byte("value4")) testutil.AssertEquals(t, stateTrieTestWrapper.Get("chaincodeID5", "key5"), []byte("value5")) testutil.AssertEquals(t, stateTrieTestWrapper.Get("chaincodeID6", "key6"), []byte("value6")) // take db snapeshot dbSnapshot := db.GetDBHandle().GetSnapshot() stateDelta1 := statemgmt.NewStateDelta() // delete a few keys stateDelta1.Delete("chaincodeID1", "key1", nil) stateDelta1.Delete("chaincodeID3", "key3", nil) stateDelta1.Delete("chaincodeID4", "key4", nil) stateDelta1.Delete("chaincodeID6", "key6", nil) // update remaining keys stateDelta1.Set("chaincodeID2", "key2", []byte("value2_new"), nil) stateDelta1.Set("chaincodeID5", "key5", []byte("value5_new"), nil) stateTrie.PrepareWorkingSet(stateDelta1) stateTrieTestWrapper.PersistChangesAndResetInMemoryChanges() //check that the keys are updated testutil.AssertNil(t, stateTrieTestWrapper.Get("chaincodeID1", "key1")) testutil.AssertNil(t, stateTrieTestWrapper.Get("chaincodeID3", "key3")) testutil.AssertNil(t, stateTrieTestWrapper.Get("chaincodeID4", "key4")) testutil.AssertNil(t, stateTrieTestWrapper.Get("chaincodeID6", "key6")) testutil.AssertEquals(t, stateTrieTestWrapper.Get("chaincodeID2", "key2"), []byte("value2_new")) testutil.AssertEquals(t, stateTrieTestWrapper.Get("chaincodeID5", "key5"), []byte("value5_new")) itr, err := newStateSnapshotIterator(dbSnapshot) testutil.AssertNoError(t, err, "Error while getting state snapeshot iterator") stateDeltaFromSnapshot := statemgmt.NewStateDelta() for itr.Next() { keyBytes, valueBytes := itr.GetRawKeyValue() t.Logf("key=[%s], value=[%s]", string(keyBytes), string(valueBytes)) chaincodeID, key := statemgmt.DecodeCompositeKey(keyBytes) stateDeltaFromSnapshot.Set(chaincodeID, key, valueBytes, nil) } testutil.AssertEquals(t, stateDelta, stateDeltaFromSnapshot) }
func fetchBlockNumberByBlockHashFromDB(blockHash []byte) (uint64, error) { blockNumberBytes, err := db.GetDBHandle().GetFromIndexesCF(encodeBlockHashKey(blockHash)) if err != nil { return 0, err } blockNumber := decodeBlockNumber(blockNumberBytes) return blockNumber, nil }
// DeleteState deletes ALL state keys/values from the DB. This is generally // only used during state synchronization when creating a new state from // a snapshot. func (state *State) DeleteState() error { state.ClearInMemoryChanges(false) err := db.GetDBHandle().DeleteState() if err != nil { logger.Error("Error deleting state", err) } return err }
// GetStateSnapshot returns a point-in-time view of the global state for the current block. This // should be used when transfering the state from one peer to another peer. You must call // stateSnapshot.Release() once you are done with the snapsnot to free up resources. func (ledger *Ledger) GetStateSnapshot() (*state.StateSnapshot, error) { dbSnapshot := db.GetDBHandle().GetSnapshot() blockNumber, err := fetchBlockchainSizeFromSnapshot(dbSnapshot) if err != nil { dbSnapshot.Release() return nil, err } return ledger.state.GetSnapshot(blockNumber, dbSnapshot) }
func fetchTransactionIndexByUUIDFromDB(txUUID string) (uint64, uint64, error) { blockNumTxIndexBytes, err := db.GetDBHandle().GetFromIndexesCF(encodeTxUUIDKey(txUUID)) if err != nil { return 0, 0, err } if blockNumTxIndexBytes == nil { return 0, 0, ErrResourceNotFound } return decodeBlockNumTxIndex(blockNumTxIndexBytes) }
func fetchBlockchainSizeFromDB() (uint64, error) { bytes, err := db.GetDBHandle().GetFromBlockchainCF(blockCountKey) if err != nil { return 0, err } if bytes == nil { return 0, nil } return decodeToUint64(bytes), nil }
// CommitStateDelta commits the changes from state.ApplyStateDelta to the // DB. func (state *State) CommitStateDelta() error { if state.updateStateImpl { state.stateImpl.PrepareWorkingSet(state.stateDelta) state.updateStateImpl = false } writeBatch := gorocksdb.NewWriteBatch() state.stateImpl.AddChangesForPersistence(writeBatch) opt := gorocksdb.NewDefaultWriteOptions() return db.GetDBHandle().DB.Write(opt, writeBatch) }
func fetchBlockFromDB(blockNumber uint64) (*protos.Block, error) { blockBytes, err := db.GetDBHandle().GetFromBlockchainCF(encodeBlockNumberDBKey(blockNumber)) if err != nil { return nil, err } if blockBytes == nil { return nil, nil } return protos.UnmarshallBlock(blockBytes) }
func fetchBlockchainSizeFromSnapshot(snapshot *gorocksdb.Snapshot) (uint64, error) { blockNumberBytes, err := db.GetDBHandle().GetFromBlockchainCFSnapshot(snapshot, blockCountKey) if err != nil { return 0, err } var blockNumber uint64 if blockNumberBytes != nil { blockNumber = decodeToUint64(blockNumberBytes) } return blockNumber, nil }
func newRangeScanIterator(chaincodeID string, startKey string, endKey string) (*RangeScanIterator, error) { dbItr := db.GetDBHandle().GetStateCFIterator() itr := &RangeScanIterator{ dbItr: dbItr, chaincodeID: chaincodeID, startKey: startKey, endKey: endKey, } itr.seekForStartKeyWithinBucket(1) return itr, nil }
func fetchBucketNodeFromDB(bucketKey *bucketKey) (*bucketNode, error) { openchainDB := db.GetDBHandle() nodeBytes, err := openchainDB.GetFromStateCF(bucketKey.getEncodedBytes()) if err != nil { return nil, err } if util.IsNil(nodeBytes) { return nil, nil } return unmarshalBucketNode(bucketKey, nodeBytes), nil }
// FetchStateDeltaFromDB fetches the StateDelta corrsponding to given blockNumber func (state *State) FetchStateDeltaFromDB(blockNumber uint64) (*statemgmt.StateDelta, error) { stateDeltaBytes, err := db.GetDBHandle().GetFromStateDeltaCF(encodeStateDeltaKey(blockNumber)) if err != nil { return nil, err } if stateDeltaBytes == nil { return nil, nil } stateDelta := statemgmt.NewStateDelta() stateDelta.Unmarshal(stateDeltaBytes) return stateDelta, nil }
func fetchLastIndexedBlockNumFromDB() (zerothBlockIndexed bool, lastIndexedBlockNum uint64, err error) { lastIndexedBlockNumberBytes, err := db.GetDBHandle().GetFromIndexesCF(lastIndexedBlockKey) if err != nil { return } if lastIndexedBlockNumberBytes == nil { return } lastIndexedBlockNum = decodeBlockNumber(lastIndexedBlockNumberBytes) zerothBlockIndexed = true return }
// GetStateSnapshot returns a point-in-time view of the global state for the current block. This // should be used when transfering the state from one peer to another peer. You must call // stateSnapshot.Release() once you are done with the snapsnot to free up resources. func (ledger *Ledger) GetStateSnapshot() (*state.StateSnapshot, error) { dbSnapshot := db.GetDBHandle().GetSnapshot() blockHeight, err := fetchBlockchainSizeFromSnapshot(dbSnapshot) if err != nil { dbSnapshot.Release() return nil, err } if 0 == blockHeight { dbSnapshot.Release() return nil, fmt.Errorf("Blockchain has no blocks, cannot determine block number") } return ledger.state.GetSnapshot(blockHeight-1, dbSnapshot) }
// createIndexes adds entries into db for creating indexes on various atributes func (indexer *blockchainIndexerAsync) createIndexesInternal(block *protos.Block, blockNumber uint64, blockHash []byte) error { openchainDB := db.GetDBHandle() writeBatch := gorocksdb.NewWriteBatch() addIndexDataForPersistence(block, blockNumber, blockHash, writeBatch) writeBatch.PutCF(openchainDB.IndexesCF, lastIndexedBlockKey, encodeBlockNumber(blockNumber)) opt := gorocksdb.NewDefaultWriteOptions() err := openchainDB.DB.Write(opt, writeBatch) if err != nil { return err } indexer.indexerState.blockIndexed(blockNumber) return nil }
func (stateImpl *StateImpl) addDataNodeChangesForPersistence(writeBatch *gorocksdb.WriteBatch) { openchainDB := db.GetDBHandle() affectedBuckets := stateImpl.dataNodesDelta.getAffectedBuckets() for _, affectedBucket := range affectedBuckets { dataNodes := stateImpl.dataNodesDelta.getSortedDataNodesFor(affectedBucket) for _, dataNode := range dataNodes { if util.IsNil(dataNode.value) { writeBatch.DeleteCF(openchainDB.StateCF, dataNode.dataKey.getEncodedBytes()) } else { writeBatch.PutCF(openchainDB.StateCF, dataNode.dataKey.getEncodedBytes(), dataNode.value) } } } }
func (stateImpl *StateImpl) addBucketNodeChangesForPersistence(writeBatch *gorocksdb.WriteBatch) { openchainDB := db.GetDBHandle() secondLastLevel := conf.getLowestLevel() - 1 for level := secondLastLevel; level >= 0; level-- { bucketNodes := stateImpl.bucketTreeDelta.getBucketNodesAt(level) for _, bucketNode := range bucketNodes { if bucketNode.markedForDeletion { writeBatch.DeleteCF(openchainDB.StateCF, bucketNode.bucketKey.getEncodedBytes()) } else { writeBatch.PutCF(openchainDB.StateCF, bucketNode.bucketKey.getEncodedBytes(), bucketNode.marshal()) } writeBatch.PutCF(openchainDB.StateCF, bucketNode.bucketKey.getEncodedBytes(), bucketNode.marshal()) } } }
func TestStateSnapshotIterator(t *testing.T) { testDBWrapper.CreateFreshDB(t) stateImplTestWrapper := newStateImplTestWrapper(t) stateDelta := statemgmt.NewStateDelta() // insert keys stateDelta.Set("chaincodeID1", "key1", []byte("value1"), nil) stateDelta.Set("chaincodeID2", "key2", []byte("value2"), nil) stateDelta.Set("chaincodeID3", "key3", []byte("value3"), nil) stateDelta.Set("chaincodeID4", "key4", []byte("value4"), nil) stateDelta.Set("chaincodeID5", "key5", []byte("value5"), nil) stateDelta.Set("chaincodeID6", "key6", []byte("value6"), nil) stateImplTestWrapper.prepareWorkingSet(stateDelta) stateImplTestWrapper.persistChangesAndResetInMemoryChanges() //check that the key is persisted testutil.AssertEquals(t, stateImplTestWrapper.get("chaincodeID5", "key5"), []byte("value5")) // take db snapeshot dbSnapshot := db.GetDBHandle().GetSnapshot() // delete keys stateDelta.Delete("chaincodeID1", "key1", nil) stateDelta.Delete("chaincodeID2", "key2", nil) stateDelta.Delete("chaincodeID3", "key3", nil) stateDelta.Delete("chaincodeID4", "key4", nil) stateDelta.Delete("chaincodeID5", "key5", nil) stateDelta.Delete("chaincodeID6", "key6", nil) stateImplTestWrapper.prepareWorkingSet(stateDelta) stateImplTestWrapper.persistChangesAndResetInMemoryChanges() //check that the key is deleted testutil.AssertNil(t, stateImplTestWrapper.get("chaincodeID5", "key5")) itr, err := newStateSnapshotIterator(dbSnapshot) testutil.AssertNoError(t, err, "Error while getting state snapeshot iterator") numKeys := 0 for itr.Next() { key, value := itr.GetRawKeyValue() t.Logf("key=[%s], value=[%s]", string(key), string(value)) numKeys++ } testutil.AssertEquals(t, numKeys, 6) }
// AddChangesForPersistence - method implementation for interface 'statemgmt.HashableState' func (impl *StateImpl) AddChangesForPersistence(writeBatch *gorocksdb.WriteBatch) error { delta := impl.stateDelta if delta == nil { return nil } openchainDB := db.GetDBHandle() updatedChaincodeIds := delta.GetUpdatedChaincodeIds(false) for _, updatedChaincodeID := range updatedChaincodeIds { updates := delta.GetUpdates(updatedChaincodeID) for updatedKey, value := range updates { compositeKey := statemgmt.ConstructCompositeKey(updatedChaincodeID, updatedKey) if value.IsDelete() { writeBatch.DeleteCF(openchainDB.StateCF, compositeKey) } else { writeBatch.PutCF(openchainDB.StateCF, compositeKey, value.GetValue()) } } } return nil }
func fetchTrieNodeFromDB(key *trieKey) (*trieNode, error) { stateTrieLogger.Debug("Enter fetchTrieNodeFromDB() for trieKey [%s]", key) openchainDB := db.GetDBHandle() trieNodeBytes, err := openchainDB.GetFromStateCF(key.getEncodedBytes()) if err != nil { stateTrieLogger.Error("Error in retrieving trie node from DB for triekey [%s]. Error:%s", key, err) return nil, err } if trieNodeBytes == nil { return nil, nil } trieNode, err := unmarshalTrieNode(key, trieNodeBytes) if err != nil { stateTrieLogger.Error("Error in unmarshalling trie node for triekey [%s]. Error:%s", key, err) return nil, err } stateTrieLogger.Debug("Exit fetchTrieNodeFromDB() for trieKey [%s]", key) return trieNode, nil }
// CommitTxBatch - gets invoked when the current transaction-batch needs to be committed // This function returns successfully iff the transactions details and state changes (that // may have happened during execution of this transaction-batch) have been committed to permanent storage func (ledger *Ledger) CommitTxBatch(id interface{}, transactions []*protos.Transaction, transactionResults []*protos.TransactionResult, metadata []byte) error { err := ledger.checkValidIDCommitORRollback(id) if err != nil { return err } stateHash, err := ledger.state.GetHash() if err != nil { ledger.resetForNextTxGroup(false) ledger.blockchain.blockPersistenceStatus(false) return err } writeBatch := gorocksdb.NewWriteBatch() defer writeBatch.Destroy() block := protos.NewBlock(transactions, metadata) block.NonHashData = &protos.NonHashData{TransactionResults: transactionResults} newBlockNumber, err := ledger.blockchain.addPersistenceChangesForNewBlock(context.TODO(), block, stateHash, writeBatch) if err != nil { ledger.resetForNextTxGroup(false) ledger.blockchain.blockPersistenceStatus(false) return err } ledger.state.AddChangesForPersistence(newBlockNumber, writeBatch) opt := gorocksdb.NewDefaultWriteOptions() defer opt.Destroy() dbErr := db.GetDBHandle().DB.Write(opt, writeBatch) if dbErr != nil { ledger.resetForNextTxGroup(false) ledger.blockchain.blockPersistenceStatus(false) return dbErr } ledger.resetForNextTxGroup(true) ledger.blockchain.blockPersistenceStatus(true) sendProducerBlockEvent(block) return nil }
// AddChangesForPersistence adds key-value pairs to writeBatch func (state *State) AddChangesForPersistence(blockNumber uint64, writeBatch *gorocksdb.WriteBatch) { logger.Debug("state.addChangesForPersistence()...start") if state.updateStateImpl { state.stateImpl.PrepareWorkingSet(state.stateDelta) state.updateStateImpl = false } state.stateImpl.AddChangesForPersistence(writeBatch) serializedStateDelta := state.stateDelta.Marshal() cf := db.GetDBHandle().StateDeltaCF logger.Debug("Adding state-delta corresponding to block number[%d]", blockNumber) writeBatch.PutCF(cf, encodeStateDeltaKey(blockNumber), serializedStateDelta) if blockNumber >= state.historyStateDeltaSize { blockNumberToDelete := blockNumber - state.historyStateDeltaSize logger.Debug("Deleting state-delta corresponding to block number[%d]", blockNumberToDelete) writeBatch.DeleteCF(cf, encodeStateDeltaKey(blockNumberToDelete)) } else { logger.Debug("Not deleting previous state-delta. Block number [%d] is smaller than historyStateDeltaSize [%d]", blockNumber, state.historyStateDeltaSize) } logger.Debug("state.addChangesForPersistence()...finished") }
func newStateSnapshotIterator(snapshot *gorocksdb.Snapshot) (*StateSnapshotIterator, error) { dbItr := db.GetDBHandle().GetStateCFSnapshotIterator(snapshot) dbItr.Seek([]byte{0x01}) dbItr.Prev() return &StateSnapshotIterator{dbItr}, nil }