Skip to content

Commit c9d0ca2

Browse files
committed
[FAB-3017] Ledger backup restore
- Added the genesis block into ledger provider which may help in future for addition/restoreing of peer by merely copying ledger provider folder (a few MBs of data) - Added a test for backup and restore of ledger The draft documentation for the instructions on backup and restore can be found at "https://jira.hyperledger.org/browse/FAB-3017#comment-22720" Change-Id: I6da2bdece4bf7f084dbd4d1da0a89706747b89da Signed-off-by: manish <[email protected]>
1 parent 722e790 commit c9d0ca2

File tree

3 files changed

+136
-6
lines changed

3 files changed

+136
-6
lines changed

core/ledger/kvledger/kv_ledger_provider.go

+11-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"errors"
2222
"fmt"
2323

24+
"github.com/golang/protobuf/proto"
2425
"github.com/hyperledger/fabric/common/ledger/blkstorage"
2526
"github.com/hyperledger/fabric/common/ledger/blkstorage/fsblkstorage"
2627
"github.com/hyperledger/fabric/common/ledger/util/leveldbhelper"
@@ -134,7 +135,7 @@ func (provider *Provider) Create(genesisBlock *common.Block) (ledger.PeerLedger,
134135
ledger.Close()
135136
return nil, err
136137
}
137-
panicOnErr(provider.idStore.createLedgerID(ledgerID), "Error while marking ledger as created")
138+
panicOnErr(provider.idStore.createLedgerID(ledgerID, genesisBlock), "Error while marking ledger as created")
138139
return ledger, nil
139140
}
140141

@@ -224,7 +225,9 @@ func (provider *Provider) recoverUnderConstructionLedger() {
224225
panicOnErr(provider.idStore.unsetUnderConstructionFlag(), "Error while unsetting under construction flag")
225226
case 1:
226227
logger.Infof("Genesis block was committed. Hence, marking the peer ledger as created")
227-
panicOnErr(provider.idStore.createLedgerID(ledgerID), "Error while adding ledgerID [%s] to created list", ledgerID)
228+
genesisBlock, err := ledger.GetBlockByNumber(0)
229+
panicOnErr(err, "Error while retrieving genesis block from blockchain for ledger [%s]", ledgerID)
230+
panicOnErr(provider.idStore.createLedgerID(ledgerID, genesisBlock), "Error while adding ledgerID [%s] to created list", ledgerID)
228231
default:
229232
panic(fmt.Errorf(
230233
"Data inconsistency: under construction flag is set for ledger [%s] while the height of the blockchain is [%d]",
@@ -281,10 +284,13 @@ func (s *idStore) getUnderConstructionFlag() (string, error) {
281284
return string(val), nil
282285
}
283286

284-
func (s *idStore) createLedgerID(ledgerID string) error {
287+
func (s *idStore) createLedgerID(ledgerID string, gb *common.Block) error {
285288
key := s.encodeLedgerKey(ledgerID)
286-
val := []byte{}
287-
err := error(nil)
289+
var val []byte
290+
var err error
291+
if val, err = proto.Marshal(gb); err != nil {
292+
return err
293+
}
288294
if val, err = s.db.Get(key); err != nil {
289295
return err
290296
}

core/ledger/kvledger/kv_ledger_provider_test.go

+120
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,19 @@ package kvledger
1818

1919
import (
2020
"fmt"
21+
"os"
22+
"path/filepath"
2123
"testing"
2224

2325
configtxtest "github.com/hyperledger/fabric/common/configtx/test"
26+
"github.com/hyperledger/fabric/common/ledger/blkstorage/fsblkstorage"
2427
"github.com/hyperledger/fabric/common/ledger/testutil"
2528
"github.com/hyperledger/fabric/core/ledger"
29+
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
30+
"github.com/hyperledger/fabric/protos/common"
31+
"github.com/hyperledger/fabric/protos/ledger/queryresult"
32+
putils "github.com/hyperledger/fabric/protos/utils"
33+
"github.com/spf13/viper"
2634
)
2735

2836
func TestLedgerProvider(t *testing.T) {
@@ -111,6 +119,118 @@ func TestMultipleLedgerBasicRW(t *testing.T) {
111119
}
112120
}
113121

122+
func TestLedgerBackup(t *testing.T) {
123+
ledgerid := "TestLedger"
124+
originalPath := "/tmp/fabric/ledgertests/kvledger1"
125+
restorePath := "/tmp/fabric/ledgertests/kvledger2"
126+
viper.Set("ledger.history.enableHistoryDatabase", true)
127+
128+
// create and populate a ledger in the original environment
129+
env := createTestEnv(t, originalPath)
130+
provider, _ := NewProvider()
131+
bg, gb := testutil.NewBlockGenerator(t, ledgerid, false)
132+
gbHash := gb.Header.Hash()
133+
ledger, _ := provider.Create(gb)
134+
135+
simulator, _ := ledger.NewTxSimulator()
136+
simulator.SetState("ns1", "key1", []byte("value1"))
137+
simulator.SetState("ns1", "key2", []byte("value2"))
138+
simulator.SetState("ns1", "key3", []byte("value3"))
139+
simulator.Done()
140+
simRes, _ := simulator.GetTxSimulationResults()
141+
block1 := bg.NextBlock([][]byte{simRes})
142+
ledger.Commit(block1)
143+
144+
simulator, _ = ledger.NewTxSimulator()
145+
simulator.SetState("ns1", "key1", []byte("value4"))
146+
simulator.SetState("ns1", "key2", []byte("value5"))
147+
simulator.SetState("ns1", "key3", []byte("value6"))
148+
simulator.Done()
149+
simRes, _ = simulator.GetTxSimulationResults()
150+
block2 := bg.NextBlock([][]byte{simRes})
151+
ledger.Commit(block2)
152+
153+
ledger.Close()
154+
provider.Close()
155+
156+
// Create restore environment
157+
env = createTestEnv(t, restorePath)
158+
159+
// remove the statedb, historydb, and block indexes (they are suppoed to be auto created during opening of an existing ledger)
160+
// and rename the originalPath to restorePath
161+
testutil.AssertNoError(t, os.RemoveAll(ledgerconfig.GetStateLevelDBPath()), "")
162+
testutil.AssertNoError(t, os.RemoveAll(ledgerconfig.GetHistoryLevelDBPath()), "")
163+
testutil.AssertNoError(t, os.RemoveAll(filepath.Join(ledgerconfig.GetBlockStorePath(), fsblkstorage.IndexDir)), "")
164+
testutil.AssertNoError(t, os.Rename(originalPath, restorePath), "")
165+
defer env.cleanup()
166+
167+
// Instantiate the ledger from restore environment and this should behave exactly as it would have in the original environment
168+
provider, _ = NewProvider()
169+
defer provider.Close()
170+
171+
_, err := provider.Create(gb)
172+
testutil.AssertEquals(t, err, ErrLedgerIDExists)
173+
174+
ledger, _ = provider.Open(ledgerid)
175+
defer ledger.Close()
176+
177+
block1Hash := block1.Header.Hash()
178+
block2Hash := block2.Header.Hash()
179+
bcInfo, _ := ledger.GetBlockchainInfo()
180+
testutil.AssertEquals(t, bcInfo, &common.BlockchainInfo{
181+
Height: 3, CurrentBlockHash: block2Hash, PreviousBlockHash: block1Hash})
182+
183+
b0, _ := ledger.GetBlockByHash(gbHash)
184+
testutil.AssertEquals(t, b0, gb)
185+
186+
b1, _ := ledger.GetBlockByHash(block1Hash)
187+
testutil.AssertEquals(t, b1, block1)
188+
189+
b2, _ := ledger.GetBlockByHash(block2Hash)
190+
testutil.AssertEquals(t, b2, block2)
191+
192+
b0, _ = ledger.GetBlockByNumber(0)
193+
testutil.AssertEquals(t, b0, gb)
194+
195+
b1, _ = ledger.GetBlockByNumber(1)
196+
testutil.AssertEquals(t, b1, block1)
197+
198+
b2, _ = ledger.GetBlockByNumber(2)
199+
testutil.AssertEquals(t, b2, block2)
200+
201+
// get the tran id from the 2nd block, then use it to test GetTransactionByID()
202+
txEnvBytes2 := block1.Data.Data[0]
203+
txEnv2, err := putils.GetEnvelopeFromBlock(txEnvBytes2)
204+
testutil.AssertNoError(t, err, "Error upon GetEnvelopeFromBlock")
205+
payload2, err := putils.GetPayload(txEnv2)
206+
testutil.AssertNoError(t, err, "Error upon GetPayload")
207+
chdr, err := putils.UnmarshalChannelHeader(payload2.Header.ChannelHeader)
208+
testutil.AssertNoError(t, err, "Error upon GetChannelHeaderFromBytes")
209+
txID2 := chdr.TxId
210+
processedTran2, err := ledger.GetTransactionByID(txID2)
211+
testutil.AssertNoError(t, err, "Error upon GetTransactionByID")
212+
// get the tran envelope from the retrieved ProcessedTransaction
213+
retrievedTxEnv2 := processedTran2.TransactionEnvelope
214+
testutil.AssertEquals(t, retrievedTxEnv2, txEnv2)
215+
216+
qe, _ := ledger.NewQueryExecutor()
217+
value1, _ := qe.GetState("ns1", "key1")
218+
testutil.AssertEquals(t, value1, []byte("value4"))
219+
220+
hqe, err := ledger.NewHistoryQueryExecutor()
221+
testutil.AssertNoError(t, err, "")
222+
itr, err := hqe.GetHistoryForKey("ns1", "key1")
223+
testutil.AssertNoError(t, err, "")
224+
defer itr.Close()
225+
226+
result1, err := itr.Next()
227+
testutil.AssertNoError(t, err, "")
228+
testutil.AssertEquals(t, result1.(*queryresult.KeyModification).Value, []byte("value1"))
229+
result2, err := itr.Next()
230+
testutil.AssertNoError(t, err, "")
231+
testutil.AssertEquals(t, result2.(*queryresult.KeyModification).Value, []byte("value4"))
232+
}
233+
114234
func constructTestLedgerID(i int) string {
115235
return fmt.Sprintf("ledger_%06d", i)
116236
}

core/ledger/kvledger/pkg_test.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ type testEnv struct {
2929
}
3030

3131
func newTestEnv(t testing.TB) *testEnv {
32-
viper.Set("peer.fileSystemPath", "/tmp/fabric/ledgertests/kvledger")
32+
return createTestEnv(t, "/tmp/fabric/ledgertests/kvledger")
33+
}
34+
35+
func createTestEnv(t testing.TB, path string) *testEnv {
36+
viper.Set("peer.fileSystemPath", path)
3337
env := &testEnv{t}
3438
env.cleanup()
3539
return env

0 commit comments

Comments
 (0)