Commit 2a16532c authored by manish's avatar manish
Browse files

Move Blockstorage code under /fabric/common package

https://jira.hyperledger.org/browse/FAB-2022



This changes introduced by this CR
- Moves the block storage code from package
core/ledger/blkstorage to common/ledger/blkstorage

- Splits the ledger_interface.go so as to move common interfaces
and data type to common/ledger package

- Moves some of the util functions to common/ledger package

- Moves core/ledger/ordererledger package to orderer/ledger/fsledger
orderer folks can futher rename/refactor this as seems suitable to them

Change-Id: I759e16f00dc2ec9bb62196121083cf48eae76948
Signed-off-by: default avatarmanish <manish.sethi@gmail.com>
parent e67a2382
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testutil
import (
"crypto/rand"
"fmt"
"reflect"
"runtime"
"testing"
)
// AssertNil varifies that the value is nil
func AssertNil(t testing.TB, value interface{}) {
if !isNil(value) {
t.Fatalf("Value not nil. value=[%#v]\n %s", value, getCallerInfo())
}
}
// AssertNotNil varifies that the value is not nil
func AssertNotNil(t testing.TB, value interface{}) {
if isNil(value) {
t.Fatalf("Values is nil. %s", getCallerInfo())
}
}
// AssertSame varifies that the two values are same
func AssertSame(t testing.TB, actual interface{}, expected interface{}) {
t.Logf("%s: AssertSame [%#v] and [%#v]", getCallerInfo(), actual, expected)
if actual != expected {
t.Fatalf("Values actual=[%#v] and expected=[%#v] do not point to same object. %s", actual, expected, getCallerInfo())
}
}
// AssertEquals varifies that the two values are equal
func AssertEquals(t testing.TB, actual interface{}, expected interface{}) {
t.Logf("%s: AssertEquals [%#v] and [%#v]", getCallerInfo(), actual, expected)
if expected == nil && isNil(actual) {
return
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("Values are not equal.\n Actual=[%#v], \n Expected=[%#v]\n %s", actual, expected, getCallerInfo())
}
}
// AssertNotEquals varifies that the two values are not equal
func AssertNotEquals(t testing.TB, actual interface{}, expected interface{}) {
if reflect.DeepEqual(actual, expected) {
t.Fatalf("Values are not supposed to be equal. Actual=[%#v], Expected=[%#v]\n %s", actual, expected, getCallerInfo())
}
}
// AssertError varifies that the err is not nil
func AssertError(t testing.TB, err error, message string) {
if err == nil {
t.Fatalf("%s\n %s", message, getCallerInfo())
}
}
// AssertNoError varifies that the err is nil
func AssertNoError(t testing.TB, err error, message string) {
if err != nil {
t.Fatalf("%s - Error: %s\n %s", message, err, getCallerInfo())
}
}
// AssertContains varifies that the slice contains the value
func AssertContains(t testing.TB, slice interface{}, value interface{}) {
if reflect.TypeOf(slice).Kind() != reflect.Slice && reflect.TypeOf(slice).Kind() != reflect.Array {
t.Fatalf("Type of argument 'slice' is expected to be a slice/array, found =[%s]\n %s", reflect.TypeOf(slice), getCallerInfo())
}
if !Contains(slice, value) {
t.Fatalf("Expected value [%s] not found in slice %s\n %s", value, slice, getCallerInfo())
}
}
// AssertContainsAll varifies that sliceActual is a superset of sliceExpected
func AssertContainsAll(t testing.TB, sliceActual interface{}, sliceExpected interface{}) {
if reflect.TypeOf(sliceActual).Kind() != reflect.Slice && reflect.TypeOf(sliceActual).Kind() != reflect.Array {
t.Fatalf("Type of argument 'sliceActual' is expected to be a slice/array, found =[%s]\n %s", reflect.TypeOf(sliceActual), getCallerInfo())
}
if reflect.TypeOf(sliceExpected).Kind() != reflect.Slice && reflect.TypeOf(sliceExpected).Kind() != reflect.Array {
t.Fatalf("Type of argument 'sliceExpected' is expected to be a slice/array, found =[%s]\n %s", reflect.TypeOf(sliceExpected), getCallerInfo())
}
array := reflect.ValueOf(sliceExpected)
for i := 0; i < array.Len(); i++ {
element := array.Index(i).Interface()
if !Contains(sliceActual, element) {
t.Fatalf("Expected value [%s] not found in slice %s\n %s", element, sliceActual, getCallerInfo())
}
}
}
// AssertPanic varifies that a panic is raised during a test
func AssertPanic(t testing.TB, msg string) {
x := recover()
if x == nil {
t.Fatal(msg)
} else {
t.Logf("A panic was caught successfully. Actual msg = %s", x)
}
}
// ConstructRandomBytes constructs random bytes of given size
func ConstructRandomBytes(t testing.TB, size int) []byte {
value := make([]byte, size)
_, err := rand.Read(value)
if err != nil {
t.Fatalf("Error while generating random bytes: %s", err)
}
return value
}
// Contains returns true iff the `value` is present in the `slice`
func Contains(slice interface{}, value interface{}) bool {
array := reflect.ValueOf(slice)
for i := 0; i < array.Len(); i++ {
element := array.Index(i).Interface()
if value == element || reflect.DeepEqual(element, value) {
return true
}
}
return false
}
func isNil(in interface{}) bool {
return in == nil || reflect.ValueOf(in).IsNil() || (reflect.TypeOf(in).Kind() == reflect.Slice && reflect.ValueOf(in).Len() == 0)
}
func getCallerInfo() string {
_, file, line, ok := runtime.Caller(2)
if !ok {
return "Could not retrieve caller's info"
}
return fmt.Sprintf("CallerInfo = [%s:%d]", file, line)
}
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package testutil
import "testing"
func TestSkipAll(t *testing.T) {
t.Skip(`No tests in this package for now - This package contains only utility functions that are meant to be used by other functional tests`)
}
...@@ -21,7 +21,7 @@ import ( ...@@ -21,7 +21,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/hyperledger/fabric/core/ledger/testutil" "github.com/hyperledger/fabric/common/ledger/testutil"
) )
var DbPathTest = "/tmp/v2/test/util" var DbPathTest = "/tmp/v2/test/util"
......
...@@ -20,7 +20,7 @@ import ( ...@@ -20,7 +20,7 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/hyperledger/fabric/core/ledger/util" "github.com/hyperledger/fabric/common/ledger/util"
"github.com/op/go-logging" "github.com/op/go-logging"
"github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/iterator" "github.com/syndtr/goleveldb/leveldb/iterator"
......
...@@ -21,7 +21,7 @@ import ( ...@@ -21,7 +21,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/hyperledger/fabric/core/ledger/testutil" "github.com/hyperledger/fabric/common/ledger/testutil"
) )
const testDBPath = "/tmp/fabric/ledgertests/util/leveldbhelper" const testDBPath = "/tmp/fabric/ledgertests/util/leveldbhelper"
......
...@@ -20,7 +20,7 @@ import ( ...@@ -20,7 +20,7 @@ import (
"testing" "testing"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/ledger/testutil" "github.com/hyperledger/fabric/common/ledger/testutil"
) )
func TestBuffer(t *testing.T) { func TestBuffer(t *testing.T) {
......
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
"encoding/binary"
"fmt"
"github.com/golang/protobuf/proto"
)
// EncodeOrderPreservingVarUint64 returns a byte-representation for a uint64 number such that
// all zero-bits starting bytes are trimmed in order to reduce the length of the array
// For preserving the order in a default bytes-comparison, first byte contains the number of remaining bytes.
// The presence of first byte also allows to use the returned bytes as part of other larger byte array such as a
// composite-key representation in db
func EncodeOrderPreservingVarUint64(number uint64) []byte {
bytes := make([]byte, 8)
binary.BigEndian.PutUint64(bytes, number)
startingIndex := 0
size := 0
for i, b := range bytes {
if b != 0x00 {
startingIndex = i
size = 8 - i
break
}
}
sizeBytes := proto.EncodeVarint(uint64(size))
if len(sizeBytes) > 1 {
panic(fmt.Errorf("[]sizeBytes should not be more than one byte because the max number it needs to hold is 8. size=%d", size))
}
encodedBytes := make([]byte, size+1)
encodedBytes[0] = sizeBytes[0]
copy(encodedBytes[1:], bytes[startingIndex:])
return encodedBytes
}
// DecodeOrderPreservingVarUint64 decodes the number from the bytes obtained from method 'EncodeOrderPreservingVarUint64'.
// Also, returns the number of bytes that are consumed in the process
func DecodeOrderPreservingVarUint64(bytes []byte) (uint64, int) {
s, _ := proto.DecodeVarint(bytes)
size := int(s)
decodedBytes := make([]byte, 8)
copy(decodedBytes[8-size:], bytes[1:size+1])
numBytesConsumed := size + 1
return binary.BigEndian.Uint64(decodedBytes), numBytesConsumed
}
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"time" "time"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
commonledger "github.com/hyperledger/fabric/common/ledger"
"github.com/hyperledger/fabric/common/util" "github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/common/ccprovider" "github.com/hyperledger/fabric/core/common/ccprovider"
ccintf "github.com/hyperledger/fabric/core/container/ccintf" ccintf "github.com/hyperledger/fabric/core/container/ccintf"
...@@ -59,7 +60,7 @@ type transactionContext struct { ...@@ -59,7 +60,7 @@ type transactionContext struct {
responseNotifier chan *pb.ChaincodeMessage responseNotifier chan *pb.ChaincodeMessage
// tracks open iterators used for range queries // tracks open iterators used for range queries
queryIteratorMap map[string]ledger.ResultsIterator queryIteratorMap map[string]commonledger.ResultsIterator
txsimulator ledger.TxSimulator txsimulator ledger.TxSimulator
} }
...@@ -186,7 +187,7 @@ func (handler *Handler) createTxContext(ctxt context.Context, chainID string, tx ...@@ -186,7 +187,7 @@ func (handler *Handler) createTxContext(ctxt context.Context, chainID string, tx
return nil, fmt.Errorf("txid:%s exists", txid) return nil, fmt.Errorf("txid:%s exists", txid)
} }
txctx := &transactionContext{chainID: chainID, proposal: prop, responseNotifier: make(chan *pb.ChaincodeMessage, 1), txctx := &transactionContext{chainID: chainID, proposal: prop, responseNotifier: make(chan *pb.ChaincodeMessage, 1),
queryIteratorMap: make(map[string]ledger.ResultsIterator)} queryIteratorMap: make(map[string]commonledger.ResultsIterator)}
handler.txCtxs[txid] = txctx handler.txCtxs[txid] = txctx
txctx.txsimulator = getTxSimulator(ctxt) txctx.txsimulator = getTxSimulator(ctxt)
...@@ -208,13 +209,13 @@ func (handler *Handler) deleteTxContext(txid string) { ...@@ -208,13 +209,13 @@ func (handler *Handler) deleteTxContext(txid string) {
} }
func (handler *Handler) putQueryIterator(txContext *transactionContext, txid string, func (handler *Handler) putQueryIterator(txContext *transactionContext, txid string,
queryIterator ledger.ResultsIterator) { queryIterator commonledger.ResultsIterator) {
handler.Lock() handler.Lock()
defer handler.Unlock() defer handler.Unlock()
txContext.queryIteratorMap[txid] = queryIterator txContext.queryIteratorMap[txid] = queryIterator
} }
func (handler *Handler) getQueryIterator(txContext *transactionContext, txid string) ledger.ResultsIterator { func (handler *Handler) getQueryIterator(txContext *transactionContext, txid string) commonledger.ResultsIterator {
handler.Lock() handler.Lock()
defer handler.Unlock() defer handler.Unlock()
return txContext.queryIteratorMap[txid] return txContext.queryIteratorMap[txid]
...@@ -699,7 +700,7 @@ func (handler *Handler) handleRangeQueryState(msg *pb.ChaincodeMessage) { ...@@ -699,7 +700,7 @@ func (handler *Handler) handleRangeQueryState(msg *pb.ChaincodeMessage) {
var keysAndValues []*pb.QueryStateKeyValue var keysAndValues []*pb.QueryStateKeyValue
var i = uint32(0) var i = uint32(0)
var qresult ledger.QueryResult var qresult commonledger.QueryResult
for ; i < maxRangeQueryStateLimit; i++ { for ; i < maxRangeQueryStateLimit; i++ {
qresult, err = rangeIter.Next() qresult, err = rangeIter.Next()
if err != nil { if err != nil {
...@@ -796,7 +797,7 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) { ...@@ -796,7 +797,7 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) {
var keysAndValues []*pb.QueryStateKeyValue var keysAndValues []*pb.QueryStateKeyValue
var i = uint32(0) var i = uint32(0)
var qresult ledger.QueryResult var qresult commonledger.QueryResult
var err error var err error
for ; i < maxRangeQueryStateLimit; i++ { for ; i < maxRangeQueryStateLimit; i++ {
qresult, err = queryIter.Next() qresult, err = queryIter.Next()
...@@ -974,7 +975,7 @@ func (handler *Handler) handleExecuteQueryState(msg *pb.ChaincodeMessage) { ...@@ -974,7 +975,7 @@ func (handler *Handler) handleExecuteQueryState(msg *pb.ChaincodeMessage) {
var keysAndValues []*pb.QueryStateKeyValue var keysAndValues []*pb.QueryStateKeyValue
var i = uint32(0) var i = uint32(0)
var qresult ledger.QueryResult var qresult commonledger.QueryResult
for ; i < maxExecuteQueryStateLimit; i++ { for ; i < maxExecuteQueryStateLimit; i++ {
qresult, err = executeIter.Next() qresult, err = executeIter.Next()
if err != nil { if err != nil {
......
...@@ -23,7 +23,6 @@ import ( ...@@ -23,7 +23,6 @@ import (
"github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/events/producer" "github.com/hyperledger/fabric/events/producer"
"github.com/hyperledger/fabric/protos/common" "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/op/go-logging" "github.com/op/go-logging"
) )
...@@ -75,7 +74,7 @@ func (lc *LedgerCommitter) Commit(block *common.Block) error { ...@@ -75,7 +74,7 @@ func (lc *LedgerCommitter) Commit(block *common.Block) error {
// LedgerHeight returns recently committed block sequence number // LedgerHeight returns recently committed block sequence number
func (lc *LedgerCommitter) LedgerHeight() (uint64, error) { func (lc *LedgerCommitter) LedgerHeight() (uint64, error) {
var info *pb.BlockchainInfo var info *common.BlockchainInfo
var err error var err error
if info, err = lc.ledger.GetBlockchainInfo(); err != nil { if info, err = lc.ledger.GetBlockchainInfo(); err != nil {
logger.Errorf("Cannot get blockchain info, %s\n", info) logger.Errorf("Cannot get blockchain info, %s\n", info)
......
...@@ -19,13 +19,13 @@ package committer ...@@ -19,13 +19,13 @@ package committer
import ( import (
"testing" "testing"
"github.com/hyperledger/fabric/core/ledger/testutil" "github.com/hyperledger/fabric/common/ledger/testutil"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/hyperledger/fabric/core/ledger/ledgermgmt" "github.com/hyperledger/fabric/core/ledger/ledgermgmt"
"github.com/hyperledger/fabric/core/mocks/validator" "github.com/hyperledger/fabric/core/mocks/validator"
pb "github.com/hyperledger/fabric/protos/peer" "github.com/hyperledger/fabric/protos/common"
) )
func TestKVLedgerBlockStorage(t *testing.T) { func TestKVLedgerBlockStorage(t *testing.T) {
...@@ -42,7 +42,7 @@ func TestKVLedgerBlockStorage(t *testing.T) { ...@@ -42,7 +42,7 @@ func TestKVLedgerBlockStorage(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
bcInfo, _ := ledger.GetBlockchainInfo() bcInfo, _ := ledger.GetBlockchainInfo()
testutil.AssertEquals(t, bcInfo, &pb.BlockchainInfo{ testutil.AssertEquals(t, bcInfo, &common.BlockchainInfo{
Height: 0, CurrentBlockHash: nil, PreviousBlockHash: nil}) Height: 0, CurrentBlockHash: nil, PreviousBlockHash: nil})
simulator, _ := ledger.NewTxSimulator() simulator, _ := ledger.NewTxSimulator()
...@@ -67,6 +67,6 @@ func TestKVLedgerBlockStorage(t *testing.T) { ...@@ -67,6 +67,6 @@ func TestKVLedgerBlockStorage(t *testing.T) {
bcInfo, _ = ledger.GetBlockchainInfo() bcInfo, _ = ledger.GetBlockchainInfo()
block1Hash := block1.Header.Hash() block1Hash := block1.Header.Hash()
testutil.AssertEquals(t, bcInfo, &pb.BlockchainInfo{ testutil.AssertEquals(t, bcInfo, &common.BlockchainInfo{
Height: 1, CurrentBlockHash: block1Hash, PreviousBlockHash: []byte{}}) Height: 1, CurrentBlockHash: block1Hash, PreviousBlockHash: []byte{}})
} }
...@@ -20,14 +20,13 @@ import ( ...@@ -20,14 +20,13 @@ import (
"testing" "testing"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/ledger/testutil"
util2 "github.com/hyperledger/fabric/common/util" util2 "github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/ledger/ledgermgmt" "github.com/hyperledger/fabric/core/ledger/ledgermgmt"
"github.com/hyperledger/fabric/core/ledger/testutil"
"github.com/hyperledger/fabric/core/ledger/util" "github.com/hyperledger/fabric/core/ledger/util"
mocktxvalidator "github.com/hyperledger/fabric/core/mocks/txvalidator" mocktxvalidator "github.com/hyperledger/fabric/core/mocks/txvalidator"
"github.com/hyperledger/fabric/core/mocks/validator" "github.com/hyperledger/fabric/core/mocks/validator"
"github.com/hyperledger/fabric/protos/common" "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/utils" "github.com/hyperledger/fabric/protos/utils"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
...@@ -43,7 +42,7 @@ func TestKVLedgerBlockStorage(t *testing.T) { ...@@ -43,7 +42,7 @@ func TestKVLedgerBlockStorage(t *testing.T) {
validator := &txValidator{&mocktxvalidator.Support{LedgerVal: ledger}, &validator.MockVsccValidator{}} validator := &txValidator{&mocktxvalidator.Support{LedgerVal: ledger}, &validator.MockVsccValidator{}}
bcInfo, _ := ledger.GetBlockchainInfo() bcInfo, _ := ledger.GetBlockchainInfo()
testutil.AssertEquals(t, bcInfo, &pb.BlockchainInfo{ testutil.AssertEquals(t, bcInfo, &common.BlockchainInfo{
Height: 0, CurrentBlockHash: nil, PreviousBlockHash: nil}) Height: 0, CurrentBlockHash: nil, PreviousBlockHash: nil})
simulator, _ := ledger.NewTxSimulator() simulator, _ := ledger.NewTxSimulator()
......
...@@ -24,8 +24,8 @@ import ( ...@@ -24,8 +24,8 @@ import (
"github.com/fsouza/go-dockerclient" "github.com/fsouza/go-dockerclient"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/hyperledger/fabric/common/ledger/testutil"
"github.com/hyperledger/fabric/core/config" "github.com/hyperledger/fabric/core/config"
"github.com/hyperledger/fabric/core/ledger/testutil"
) )
func TestHostConfig(t *testing.T) { func TestHostConfig(t *testing.T) {
......
...@@ -19,7 +19,7 @@ package historydb ...@@ -19,7 +19,7 @@ package historydb
import ( import (
"bytes" "bytes"
"github.com/hyperledger/fabric/core/ledger/util" "github.com/hyperledger/fabric/common/ledger/util"
) )
var compositeKeySep = []byte{0x00} var compositeKeySep = []byte{0x00}
......
...@@ -19,7 +19,7 @@ package historydb ...@@ -19,7 +19,7 @@ package historydb
import ( import (
"testing" "testing"
"github.com/hyperledger/fabric/core/ledger/testutil" "github.com/hyperledger/fabric/common/ledger/testutil"
) )
var strKeySep = string(compositeKeySep) var strKeySep = string(compositeKeySep)
......
...@@ -17,12 +17,12 @@ limitations under the License. ...@@ -17,12 +17,12 @@ limitations under the License.
package historyleveldb package historyleveldb
import ( import (
"github.com/hyperledger/fabric/common/ledger/util/leveldbhelper"
"github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/ledger/kvledger/history/historydb" "github.com/hyperledger/fabric/core/ledger/kvledger/history/historydb"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwset" "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwset"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
"github.com/hyperledger/fabric/core/ledger/ledgerconfig" "github.com/hyperledger/fabric/core/ledger/ledgerconfig"
"github.com/hyperledger/fabric/core/ledger/util/leveldbhelper"
"github.com/hyperledger/fabric/protos/common" "github.com/hyperledger/fabric/protos/common"
putils "github.com/hyperledger/fabric/protos/utils" putils "github.com/hyperledger/fabric/protos/utils"
logging "github.com/op/go-logging" logging "github.com/op/go-logging"
......
...@@ -20,10 +20,11 @@ import ( ...@@ -20,10 +20,11 @@ import (
"errors" "errors"
"fmt" "fmt"