github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/kvledger/kv_ledger_provider.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package kvledger 8 9 import ( 10 "bytes" 11 "fmt" 12 13 "github.com/golang/protobuf/proto" 14 "github.com/hyperledger/fabric-protos-go/common" 15 "github.com/hyperledger/fabric/common/ledger/dataformat" 16 "github.com/hyperledger/fabric/common/ledger/util/leveldbhelper" 17 "github.com/hyperledger/fabric/core/ledger" 18 "github.com/hyperledger/fabric/core/ledger/confighistory" 19 "github.com/hyperledger/fabric/core/ledger/kvledger/bookkeeping" 20 "github.com/hyperledger/fabric/core/ledger/kvledger/history" 21 "github.com/hyperledger/fabric/core/ledger/kvledger/msgs" 22 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/privacyenabledstate" 23 "github.com/hyperledger/fabric/core/ledger/ledgerstorage" 24 "github.com/hyperledger/fabric/core/ledger/pvtdatastorage" 25 "github.com/hyperledger/fabric/protoutil" 26 "github.com/pkg/errors" 27 "github.com/syndtr/goleveldb/leveldb" 28 ) 29 30 var ( 31 // ErrLedgerIDExists is thrown by a CreateLedger call if a ledger with the given id already exists 32 ErrLedgerIDExists = errors.New("LedgerID already exists") 33 // ErrNonExistingLedgerID is thrown by an OpenLedger call if a ledger with the given id does not exist 34 ErrNonExistingLedgerID = errors.New("LedgerID does not exist") 35 // ErrLedgerNotOpened is thrown by a CloseLedger call if a ledger with the given id has not been opened 36 ErrLedgerNotOpened = errors.New("ledger is not opened yet") 37 // ErrInactiveLedger is thrown by an OpenLedger call if a ledger with the given id is not active 38 ErrInactiveLedger = errors.New("Ledger is not active") 39 40 underConstructionLedgerKey = []byte("underConstructionLedgerKey") 41 // ledgerKeyPrefix is the prefix for each ledger key in idStore db 42 ledgerKeyPrefix = []byte{'l'} 43 // ledgerKeyStop is the end key when querying idStore db by ledger key 44 ledgerKeyStop = []byte{'l' + 1} 45 // metadataKeyPrefix is the prefix for each metadata key in idStore db 46 metadataKeyPrefix = []byte{'s'} 47 // metadataKeyStop is the end key when querying idStore db by metadata key 48 metadataKeyStop = []byte{'s' + 1} 49 50 // formatKey 51 formatKey = []byte("f") 52 ) 53 54 // Provider implements interface ledger.PeerLedgerProvider 55 type Provider struct { 56 idStore *idStore 57 ledgerStoreProvider *ledgerstorage.Provider 58 vdbProvider privacyenabledstate.DBProvider 59 historydbProvider *history.DBProvider 60 configHistoryMgr confighistory.Mgr 61 stateListeners []ledger.StateListener 62 bookkeepingProvider bookkeeping.Provider 63 initializer *ledger.Initializer 64 collElgNotifier *collElgNotifier 65 stats *stats 66 fileLock *leveldbhelper.FileLock 67 hasher ledger.Hasher 68 } 69 70 // NewProvider instantiates a new Provider. 71 // This is not thread-safe and assumed to be synchronized by the caller 72 func NewProvider(initializer *ledger.Initializer) (pr *Provider, e error) { 73 p := &Provider{ 74 initializer: initializer, 75 hasher: initializer.Hasher, 76 } 77 78 defer func() { 79 if e != nil { 80 p.Close() 81 if errFormatMismatch, ok := e.(*dataformat.ErrVersionMismatch); ok { 82 if errFormatMismatch.Version == dataformat.Version1x && errFormatMismatch.ExpectedVersion == dataformat.Version20 { 83 logger.Errorf("Please execute the 'peer node upgrade-dbs' command to upgrade the database format: %s", errFormatMismatch) 84 } else { 85 logger.Errorf("Please check the Fabric version matches the ledger data format: %s", errFormatMismatch) 86 } 87 } 88 } 89 }() 90 91 fileLockPath := fileLockPath(initializer.Config.RootFSPath) 92 fileLock := leveldbhelper.NewFileLock(fileLockPath) 93 if err := fileLock.Lock(); err != nil { 94 return nil, errors.Wrap(err, "as another peer node command is executing,"+ 95 " wait for that command to complete its execution or terminate it before retrying") 96 } 97 98 p.fileLock = fileLock 99 100 if err := p.initLedgerIDInventory(); err != nil { 101 return nil, err 102 } 103 104 if err := p.initLedgerStorageProvider(); err != nil { 105 return nil, err 106 } 107 108 if err := p.initHistoryDBProvider(); err != nil { 109 return nil, err 110 } 111 112 if err := p.initConfigHistoryManager(); err != nil { 113 return nil, err 114 } 115 116 p.initCollElgNotifier() 117 118 p.initStateListeners() 119 120 if err := p.initStateDBProvider(); err != nil { 121 return nil, err 122 } 123 124 p.initLedgerStatistics() 125 126 p.recoverUnderConstructionLedger() 127 128 return p, nil 129 } 130 131 func (p *Provider) initLedgerIDInventory() error { 132 idStore, err := openIDStore(LedgerProviderPath(p.initializer.Config.RootFSPath)) 133 if err != nil { 134 return err 135 } 136 p.idStore = idStore 137 return nil 138 } 139 140 func (p *Provider) initLedgerStorageProvider() error { 141 // initialize ledger storage 142 privateData := &pvtdatastorage.PrivateDataConfig{ 143 PrivateDataConfig: p.initializer.Config.PrivateDataConfig, 144 StorePath: PvtDataStorePath(p.initializer.Config.RootFSPath), 145 } 146 147 ledgerStoreProvider, err := ledgerstorage.NewProvider( 148 BlockStorePath(p.initializer.Config.RootFSPath), 149 privateData, 150 p.initializer.MetricsProvider, 151 ) 152 if err != nil { 153 return err 154 } 155 p.ledgerStoreProvider = ledgerStoreProvider 156 return nil 157 } 158 159 func (p *Provider) initHistoryDBProvider() error { 160 if !p.initializer.Config.HistoryDBConfig.Enabled { 161 return nil 162 } 163 // Initialize the history database (index for history of values by key) 164 historydbProvider, err := history.NewDBProvider( 165 HistoryDBPath(p.initializer.Config.RootFSPath), 166 ) 167 if err != nil { 168 return err 169 } 170 p.historydbProvider = historydbProvider 171 return nil 172 } 173 174 func (p *Provider) initConfigHistoryManager() error { 175 var err error 176 configHistoryMgr, err := confighistory.NewMgr( 177 ConfigHistoryDBPath(p.initializer.Config.RootFSPath), 178 p.initializer.DeployedChaincodeInfoProvider, 179 ) 180 if err != nil { 181 return err 182 } 183 p.configHistoryMgr = configHistoryMgr 184 return nil 185 } 186 187 func (p *Provider) initCollElgNotifier() { 188 collElgNotifier := &collElgNotifier{ 189 p.initializer.DeployedChaincodeInfoProvider, 190 p.initializer.MembershipInfoProvider, 191 make(map[string]collElgListener), 192 } 193 p.collElgNotifier = collElgNotifier 194 } 195 196 func (p *Provider) initStateListeners() { 197 stateListeners := p.initializer.StateListeners 198 stateListeners = append(stateListeners, p.collElgNotifier) 199 stateListeners = append(stateListeners, p.configHistoryMgr) 200 p.stateListeners = stateListeners 201 } 202 203 func (p *Provider) initStateDBProvider() error { 204 var err error 205 p.bookkeepingProvider, err = bookkeeping.NewProvider( 206 BookkeeperDBPath(p.initializer.Config.RootFSPath), 207 ) 208 if err != nil { 209 return err 210 } 211 stateDB := &privacyenabledstate.StateDBConfig{ 212 StateDBConfig: p.initializer.Config.StateDBConfig, 213 LevelDBPath: StateDBPath(p.initializer.Config.RootFSPath), 214 } 215 sysNamespaces := p.initializer.DeployedChaincodeInfoProvider.Namespaces() 216 p.vdbProvider, err = privacyenabledstate.NewCommonStorageDBProvider( 217 p.bookkeepingProvider, 218 p.initializer.MetricsProvider, 219 p.initializer.HealthCheckRegistry, 220 stateDB, 221 sysNamespaces, 222 ) 223 return err 224 } 225 226 func (p *Provider) initLedgerStatistics() { 227 p.stats = newStats(p.initializer.MetricsProvider) 228 } 229 230 // Create implements the corresponding method from interface ledger.PeerLedgerProvider 231 // This functions sets a under construction flag before doing any thing related to ledger creation and 232 // upon a successful ledger creation with the committed genesis block, removes the flag and add entry into 233 // created ledgers list (atomically). If a crash happens in between, the 'recoverUnderConstructionLedger' 234 // function is invoked before declaring the provider to be usable 235 func (p *Provider) Create(genesisBlock *common.Block) (ledger.PeerLedger, error) { 236 ledgerID, err := protoutil.GetChainIDFromBlock(genesisBlock) 237 if err != nil { 238 return nil, err 239 } 240 exists, err := p.idStore.ledgerIDExists(ledgerID) 241 if err != nil { 242 return nil, err 243 } 244 if exists { 245 return nil, ErrLedgerIDExists 246 } 247 if err = p.idStore.setUnderConstructionFlag(ledgerID); err != nil { 248 return nil, err 249 } 250 lgr, err := p.openInternal(ledgerID) 251 if err != nil { 252 logger.Errorf("Error opening a new empty ledger. Unsetting under construction flag. Error: %+v", err) 253 panicOnErr(p.runCleanup(ledgerID), "Error running cleanup for ledger id [%s]", ledgerID) 254 panicOnErr(p.idStore.unsetUnderConstructionFlag(), "Error while unsetting under construction flag") 255 return nil, err 256 } 257 if err := lgr.CommitLegacy(&ledger.BlockAndPvtData{Block: genesisBlock}, &ledger.CommitOptions{}); err != nil { 258 lgr.Close() 259 return nil, err 260 } 261 panicOnErr(p.idStore.createLedgerID(ledgerID, genesisBlock), "Error while marking ledger as created") 262 return lgr, nil 263 } 264 265 // Open implements the corresponding method from interface ledger.PeerLedgerProvider 266 func (p *Provider) Open(ledgerID string) (ledger.PeerLedger, error) { 267 logger.Debugf("Open() opening kvledger: %s", ledgerID) 268 // Check the ID store to ensure that the chainId/ledgerId exists 269 active, exists, err := p.idStore.ledgerIDActive(ledgerID) 270 if err != nil { 271 return nil, err 272 } 273 if !exists { 274 return nil, ErrNonExistingLedgerID 275 } 276 if !active { 277 return nil, ErrInactiveLedger 278 } 279 return p.openInternal(ledgerID) 280 } 281 282 func (p *Provider) openInternal(ledgerID string) (ledger.PeerLedger, error) { 283 // Get the block store for a chain/ledger 284 blockStore, err := p.ledgerStoreProvider.Open(ledgerID) 285 if err != nil { 286 return nil, err 287 } 288 p.collElgNotifier.registerListener(ledgerID, blockStore) 289 290 // Get the versioned database (state database) for a chain/ledger 291 vDB, err := p.vdbProvider.GetDBHandle(ledgerID) 292 if err != nil { 293 return nil, err 294 } 295 296 // Get the history database (index for history of values by key) for a chain/ledger 297 var historyDB *history.DB 298 if p.historydbProvider != nil { 299 historyDB, err = p.historydbProvider.GetDBHandle(ledgerID) 300 if err != nil { 301 return nil, err 302 } 303 } 304 305 // Create a kvLedger for this chain/ledger, which encapsulates the underlying data stores 306 // (id store, blockstore, state database, history database) 307 l, err := newKVLedger( 308 ledgerID, 309 blockStore, 310 vDB, 311 historyDB, 312 p.configHistoryMgr, 313 p.stateListeners, 314 p.bookkeepingProvider, 315 p.initializer.DeployedChaincodeInfoProvider, 316 p.initializer.ChaincodeLifecycleEventProvider, 317 p.stats.ledgerStats(ledgerID), 318 p.initializer.CustomTxProcessors, 319 p.hasher, 320 ) 321 if err != nil { 322 return nil, err 323 } 324 return l, nil 325 } 326 327 // Exists implements the corresponding method from interface ledger.PeerLedgerProvider 328 func (p *Provider) Exists(ledgerID string) (bool, error) { 329 return p.idStore.ledgerIDExists(ledgerID) 330 } 331 332 // List implements the corresponding method from interface ledger.PeerLedgerProvider 333 func (p *Provider) List() ([]string, error) { 334 return p.idStore.getActiveLedgerIDs() 335 } 336 337 // Close implements the corresponding method from interface ledger.PeerLedgerProvider 338 func (p *Provider) Close() { 339 if p.idStore != nil { 340 p.idStore.close() 341 } 342 if p.ledgerStoreProvider != nil { 343 p.ledgerStoreProvider.Close() 344 } 345 if p.vdbProvider != nil { 346 p.vdbProvider.Close() 347 } 348 if p.bookkeepingProvider != nil { 349 p.bookkeepingProvider.Close() 350 } 351 if p.configHistoryMgr != nil { 352 p.configHistoryMgr.Close() 353 } 354 if p.historydbProvider != nil { 355 p.historydbProvider.Close() 356 } 357 if p.fileLock != nil { 358 p.fileLock.Unlock() 359 } 360 } 361 362 // recoverUnderConstructionLedger checks whether the under construction flag is set - this would be the case 363 // if a crash had happened during creation of ledger and the ledger creation could have been left in intermediate 364 // state. Recovery checks if the ledger was created and the genesis block was committed successfully then it completes 365 // the last step of adding the ledger id to the list of created ledgers. Else, it clears the under construction flag 366 func (p *Provider) recoverUnderConstructionLedger() { 367 logger.Debugf("Recovering under construction ledger") 368 ledgerID, err := p.idStore.getUnderConstructionFlag() 369 panicOnErr(err, "Error while checking whether the under construction flag is set") 370 if ledgerID == "" { 371 logger.Debugf("No under construction ledger found. Quitting recovery") 372 return 373 } 374 logger.Infof("ledger [%s] found as under construction", ledgerID) 375 ledger, err := p.openInternal(ledgerID) 376 panicOnErr(err, "Error while opening under construction ledger [%s]", ledgerID) 377 bcInfo, err := ledger.GetBlockchainInfo() 378 panicOnErr(err, "Error while getting blockchain info for the under construction ledger [%s]", ledgerID) 379 ledger.Close() 380 381 switch bcInfo.Height { 382 case 0: 383 logger.Infof("Genesis block was not committed. Hence, the peer ledger not created. unsetting the under construction flag") 384 panicOnErr(p.runCleanup(ledgerID), "Error while running cleanup for ledger id [%s]", ledgerID) 385 panicOnErr(p.idStore.unsetUnderConstructionFlag(), "Error while unsetting under construction flag") 386 case 1: 387 logger.Infof("Genesis block was committed. Hence, marking the peer ledger as created") 388 genesisBlock, err := ledger.GetBlockByNumber(0) 389 panicOnErr(err, "Error while retrieving genesis block from blockchain for ledger [%s]", ledgerID) 390 panicOnErr(p.idStore.createLedgerID(ledgerID, genesisBlock), "Error while adding ledgerID [%s] to created list", ledgerID) 391 default: 392 panic(errors.Errorf( 393 "data inconsistency: under construction flag is set for ledger [%s] while the height of the blockchain is [%d]", 394 ledgerID, bcInfo.Height)) 395 } 396 return 397 } 398 399 // runCleanup cleans up blockstorage, statedb, and historydb for what 400 // may have got created during in-complete ledger creation 401 func (p *Provider) runCleanup(ledgerID string) error { 402 // TODO - though, not having this is harmless for kv ledger. 403 // If we want, following could be done: 404 // - blockstorage could remove empty folders 405 // - couchdb backed statedb could delete the database if got created 406 // - leveldb backed statedb and history db need not perform anything as it uses a single db shared across ledgers 407 return nil 408 } 409 410 func panicOnErr(err error, mgsFormat string, args ...interface{}) { 411 if err == nil { 412 return 413 } 414 args = append(args, err) 415 panic(fmt.Sprintf(mgsFormat+" Error: %s", args...)) 416 } 417 418 ////////////////////////////////////////////////////////////////////// 419 // Ledger id persistence related code 420 /////////////////////////////////////////////////////////////////////// 421 type idStore struct { 422 db *leveldbhelper.DB 423 dbPath string 424 } 425 426 func openIDStore(path string) (s *idStore, e error) { 427 db := leveldbhelper.CreateDB(&leveldbhelper.Conf{DBPath: path}) 428 db.Open() 429 defer func() { 430 if e != nil { 431 db.Close() 432 } 433 }() 434 435 emptyDB, err := db.IsEmpty() 436 if err != nil { 437 return nil, err 438 } 439 440 expectedFormatBytes := []byte(dataformat.Version20) 441 if emptyDB { 442 // add format key to a new db 443 err := db.Put(formatKey, expectedFormatBytes, true) 444 if err != nil { 445 return nil, err 446 } 447 return &idStore{db, path}, nil 448 } 449 450 // verify the format is current for an existing db 451 formatVersion, err := db.Get(formatKey) 452 if err != nil { 453 return nil, err 454 } 455 if !bytes.Equal(formatVersion, expectedFormatBytes) { 456 logger.Errorf("The db at path [%s] contains data in unexpected format. expected data format = [%s] (%#v), data format = [%s] (%#v).", 457 path, dataformat.Version20, expectedFormatBytes, formatVersion, formatVersion) 458 return nil, &dataformat.ErrVersionMismatch{ 459 ExpectedVersion: dataformat.Version20, 460 Version: string(formatVersion), 461 DBInfo: fmt.Sprintf("leveldb for channel-IDs at [%s]", path), 462 } 463 } 464 return &idStore{db, path}, nil 465 } 466 467 func (s *idStore) upgradeFormat() error { 468 format, err := s.db.Get(formatKey) 469 if err != nil { 470 return err 471 } 472 idStoreFormatBytes := []byte(dataformat.Version20) 473 if bytes.Equal(format, idStoreFormatBytes) { 474 logger.Debug("Format is current, nothing to do") 475 return nil 476 } 477 if format != nil { 478 err = &dataformat.ErrVersionMismatch{ 479 ExpectedVersion: "", 480 Version: string(format), 481 DBInfo: fmt.Sprintf("leveldb for channel-IDs at [%s]", s.dbPath), 482 } 483 logger.Errorf("Failed to upgrade format [%#v] to new format [%#v]: %s", format, idStoreFormatBytes, err) 484 return err 485 } 486 487 logger.Infof("The ledgerProvider db format is old, upgrading to the new format %s", dataformat.Version20) 488 489 batch := &leveldb.Batch{} 490 batch.Put(formatKey, idStoreFormatBytes) 491 492 // add new metadata key for each ledger (channel) 493 metadata, err := protoutil.Marshal(&msgs.LedgerMetadata{Status: msgs.Status_ACTIVE}) 494 if err != nil { 495 logger.Errorf("Error marshalling ledger metadata: %s", err) 496 return errors.Wrapf(err, "error marshalling ledger metadata") 497 } 498 itr := s.db.GetIterator(ledgerKeyPrefix, ledgerKeyStop) 499 defer itr.Release() 500 for itr.Error() == nil && itr.Next() { 501 id := s.decodeLedgerID(itr.Key(), ledgerKeyPrefix) 502 batch.Put(s.encodeLedgerKey(id, metadataKeyPrefix), metadata) 503 } 504 if err = itr.Error(); err != nil { 505 logger.Errorf("Error while upgrading idStore format: %s", err) 506 return errors.Wrapf(err, "error while upgrading idStore format") 507 } 508 509 return s.db.WriteBatch(batch, true) 510 } 511 512 func (s *idStore) setUnderConstructionFlag(ledgerID string) error { 513 return s.db.Put(underConstructionLedgerKey, []byte(ledgerID), true) 514 } 515 516 func (s *idStore) unsetUnderConstructionFlag() error { 517 return s.db.Delete(underConstructionLedgerKey, true) 518 } 519 520 func (s *idStore) getUnderConstructionFlag() (string, error) { 521 val, err := s.db.Get(underConstructionLedgerKey) 522 if err != nil { 523 return "", err 524 } 525 return string(val), nil 526 } 527 528 func (s *idStore) createLedgerID(ledgerID string, gb *common.Block) error { 529 gbKey := s.encodeLedgerKey(ledgerID, ledgerKeyPrefix) 530 metadataKey := s.encodeLedgerKey(ledgerID, metadataKeyPrefix) 531 var val []byte 532 var metadata []byte 533 var err error 534 if val, err = s.db.Get(gbKey); err != nil { 535 return err 536 } 537 if val != nil { 538 return ErrLedgerIDExists 539 } 540 if val, err = proto.Marshal(gb); err != nil { 541 return err 542 } 543 if metadata, err = protoutil.Marshal(&msgs.LedgerMetadata{Status: msgs.Status_ACTIVE}); err != nil { 544 return err 545 } 546 batch := &leveldb.Batch{} 547 batch.Put(gbKey, val) 548 batch.Put(metadataKey, metadata) 549 batch.Delete(underConstructionLedgerKey) 550 return s.db.WriteBatch(batch, true) 551 } 552 553 func (s *idStore) updateLedgerStatus(ledgerID string, newStatus msgs.Status) error { 554 metadata, err := s.getLedgerMetadata(ledgerID) 555 if err != nil { 556 return err 557 } 558 if metadata == nil { 559 logger.Errorf("LedgerID [%s] does not exist", ledgerID) 560 return ErrNonExistingLedgerID 561 } 562 if metadata.Status == newStatus { 563 logger.Infof("Ledger [%s] is already in [%s] status, nothing to do", ledgerID, newStatus) 564 return nil 565 } 566 metadata.Status = newStatus 567 metadataBytes, err := proto.Marshal(metadata) 568 if err != nil { 569 logger.Errorf("Error marshalling ledger metadata: %s", err) 570 return errors.Wrapf(err, "error marshalling ledger metadata") 571 } 572 logger.Infof("Updating ledger [%s] status to [%s]", ledgerID, newStatus) 573 key := s.encodeLedgerKey(ledgerID, metadataKeyPrefix) 574 return s.db.Put(key, metadataBytes, true) 575 } 576 577 func (s *idStore) getLedgerMetadata(ledgerID string) (*msgs.LedgerMetadata, error) { 578 val, err := s.db.Get(s.encodeLedgerKey(ledgerID, metadataKeyPrefix)) 579 if val == nil || err != nil { 580 return nil, err 581 } 582 metadata := &msgs.LedgerMetadata{} 583 if err := proto.Unmarshal(val, metadata); err != nil { 584 logger.Errorf("Error unmarshalling ledger metadata: %s", err) 585 return nil, errors.Wrapf(err, "error unmarshalling ledger metadata") 586 } 587 return metadata, nil 588 } 589 590 func (s *idStore) ledgerIDExists(ledgerID string) (bool, error) { 591 key := s.encodeLedgerKey(ledgerID, ledgerKeyPrefix) 592 val := []byte{} 593 err := error(nil) 594 if val, err = s.db.Get(key); err != nil { 595 return false, err 596 } 597 return val != nil, nil 598 } 599 600 // ledgerIDActive returns if a ledger is active and existed 601 func (s *idStore) ledgerIDActive(ledgerID string) (bool, bool, error) { 602 metadata, err := s.getLedgerMetadata(ledgerID) 603 if metadata == nil || err != nil { 604 return false, false, err 605 } 606 return metadata.Status == msgs.Status_ACTIVE, true, nil 607 } 608 609 func (s *idStore) getActiveLedgerIDs() ([]string, error) { 610 var ids []string 611 itr := s.db.GetIterator(metadataKeyPrefix, metadataKeyStop) 612 defer itr.Release() 613 for itr.Error() == nil && itr.Next() { 614 metadata := &msgs.LedgerMetadata{} 615 if err := proto.Unmarshal(itr.Value(), metadata); err != nil { 616 logger.Errorf("Error unmarshalling ledger metadata: %s", err) 617 return nil, errors.Wrapf(err, "error unmarshalling ledger metadata") 618 } 619 if metadata.Status == msgs.Status_ACTIVE { 620 id := s.decodeLedgerID(itr.Key(), metadataKeyPrefix) 621 ids = append(ids, id) 622 } 623 } 624 if err := itr.Error(); err != nil { 625 logger.Errorf("Error getting ledger ids from idStore: %s", err) 626 return nil, errors.Wrapf(err, "error getting ledger ids from idStore") 627 } 628 return ids, nil 629 } 630 631 func (s *idStore) close() { 632 s.db.Close() 633 } 634 635 func (s *idStore) encodeLedgerKey(ledgerID string, prefix []byte) []byte { 636 return append(prefix, []byte(ledgerID)...) 637 } 638 639 func (s *idStore) decodeLedgerID(key []byte, prefix []byte) string { 640 return string(key[len(prefix):]) 641 }