From 5237639138d9c0997e6b9f00a6ec34cd571bdecf Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 5 Sep 2018 21:48:32 -0700 Subject: [PATCH 01/10] fix prefixIterator --- store/prefixstore.go | 124 ++++++++++++++++++++++++++++++++------ store/prefixstore_test.go | 71 +++++++++++++++++++++- 2 files changed, 174 insertions(+), 21 deletions(-) diff --git a/store/prefixstore.go b/store/prefixstore.go index 835a21038..af9e59b64 100644 --- a/store/prefixstore.go +++ b/store/prefixstore.go @@ -1,6 +1,7 @@ package store import ( + "bytes" "io" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,6 +14,18 @@ type prefixStore struct { prefix []byte } +func clone(bz []byte) (res []byte) { + res = make([]byte, len(bz)) + copy(res, bz) + return +} + +func (s prefixStore) key(key []byte) (res []byte) { + res = clone(s.prefix) + res = append(res, key...) + return +} + // Implements Store func (s prefixStore) GetStoreType() StoreType { return s.parent.GetStoreType() @@ -30,22 +43,23 @@ func (s prefixStore) CacheWrapWithTrace(w io.Writer, tc TraceContext) CacheWrap // Implements KVStore func (s prefixStore) Get(key []byte) []byte { - return s.parent.Get(append(s.prefix, key...)) + res := s.parent.Get(s.key(key)) + return res } // Implements KVStore func (s prefixStore) Has(key []byte) bool { - return s.parent.Has(append(s.prefix, key...)) + return s.parent.Has(s.key(key)) } // Implements KVStore func (s prefixStore) Set(key, value []byte) { - s.parent.Set(append(s.prefix, key...), value) + s.parent.Set(s.key(key), value) } // Implements KVStore func (s prefixStore) Delete(key []byte) { - s.parent.Delete(append(s.prefix, key...)) + s.parent.Delete(s.key(key)) } // Implements KVStore @@ -59,53 +73,83 @@ func (s prefixStore) Gas(meter GasMeter, config GasConfig) KVStore { } // Implements KVStore +// Check https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db.go#L106 func (s prefixStore) Iterator(start, end []byte) Iterator { + newstart := append(clone(s.prefix), start...) + + var newend []byte if end == nil { - end = sdk.PrefixEndBytes(s.prefix) + newend = cpIncr(s.prefix) } else { - end = append(s.prefix, end...) + newend = append(clone(s.prefix), end...) } + return prefixIterator{ prefix: s.prefix, - iter: s.parent.Iterator(append(s.prefix, start...), end), + start: newstart, + end: newend, + iter: s.parent.Iterator(newstart, newend), } + } // Implements KVStore +// Check https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db.go#L129 func (s prefixStore) ReverseIterator(start, end []byte) Iterator { - if end == nil { - end = sdk.PrefixEndBytes(s.prefix) + var newstart []byte + if start == nil { + newstart = cpIncr(s.prefix) } else { - end = append(s.prefix, end...) + newstart = append(clone(s.prefix), start...) } + + var newend []byte + if end == nil { + newend = cpIncr(s.prefix) + } else { + newend = append(clone(s.prefix), end...) + } + + iter := s.parent.ReverseIterator(newstart, newend) + if start == nil { + skipOne(iter, cpIncr(s.prefix)) + } + return prefixIterator{ prefix: s.prefix, - iter: s.parent.ReverseIterator(start, end), + start: newstart, + end: newend, + iter: iter, } } type prefixIterator struct { - prefix []byte - - iter Iterator + prefix []byte + start, end []byte + iter Iterator + valid bool } // Implements Iterator -func (iter prefixIterator) Domain() (start []byte, end []byte) { - start, end = iter.iter.Domain() - start = start[len(iter.prefix):] - end = end[len(iter.prefix):] - return +func (iter prefixIterator) Domain() ([]byte, []byte) { + return iter.start, iter.end } // Implements Iterator func (iter prefixIterator) Valid() bool { - return iter.iter.Valid() + return iter.valid && iter.iter.Valid() } // Implements Iterator func (iter prefixIterator) Next() { + if !iter.valid { + panic("prefixIterator invalid, cannot call Next()") + } iter.iter.Next() + if !iter.iter.Valid() || !bytes.HasPrefix(iter.iter.Key(), iter.prefix) { + iter.iter.Close() + iter.valid = false + } } // Implements Iterator @@ -124,3 +168,43 @@ func (iter prefixIterator) Value() []byte { func (iter prefixIterator) Close() { iter.iter.Close() } + +// copied from github.com/tendermint/tendermint/libs/db/prefix_db.go +func stripPrefix(key []byte, prefix []byte) []byte { + if len(key) < len(prefix) || !bytes.Equal(key[:len(prefix)], prefix) { + panic("should not happen") + } + return key[len(prefix):] +} + +// wrapping sdk.PrefixEndBytes +func cpIncr(bz []byte) []byte { + return sdk.PrefixEndBytes(bz) +} + +// copied from github.com/tendermint/tendermint/libs/db/util.go +func cpDecr(bz []byte) (ret []byte) { + if len(bz) == 0 { + panic("cpDecr expects non-zero bz length") + } + ret = clone(bz) + for i := len(bz) - 1; i >= 0; i-- { + if ret[i] > byte(0x00) { + ret[i]-- + return + } + ret[i] = byte(0xFF) + if i == 0 { + return nil + } + } + return nil +} + +func skipOne(iter Iterator, skipKey []byte) { + if iter.Valid() { + if bytes.Equal(iter.Key(), skipKey) { + iter.Next() + } + } +} diff --git a/store/prefixstore_test.go b/store/prefixstore_test.go index 49bc68037..cf50b9dd4 100644 --- a/store/prefixstore_test.go +++ b/store/prefixstore_test.go @@ -1,6 +1,7 @@ package store import ( + "bytes" "math/rand" "testing" @@ -105,7 +106,75 @@ func TestPrefixStoreIterate(t *testing.T) { pIter.Next() } - require.Equal(t, bIter.Valid(), pIter.Valid()) bIter.Close() pIter.Close() } + +func TestPrefixStoreIteratorEdgeCase(t *testing.T) { + db := dbm.NewMemDB() + baseStore := dbStoreAdapter{db} + + // overflow in cpIncr + prefix := []byte{0xAA, 0xFF, 0xFF} + prefixStore := baseStore.Prefix(prefix) + + // ascending order + baseStore.Set([]byte{0xAA, 0xFF, 0xFE}, []byte{}) + baseStore.Set([]byte{0xAA, 0xFF, 0xFE, 0x00}, []byte{}) + baseStore.Set([]byte{0xAA, 0xFF, 0xFF}, []byte{}) + baseStore.Set([]byte{0xAA, 0xFF, 0xFF, 0x00}, []byte{}) + baseStore.Set([]byte{0xAB}, []byte{}) + baseStore.Set([]byte{0xAB, 0x00}, []byte{}) + baseStore.Set([]byte{0xAB, 0x00, 0x00}, []byte{}) + + for iter := prefixStore.Iterator(nil, nil); iter.Valid(); iter.Next() { + require.True(t, bytes.HasPrefix(iter.Key(), prefix)) + } +} + +func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { + db := dbm.NewMemDB() + baseStore := dbStoreAdapter{db} + + // overflow in cpIncr + prefix := []byte{0xAA, 0xFF, 0xFF} + prefixStore := baseStore.Prefix(prefix) + + // descending order + baseStore.Set([]byte{0xAB, 0x00, 0x00}, []byte{}) + baseStore.Set([]byte{0xAB, 0x00}, []byte{}) + baseStore.Set([]byte{0xAB}, []byte{}) + baseStore.Set([]byte{0xAA, 0xFF, 0xFF, 0x00}, []byte{}) + baseStore.Set([]byte{0xAA, 0xFF, 0xFF}, []byte{}) + baseStore.Set([]byte{0xAA, 0xFF, 0xFE, 0x00}, []byte{}) + baseStore.Set([]byte{0xAA, 0xFF, 0xFE}, []byte{}) + + iter := prefixStore.ReverseIterator(nil, nil) + for ; iter.Valid(); iter.Next() { + require.True(t, bytes.HasPrefix(iter.Key(), prefix)) + } + + iter.Close() + + db = dbm.NewMemDB() + baseStore = dbStoreAdapter{db} + + // underflow in cpDecr + prefix = []byte{0xAA, 0x00, 0x00} + prefixStore = baseStore.Prefix(prefix) + + baseStore.Set([]byte{0xAB, 0x00, 0x01, 0x00, 0x00}, []byte{}) + baseStore.Set([]byte{0xAB, 0x00, 0x01, 0x00}, []byte{}) + baseStore.Set([]byte{0xAB, 0x00, 0x01}, []byte{}) + baseStore.Set([]byte{0xAA, 0x00, 0x00, 0x00}, []byte{}) + baseStore.Set([]byte{0xAA, 0x00, 0x00}, []byte{}) + baseStore.Set([]byte{0xA9, 0xFF, 0xFF, 0x00}, []byte{}) + baseStore.Set([]byte{0xA9, 0xFF, 0xFF}, []byte{}) + + iter = prefixStore.ReverseIterator(nil, nil) + for ; iter.Valid(); iter.Next() { + require.True(t, bytes.HasPrefix(iter.Key(), prefix)) + } + + iter.Close() +} From 5091d1688dfa7ae391735fd2edb1bb1914a5da3d Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 11 Sep 2018 15:59:58 +0900 Subject: [PATCH 02/10] partially apply requests --- store/prefixstore.go | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/store/prefixstore.go b/store/prefixstore.go index af9e59b64..c060bf5c3 100644 --- a/store/prefixstore.go +++ b/store/prefixstore.go @@ -14,15 +14,15 @@ type prefixStore struct { prefix []byte } -func clone(bz []byte) (res []byte) { - res = make([]byte, len(bz)) +func cloneAppend(bz []byte, tail []byte) (res []byte) { + res = make([]byte, len(bz)+len(tail)) copy(res, bz) + res = append(res, bz...) return } func (s prefixStore) key(key []byte) (res []byte) { - res = clone(s.prefix) - res = append(res, key...) + res = cloneAppend(s.prefix, key) return } @@ -75,19 +75,19 @@ func (s prefixStore) Gas(meter GasMeter, config GasConfig) KVStore { // Implements KVStore // Check https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db.go#L106 func (s prefixStore) Iterator(start, end []byte) Iterator { - newstart := append(clone(s.prefix), start...) + newstart := cloneAppend(s.prefix, start) var newend []byte if end == nil { newend = cpIncr(s.prefix) } else { - newend = append(clone(s.prefix), end...) + newend = cloneAppend(s.prefix, end) } return prefixIterator{ prefix: s.prefix, - start: newstart, - end: newend, + start: start, + end: end, iter: s.parent.Iterator(newstart, newend), } @@ -100,14 +100,14 @@ func (s prefixStore) ReverseIterator(start, end []byte) Iterator { if start == nil { newstart = cpIncr(s.prefix) } else { - newstart = append(clone(s.prefix), start...) + newstart = cloneAppend(s.prefix, start) } var newend []byte if end == nil { - newend = cpIncr(s.prefix) + newend = cpDecr(s.prefix) } else { - newend = append(clone(s.prefix), end...) + newend = cloneAppend(s.prefix, end) } iter := s.parent.ReverseIterator(newstart, newend) @@ -117,8 +117,8 @@ func (s prefixStore) ReverseIterator(start, end []byte) Iterator { return prefixIterator{ prefix: s.prefix, - start: newstart, - end: newend, + start: start, + end: end, iter: iter, } } @@ -187,7 +187,8 @@ func cpDecr(bz []byte) (ret []byte) { if len(bz) == 0 { panic("cpDecr expects non-zero bz length") } - ret = clone(bz) + ret = make([]byte, len(bz)) + copy(ret, bz) for i := len(bz) - 1; i >= 0; i-- { if ret[i] > byte(0x00) { ret[i]-- From c770e74571dc5ef9c12b062e391028de47bc82c7 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 9 Oct 2018 03:06:16 +0900 Subject: [PATCH 03/10] fix cloneAppend --- store/prefixstore.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/prefixstore.go b/store/prefixstore.go index c060bf5c3..2b70a28ff 100644 --- a/store/prefixstore.go +++ b/store/prefixstore.go @@ -17,7 +17,7 @@ type prefixStore struct { func cloneAppend(bz []byte, tail []byte) (res []byte) { res = make([]byte, len(bz)+len(tail)) copy(res, bz) - res = append(res, bz...) + copy(res[len(bz):], tail) return } From e7c76eb344ad211ccb63f969dcb2e67e89dcf859 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 9 Oct 2018 04:43:55 +0900 Subject: [PATCH 04/10] port tests from tmlibs, fix tests --- store/prefixstore.go | 31 ++--- store/prefixstore_test.go | 230 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 238 insertions(+), 23 deletions(-) diff --git a/store/prefixstore.go b/store/prefixstore.go index 2b70a28ff..a29459e4e 100644 --- a/store/prefixstore.go +++ b/store/prefixstore.go @@ -9,6 +9,10 @@ import ( var _ KVStore = prefixStore{} +// prefixStore is similar with tendermint/tendermint/libs/db/prefix_db +// both gives access only to the limited subset of the store +// for convinience or safety + type prefixStore struct { parent KVStore prefix []byte @@ -84,13 +88,9 @@ func (s prefixStore) Iterator(start, end []byte) Iterator { newend = cloneAppend(s.prefix, end) } - return prefixIterator{ - prefix: s.prefix, - start: start, - end: end, - iter: s.parent.Iterator(newstart, newend), - } + iter := s.parent.Iterator(newstart, newend) + return newPrefixIterator(s.prefix, start, end, iter) } // Implements KVStore @@ -115,12 +115,7 @@ func (s prefixStore) ReverseIterator(start, end []byte) Iterator { skipOne(iter, cpIncr(s.prefix)) } - return prefixIterator{ - prefix: s.prefix, - start: start, - end: end, - iter: iter, - } + return newPrefixIterator(s.prefix, start, end, iter) } type prefixIterator struct { @@ -130,6 +125,16 @@ type prefixIterator struct { valid bool } +func newPrefixIterator(prefix, start, end []byte, parent Iterator) prefixIterator { + return prefixIterator{ + prefix: prefix, + start: start, + end: end, + iter: parent, + valid: parent.Valid() && bytes.HasPrefix(parent.Key(), prefix), + } +} + // Implements Iterator func (iter prefixIterator) Domain() ([]byte, []byte) { return iter.start, iter.end @@ -155,7 +160,7 @@ func (iter prefixIterator) Next() { // Implements Iterator func (iter prefixIterator) Key() (key []byte) { key = iter.iter.Key() - key = key[len(iter.prefix):] + key = stripPrefix(key, iter.prefix) return } diff --git a/store/prefixstore_test.go b/store/prefixstore_test.go index cf50b9dd4..499f30d50 100644 --- a/store/prefixstore_test.go +++ b/store/prefixstore_test.go @@ -1,7 +1,6 @@ package store import ( - "bytes" "math/rand" "testing" @@ -127,9 +126,17 @@ func TestPrefixStoreIteratorEdgeCase(t *testing.T) { baseStore.Set([]byte{0xAB, 0x00}, []byte{}) baseStore.Set([]byte{0xAB, 0x00, 0x00}, []byte{}) - for iter := prefixStore.Iterator(nil, nil); iter.Valid(); iter.Next() { - require.True(t, bytes.HasPrefix(iter.Key(), prefix)) - } + iter := prefixStore.Iterator(nil, nil) + + checkDomain(t, iter, nil, nil) + checkItem(t, iter, []byte{}, bz("")) + checkNext(t, iter, true) + checkItem(t, iter, []byte{0x00}, bz("")) + checkNext(t, iter, false) + + checkInvalid(t, iter) + + iter.Close() } func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { @@ -150,9 +157,14 @@ func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { baseStore.Set([]byte{0xAA, 0xFF, 0xFE}, []byte{}) iter := prefixStore.ReverseIterator(nil, nil) - for ; iter.Valid(); iter.Next() { - require.True(t, bytes.HasPrefix(iter.Key(), prefix)) - } + + checkDomain(t, iter, nil, nil) + checkItem(t, iter, []byte{0x00}, bz("")) + checkNext(t, iter, true) + checkItem(t, iter, []byte{}, bz("")) + checkNext(t, iter, false) + + checkInvalid(t, iter) iter.Close() @@ -172,9 +184,207 @@ func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) { baseStore.Set([]byte{0xA9, 0xFF, 0xFF}, []byte{}) iter = prefixStore.ReverseIterator(nil, nil) - for ; iter.Valid(); iter.Next() { - require.True(t, bytes.HasPrefix(iter.Key(), prefix)) - } + + checkDomain(t, iter, nil, nil) + checkItem(t, iter, []byte{0x00}, bz("")) + checkNext(t, iter, true) + checkItem(t, iter, []byte{}, bz("")) + checkNext(t, iter, false) + + checkInvalid(t, iter) iter.Close() } + +// Tests below are ported from https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db_test.go + +func mockStoreWithStuff() sdk.KVStore { + db := dbm.NewMemDB() + store := dbStoreAdapter{db} + // Under "key" prefix + store.Set(bz("key"), bz("value")) + store.Set(bz("key1"), bz("value1")) + store.Set(bz("key2"), bz("value2")) + store.Set(bz("key3"), bz("value3")) + store.Set(bz("something"), bz("else")) + store.Set(bz(""), bz("")) + store.Set(bz("k"), bz("val")) + store.Set(bz("ke"), bz("valu")) + store.Set(bz("kee"), bz("valuu")) + return store +} + +func checkValue(t *testing.T, store sdk.KVStore, key []byte, expected []byte) { + bz := store.Get(key) + require.Equal(t, expected, bz) +} + +func checkValid(t *testing.T, itr sdk.Iterator, expected bool) { + valid := itr.Valid() + require.Equal(t, expected, valid) +} + +func checkNext(t *testing.T, itr sdk.Iterator, expected bool) { + itr.Next() + valid := itr.Valid() + require.Equal(t, expected, valid) +} + +func checkDomain(t *testing.T, itr sdk.Iterator, start, end []byte) { + ds, de := itr.Domain() + require.Equal(t, start, ds) + require.Equal(t, end, de) +} + +func checkItem(t *testing.T, itr sdk.Iterator, key, value []byte) { + require.Exactly(t, key, itr.Key()) + require.Exactly(t, value, itr.Value()) +} + +func checkInvalid(t *testing.T, itr sdk.Iterator) { + checkValid(t, itr, false) + checkKeyPanics(t, itr) + checkValuePanics(t, itr) + checkNextPanics(t, itr) +} + +func checkKeyPanics(t *testing.T, itr sdk.Iterator) { + require.Panics(t, func() { itr.Key() }) +} + +func checkValuePanics(t *testing.T, itr sdk.Iterator) { + require.Panics(t, func() { itr.Value() }) +} + +func checkNextPanics(t *testing.T, itr sdk.Iterator) { + require.Panics(t, func() { itr.Next() }) +} + +func TestPrefixDBSimple(t *testing.T) { + store := mockStoreWithStuff() + pstore := store.Prefix(bz("key")) + + checkValue(t, pstore, bz("key"), nil) + checkValue(t, pstore, bz(""), bz("value")) + checkValue(t, pstore, bz("key1"), nil) + checkValue(t, pstore, bz("1"), bz("value1")) + checkValue(t, pstore, bz("key2"), nil) + checkValue(t, pstore, bz("2"), bz("value2")) + checkValue(t, pstore, bz("key3"), nil) + checkValue(t, pstore, bz("3"), bz("value3")) + checkValue(t, pstore, bz("something"), nil) + checkValue(t, pstore, bz("k"), nil) + checkValue(t, pstore, bz("ke"), nil) + checkValue(t, pstore, bz("kee"), nil) +} + +func TestPrefixDBIterator1(t *testing.T) { + store := mockStoreWithStuff() + pstore := store.Prefix(bz("key")) + + itr := pstore.Iterator(nil, nil) + checkDomain(t, itr, nil, nil) + checkItem(t, itr, bz(""), bz("value")) + checkNext(t, itr, true) + checkItem(t, itr, bz("1"), bz("value1")) + checkNext(t, itr, true) + checkItem(t, itr, bz("2"), bz("value2")) + checkNext(t, itr, true) + checkItem(t, itr, bz("3"), bz("value3")) + checkNext(t, itr, false) + checkInvalid(t, itr) + itr.Close() +} + +func TestPrefixDBIterator2(t *testing.T) { + store := mockStoreWithStuff() + pstore := store.Prefix(bz("key")) + + itr := pstore.Iterator(nil, bz("")) + checkDomain(t, itr, nil, bz("")) + checkInvalid(t, itr) + itr.Close() +} + +func TestPrefixDBIterator3(t *testing.T) { + store := mockStoreWithStuff() + pstore := store.Prefix(bz("key")) + + itr := pstore.Iterator(bz(""), nil) + checkDomain(t, itr, bz(""), nil) + checkItem(t, itr, bz(""), bz("value")) + checkNext(t, itr, true) + checkItem(t, itr, bz("1"), bz("value1")) + checkNext(t, itr, true) + checkItem(t, itr, bz("2"), bz("value2")) + checkNext(t, itr, true) + checkItem(t, itr, bz("3"), bz("value3")) + checkNext(t, itr, false) + checkInvalid(t, itr) + itr.Close() +} + +func TestPrefixDBIterator4(t *testing.T) { + store := mockStoreWithStuff() + pstore := store.Prefix(bz("key")) + + itr := pstore.Iterator(bz(""), bz("")) + checkDomain(t, itr, bz(""), bz("")) + checkInvalid(t, itr) + itr.Close() +} + +func TestPrefixDBReverseIterator1(t *testing.T) { + store := mockStoreWithStuff() + pstore := store.Prefix(bz("key")) + + itr := pstore.ReverseIterator(nil, nil) + checkDomain(t, itr, nil, nil) + checkItem(t, itr, bz("3"), bz("value3")) + checkNext(t, itr, true) + checkItem(t, itr, bz("2"), bz("value2")) + checkNext(t, itr, true) + checkItem(t, itr, bz("1"), bz("value1")) + checkNext(t, itr, true) + checkItem(t, itr, bz(""), bz("value")) + checkNext(t, itr, false) + checkInvalid(t, itr) + itr.Close() +} + +func TestPrefixDBReverseIterator2(t *testing.T) { + store := mockStoreWithStuff() + pstore := store.Prefix(bz("key")) + + itr := pstore.ReverseIterator(nil, bz("")) + checkDomain(t, itr, nil, bz("")) + checkItem(t, itr, bz("3"), bz("value3")) + checkNext(t, itr, true) + checkItem(t, itr, bz("2"), bz("value2")) + checkNext(t, itr, true) + checkItem(t, itr, bz("1"), bz("value1")) + checkNext(t, itr, false) + checkInvalid(t, itr) + itr.Close() +} + +func TestPrefixDBReverseIterator3(t *testing.T) { + store := mockStoreWithStuff() + pstore := store.Prefix(bz("key")) + + itr := pstore.ReverseIterator(bz(""), nil) + checkDomain(t, itr, bz(""), nil) + checkItem(t, itr, bz(""), bz("value")) + checkNext(t, itr, false) + checkInvalid(t, itr) + itr.Close() +} + +func TestPrefixDBReverseIterator4(t *testing.T) { + store := mockStoreWithStuff() + pstore := store.Prefix(bz("key")) + + itr := pstore.ReverseIterator(bz(""), bz("")) + checkInvalid(t, itr) + itr.Close() +} From 43b3352c87d8e44c8d968cd06b14c58efbaf59b3 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 9 Oct 2018 05:06:40 +0900 Subject: [PATCH 05/10] fix Close() --- store/prefixstore.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/store/prefixstore.go b/store/prefixstore.go index a29459e4e..04d268057 100644 --- a/store/prefixstore.go +++ b/store/prefixstore.go @@ -152,13 +152,15 @@ func (iter prefixIterator) Next() { } iter.iter.Next() if !iter.iter.Valid() || !bytes.HasPrefix(iter.iter.Key(), iter.prefix) { - iter.iter.Close() iter.valid = false } } // Implements Iterator func (iter prefixIterator) Key() (key []byte) { + if !iter.valid { + panic("prefixIterator invalid, cannot call Key()") + } key = iter.iter.Key() key = stripPrefix(key, iter.prefix) return @@ -166,6 +168,9 @@ func (iter prefixIterator) Key() (key []byte) { // Implements Iterator func (iter prefixIterator) Value() []byte { + if !iter.valid() { + panic("prefixIterator invalid, cannot call Value()") + } return iter.iter.Value() } From ed9b29c856801db32c6759170fbf32c30d248c38 Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 9 Oct 2018 05:18:43 +0900 Subject: [PATCH 06/10] fix typo --- store/prefixstore.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/prefixstore.go b/store/prefixstore.go index 04d268057..981d82131 100644 --- a/store/prefixstore.go +++ b/store/prefixstore.go @@ -168,7 +168,7 @@ func (iter prefixIterator) Key() (key []byte) { // Implements Iterator func (iter prefixIterator) Value() []byte { - if !iter.valid() { + if !iter.valid { panic("prefixIterator invalid, cannot call Value()") } return iter.iter.Value() From 0cbb37ff034396e837dc1cd81b82032cd068159e Mon Sep 17 00:00:00 2001 From: mossid Date: Tue, 9 Oct 2018 05:37:18 +0900 Subject: [PATCH 07/10] rm Close() from Next() --- store/prefixstore.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/store/prefixstore.go b/store/prefixstore.go index 981d82131..55af1084e 100644 --- a/store/prefixstore.go +++ b/store/prefixstore.go @@ -118,6 +118,8 @@ func (s prefixStore) ReverseIterator(start, end []byte) Iterator { return newPrefixIterator(s.prefix, start, end, iter) } +var _ sdk.Iterator = (*prefixIterator)(nil) + type prefixIterator struct { prefix []byte start, end []byte @@ -125,8 +127,8 @@ type prefixIterator struct { valid bool } -func newPrefixIterator(prefix, start, end []byte, parent Iterator) prefixIterator { - return prefixIterator{ +func newPrefixIterator(prefix, start, end []byte, parent Iterator) *prefixIterator { + return &prefixIterator{ prefix: prefix, start: start, end: end, @@ -136,17 +138,17 @@ func newPrefixIterator(prefix, start, end []byte, parent Iterator) prefixIterato } // Implements Iterator -func (iter prefixIterator) Domain() ([]byte, []byte) { +func (iter *prefixIterator) Domain() ([]byte, []byte) { return iter.start, iter.end } // Implements Iterator -func (iter prefixIterator) Valid() bool { +func (iter *prefixIterator) Valid() bool { return iter.valid && iter.iter.Valid() } // Implements Iterator -func (iter prefixIterator) Next() { +func (iter *prefixIterator) Next() { if !iter.valid { panic("prefixIterator invalid, cannot call Next()") } @@ -157,7 +159,7 @@ func (iter prefixIterator) Next() { } // Implements Iterator -func (iter prefixIterator) Key() (key []byte) { +func (iter *prefixIterator) Key() (key []byte) { if !iter.valid { panic("prefixIterator invalid, cannot call Key()") } @@ -167,7 +169,7 @@ func (iter prefixIterator) Key() (key []byte) { } // Implements Iterator -func (iter prefixIterator) Value() []byte { +func (iter *prefixIterator) Value() []byte { if !iter.valid { panic("prefixIterator invalid, cannot call Value()") } @@ -175,7 +177,7 @@ func (iter prefixIterator) Value() []byte { } // Implements Iterator -func (iter prefixIterator) Close() { +func (iter *prefixIterator) Close() { iter.iter.Close() } From 963bcaf66fadf1954dfa3ed03dca7f57fa092528 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Tue, 9 Oct 2018 23:13:37 +0200 Subject: [PATCH 08/10] Fix IBC paper link --- docs/spec/ibc/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/spec/ibc/README.md b/docs/spec/ibc/README.md index e9448bca8..b42bb3592 100644 --- a/docs/spec/ibc/README.md +++ b/docs/spec/ibc/README.md @@ -8,7 +8,7 @@ The core IBC protocol is payload-agnostic. On top of IBC, developers can impleme IBC requires two blockchains with cheaply verifiable rapid finality and Merkle tree substate proofs. The protocol makes no assumptions of block confirmation times or maximum network latency of packet transmissions, and the two consensus algorithms remain completely independent. Each chain maintains a local partial order and inter-chain message sequencing ensures cross-chain linearity. Once the two chains have registered a trust relationship, cryptographically verifiable packets can be sent between them. -IBC was first outlined in the [Cosmos Whitepaper](https://github.com/cosmos/cosmos/blob/master/WHITEPAPER.md#inter-blockchain-communication-ibc), and later described in more detail by the [IBC specification paper](https://github.com/cosmos/ibc/raw/master/CosmosIBCSpecification.pdf). This document supersedes both. It explains the requirements and structure of the protocol and provides sufficient detail for both analysis and implementation. +IBC was first outlined in the [Cosmos Whitepaper](https://github.com/cosmos/cosmos/blob/master/WHITEPAPER.md#inter-blockchain-communication-ibc), and later described in more detail by the [IBC specification paper](https://github.com/cosmos/ibc/blob/master/CosmosIBCSpecification.pdf). This document supersedes both. It explains the requirements and structure of the protocol and provides sufficient detail for both analysis and implementation. ## Contents From 0f4a03b44e1d34795a1f5828d26bdf8d6ce705d5 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Wed, 10 Oct 2018 15:45:41 -0700 Subject: [PATCH 09/10] Alessio/server refactor (#2472) * Add arg to PrintUnsignedStdTx() to actually operate in offline mode * WIP simplifying server module * Expose ExternalIP() * Move {GenTx,Init}Cmd into gaia's new init package --- .gitignore | 3 + client/utils/utils.go | 14 +- cmd/gaia/cmd/gaiad/main.go | 9 +- cmd/gaia/init/init.go | 321 ++++++++++++++++++++++++ cmd/gaia/init/init_test.go | 111 ++++++++ {server => cmd/gaia/init}/testnet.go | 11 +- examples/basecoin/cmd/basecoind/main.go | 10 +- examples/democoin/cmd/democoind/main.go | 7 +- server/constructors.go | 77 ++---- server/export.go | 12 +- server/export_test.go | 53 ---- server/init.go | 313 +---------------------- server/init_test.go | 47 ---- server/start.go | 20 +- server/start_test.go | 52 ---- server/test_helpers.go | 4 +- server/util.go | 10 +- x/bank/client/cli/sendtx.go | 2 +- x/gov/client/cli/tx.go | 6 +- x/ibc/client/cli/ibctx.go | 2 +- x/slashing/client/cli/tx.go | 2 +- x/stake/client/cli/tx.go | 10 +- 22 files changed, 533 insertions(+), 563 deletions(-) create mode 100644 cmd/gaia/init/init.go create mode 100644 cmd/gaia/init/init_test.go rename {server => cmd/gaia/init}/testnet.go (95%) delete mode 100644 server/export_test.go delete mode 100644 server/init_test.go delete mode 100644 server/start_test.go diff --git a/.gitignore b/.gitignore index c6713cae8..dec322b7b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ .DS_Store *.swp *.swo +*.swl +*.swm +*.swn .vscode .idea diff --git a/client/utils/utils.go b/client/utils/utils.go index 9e72c552d..364b9e692 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -87,8 +87,14 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc * } // PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout. -func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (err error) { - stdTx, err := buildUnsignedStdTx(txBldr, cliCtx, msgs) +// Don't perform online validation or lookups if offline is true. +func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg, offline bool) (err error) { + var stdTx auth.StdTx + if offline { + stdTx, err = buildUnsignedStdTxOffline(txBldr, cliCtx, msgs) + } else { + stdTx, err = buildUnsignedStdTx(txBldr, cliCtx, msgs) + } if err != nil { return } @@ -204,6 +210,10 @@ func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg if err != nil { return } + return buildUnsignedStdTxOffline(txBldr, cliCtx, msgs) +} + +func buildUnsignedStdTxOffline(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) { if txBldr.SimulateGas { var name string name, err = cliCtx.GetFromName() diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 0b5f0e505..adfb12d57 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -16,6 +16,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" + gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init" "github.com/cosmos/cosmos-sdk/server" ) @@ -28,10 +29,12 @@ func main() { Short: "Gaia Daemon (server)", PersistentPreRunE: server.PersistentPreRunEFn(ctx), } + appInit := app.GaiaAppInit() + rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit)) + rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit)) - server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), - server.ConstructAppCreator(newApp, "gaia"), - server.ConstructAppExporter(exportAppStateAndTMValidators, "gaia")) + server.AddCommands(ctx, cdc, rootCmd, appInit, + newApp, exportAppStateAndTMValidators) // prepare and add flags executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome) diff --git a/cmd/gaia/init/init.go b/cmd/gaia/init/init.go new file mode 100644 index 000000000..a04c1d2ae --- /dev/null +++ b/cmd/gaia/init/init.go @@ -0,0 +1,321 @@ +package init + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "sort" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + servercfg "github.com/cosmos/cosmos-sdk/server/config" + "github.com/spf13/cobra" + "github.com/spf13/viper" + cfg "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/libs/cli" + "github.com/tendermint/tendermint/libs/common" + "github.com/tendermint/tendermint/p2p" + "github.com/tendermint/tendermint/privval" + "github.com/tendermint/tendermint/types" +) + +// get cmd to initialize all files for tendermint and application +func GenTxCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command { + cmd := &cobra.Command{ + Use: "gen-tx", + Short: "Create genesis transaction file (under [--home]/config/gentx/gentx-[nodeID].json)", + Args: cobra.NoArgs, + RunE: func(_ *cobra.Command, args []string) error { + config := ctx.Config + config.SetRoot(viper.GetString(cli.HomeFlag)) + + ip := viper.GetString(server.FlagIP) + if len(ip) == 0 { + eip, err := server.ExternalIP() + if err != nil { + return err + } + ip = eip + } + + genTxConfig := servercfg.GenTx{ + viper.GetString(server.FlagName), + viper.GetString(server.FlagClientHome), + viper.GetBool(server.FlagOWK), + ip, + } + cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig) + if err != nil { + return err + } + toPrint := struct { + AppMessage json.RawMessage `json:"app_message"` + GenTxFile json.RawMessage `json:"gen_tx_file"` + }{ + cliPrint, + genTxFile, + } + out, err := codec.MarshalJSONIndent(cdc, toPrint) + if err != nil { + return err + } + fmt.Println(string(out)) + return nil + }, + } + cmd.Flags().String(server.FlagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine") + cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) + return cmd +} + +// NOTE: This will update (write) the config file with +// updated name (moniker) for node. +func gentxWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, genTxConfig servercfg.GenTx) ( + cliPrint json.RawMessage, genTxFile json.RawMessage, err error) { + nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) + if err != nil { + return + } + nodeID := string(nodeKey.ID()) + pubKey := readOrCreatePrivValidator(config) + + appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) + if err != nil { + return + } + + tx := server.GenesisTx{ + NodeID: nodeID, + IP: genTxConfig.IP, + Validator: validator, + AppGenTx: appGenTx, + } + bz, err := codec.MarshalJSONIndent(cdc, tx) + if err != nil { + return + } + genTxFile = json.RawMessage(bz) + name := fmt.Sprintf("gentx-%v.json", nodeID) + writePath := filepath.Join(config.RootDir, "config", "gentx") + file := filepath.Join(writePath, name) + err = common.EnsureDir(writePath, 0700) + if err != nil { + return + } + err = common.WriteFile(file, bz, 0644) + if err != nil { + return + } + + // Write updated config with moniker + config.Moniker = genTxConfig.Name + configFilePath := filepath.Join(config.RootDir, "config", "config.toml") + cfg.WriteConfigFile(configFilePath, config) + + return +} + +// get cmd to initialize all files for tendermint and application +// nolint: golint +func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command { + cmd := &cobra.Command{ + Use: "init", + Short: "Initialize genesis config, priv-validator file, and p2p-node file", + Args: cobra.NoArgs, + RunE: func(_ *cobra.Command, _ []string) error { + + config := ctx.Config + config.SetRoot(viper.GetString(cli.HomeFlag)) + initConfig := server.InitConfig{ + viper.GetString(server.FlagChainID), + viper.GetBool(server.FlagWithTxs), + filepath.Join(config.RootDir, "config", "gentx"), + viper.GetBool(server.FlagOverwrite), + } + + chainID, nodeID, appMessage, err := initWithConfig(cdc, appInit, config, initConfig) + if err != nil { + return err + } + // print out some key information + toPrint := struct { + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + AppMessage json.RawMessage `json:"app_message"` + }{ + chainID, + nodeID, + appMessage, + } + out, err := codec.MarshalJSONIndent(cdc, toPrint) + if err != nil { + return err + } + fmt.Println(string(out)) + return nil + }, + } + cmd.Flags().BoolP(server.FlagOverwrite, "o", false, "overwrite the genesis.json file") + cmd.Flags().String(server.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") + cmd.Flags().Bool(server.FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/") + cmd.Flags().AddFlagSet(appInit.FlagsAppGenState) + cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided + cmd.AddCommand(GenTxCmd(ctx, cdc, appInit)) + return cmd +} + +func initWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, initConfig server.InitConfig) ( + chainID string, nodeID string, appMessage json.RawMessage, err error) { + nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) + if err != nil { + return + } + nodeID = string(nodeKey.ID()) + pubKey := readOrCreatePrivValidator(config) + + if initConfig.ChainID == "" { + initConfig.ChainID = fmt.Sprintf("test-chain-%v", common.RandStr(6)) + } + chainID = initConfig.ChainID + + genFile := config.GenesisFile() + if !initConfig.Overwrite && common.FileExists(genFile) { + err = fmt.Errorf("genesis.json file already exists: %v", genFile) + return + } + + // process genesis transactions, or otherwise create one for defaults + var appGenTxs []json.RawMessage + var validators []types.GenesisValidator + var persistentPeers string + + if initConfig.GenTxs { + validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc) + if err != nil { + return + } + config.P2P.PersistentPeers = persistentPeers + configFilePath := filepath.Join(config.RootDir, "config", "config.toml") + cfg.WriteConfigFile(configFilePath, config) + } else { + genTxConfig := servercfg.GenTx{ + viper.GetString(server.FlagName), + viper.GetString(server.FlagClientHome), + viper.GetBool(server.FlagOWK), + "127.0.0.1", + } + + // Write updated config with moniker + config.Moniker = genTxConfig.Name + configFilePath := filepath.Join(config.RootDir, "config", "config.toml") + cfg.WriteConfigFile(configFilePath, config) + appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) + appMessage = am + if err != nil { + return "", "", nil, err + } + validators = []types.GenesisValidator{validator} + appGenTxs = []json.RawMessage{appGenTx} + } + + appState, err := appInit.AppGenState(cdc, appGenTxs) + if err != nil { + return + } + + err = writeGenesisFile(cdc, genFile, initConfig.ChainID, validators, appState) + if err != nil { + return + } + + return +} + +// append a genesis-piece +func processGenTxs(genTxsDir string, cdc *codec.Codec) ( + validators []types.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) { + + var fos []os.FileInfo + fos, err = ioutil.ReadDir(genTxsDir) + if err != nil { + return + } + + genTxs := make(map[string]server.GenesisTx) + var nodeIDs []string + for _, fo := range fos { + filename := path.Join(genTxsDir, fo.Name()) + if !fo.IsDir() && (path.Ext(filename) != ".json") { + continue + } + + // get the genTx + var bz []byte + bz, err = ioutil.ReadFile(filename) + if err != nil { + return + } + var genTx server.GenesisTx + err = cdc.UnmarshalJSON(bz, &genTx) + if err != nil { + return + } + + genTxs[genTx.NodeID] = genTx + nodeIDs = append(nodeIDs, genTx.NodeID) + } + + sort.Strings(nodeIDs) + + for _, nodeID := range nodeIDs { + genTx := genTxs[nodeID] + + // combine some stuff + validators = append(validators, genTx.Validator) + appGenTxs = append(appGenTxs, genTx.AppGenTx) + + // Add a persistent peer + comma := "," + if len(persistentPeers) == 0 { + comma = "" + } + persistentPeers += fmt.Sprintf("%s%s@%s:26656", comma, genTx.NodeID, genTx.IP) + } + + return +} + +// read of create the private key file for this config +func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { + // private validator + privValFile := tmConfig.PrivValidatorFile() + var privValidator *privval.FilePV + if common.FileExists(privValFile) { + privValidator = privval.LoadFilePV(privValFile) + } else { + privValidator = privval.GenFilePV(privValFile) + privValidator.Save() + } + return privValidator.GetPubKey() +} + +// writeGenesisFile creates and writes the genesis configuration to disk. An +// error is returned if building or writing the configuration to file fails. +// nolint: unparam +func writeGenesisFile(cdc *codec.Codec, genesisFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage) error { + genDoc := types.GenesisDoc{ + ChainID: chainID, + Validators: validators, + AppState: appState, + } + + if err := genDoc.ValidateAndComplete(); err != nil { + return err + } + + return genDoc.SaveAs(genesisFile) +} diff --git a/cmd/gaia/init/init_test.go b/cmd/gaia/init/init_test.go new file mode 100644 index 000000000..3a7f0a358 --- /dev/null +++ b/cmd/gaia/init/init_test.go @@ -0,0 +1,111 @@ +package init + +import ( + "bytes" + "io" + "io/ioutil" + "os" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/server/mock" + "github.com/stretchr/testify/require" + abciServer "github.com/tendermint/tendermint/abci/server" + tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" + "github.com/tendermint/tendermint/libs/log" +) + +func TestInitCmd(t *testing.T) { + defer server.SetupViper(t)() + + logger := log.NewNopLogger() + cfg, err := tcmd.ParseConfig() + require.Nil(t, err) + ctx := server.NewContext(cfg, logger) + cdc := codec.New() + appInit := server.AppInit{ + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, + } + cmd := InitCmd(ctx, cdc, appInit) + err = cmd.RunE(nil, nil) + require.NoError(t, err) +} + +func TestEmptyState(t *testing.T) { + defer server.SetupViper(t)() + logger := log.NewNopLogger() + cfg, err := tcmd.ParseConfig() + require.Nil(t, err) + ctx := server.NewContext(cfg, logger) + cdc := codec.New() + appInit := server.AppInit{ + AppGenTx: mock.AppGenTx, + AppGenState: mock.AppGenStateEmpty, + } + cmd := InitCmd(ctx, cdc, appInit) + err = cmd.RunE(nil, nil) + require.NoError(t, err) + + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + cmd = server.ExportCmd(ctx, cdc, nil) + err = cmd.RunE(nil, nil) + require.NoError(t, err) + + outC := make(chan string) + go func() { + var buf bytes.Buffer + io.Copy(&buf, r) + outC <- buf.String() + }() + + w.Close() + os.Stdout = old + out := <-outC + require.Contains(t, out, "WARNING: State is not initialized") + require.Contains(t, out, "genesis_time") + require.Contains(t, out, "chain_id") + require.Contains(t, out, "consensus_params") + require.Contains(t, out, "validators") + require.Contains(t, out, "app_hash") +} + +func TestStartStandAlone(t *testing.T) { + home, err := ioutil.TempDir("", "mock-sdk-cmd") + require.Nil(t, err) + defer func() { + os.RemoveAll(home) + }() + + logger := log.NewNopLogger() + cfg, err := tcmd.ParseConfig() + require.Nil(t, err) + ctx := server.NewContext(cfg, logger) + cdc := codec.New() + appInit := server.AppInit{ + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, + } + initCmd := InitCmd(ctx, cdc, appInit) + err = initCmd.RunE(nil, nil) + require.NoError(t, err) + + app, err := mock.NewApp(home, logger) + require.Nil(t, err) + svrAddr, _, err := server.FreeTCPAddr() + require.Nil(t, err) + svr, err := abciServer.NewServer(svrAddr, "socket", app) + require.Nil(t, err, "error creating listener") + svr.SetLogger(logger.With("module", "abci-server")) + svr.Start() + + timer := time.NewTimer(time.Duration(2) * time.Second) + select { + case <-timer.C: + svr.Stop() + } +} diff --git a/server/testnet.go b/cmd/gaia/init/testnet.go similarity index 95% rename from server/testnet.go rename to cmd/gaia/init/testnet.go index e76263160..48b714f2d 100644 --- a/server/testnet.go +++ b/cmd/gaia/init/testnet.go @@ -1,7 +1,8 @@ -package server +package init import ( "fmt" + "github.com/cosmos/cosmos-sdk/server" "net" "path/filepath" @@ -30,7 +31,7 @@ var ( const nodeDirPerm = 0755 // get cmd to initialize all files for tendermint testnet and application -func TestnetFilesCmd(ctx *Context, cdc *codec.Codec, appInit AppInit) *cobra.Command { +func TestnetFilesCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command { cmd := &cobra.Command{ Use: "testnet", Short: "Initialize files for a Gaiad testnet", @@ -65,7 +66,7 @@ Example: return cmd } -func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit AppInit) error { +func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppInit) error { outDir := viper.GetString(outputDir) numValidators := viper.GetInt(nValidators) @@ -133,7 +134,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit AppInit) er nodeDaemonHomeName := viper.GetString(nodeDaemonHome) nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName) gentxsDir := filepath.Join(outDir, "gentxs") - initConfig := InitConfig{ + initConfig := server.InitConfig{ chainID, true, gentxsDir, @@ -156,7 +157,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit AppInit) er func getIP(i int) (ip string, err error) { ip = viper.GetString(startingIPAddress) if len(ip) == 0 { - ip, err = externalIP() + ip, err = server.ExternalIP() if err != nil { return "", err } diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 420508e72..362193544 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -6,6 +6,7 @@ import ( "os" "github.com/cosmos/cosmos-sdk/baseapp" + gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init" "github.com/cosmos/cosmos-sdk/examples/basecoin/app" "github.com/cosmos/cosmos-sdk/server" @@ -28,9 +29,12 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, - server.ConstructAppCreator(newApp, "basecoin"), - server.ConstructAppExporter(exportAppStateAndTMValidators, "basecoin")) + appInit := server.DefaultAppInit + rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit)) + rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit)) + + server.AddCommands(ctx, cdc, rootCmd, appInit, + newApp, exportAppStateAndTMValidators) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.basecoind") diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index e22b0fc3e..7f8c7c54d 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -13,6 +13,7 @@ import ( "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" + gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/examples/democoin/app" "github.com/cosmos/cosmos-sdk/server" @@ -70,9 +71,11 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } + rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, CoolAppInit)) + rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, CoolAppInit)) + server.AddCommands(ctx, cdc, rootCmd, CoolAppInit, - server.ConstructAppCreator(newApp, "democoin"), - server.ConstructAppExporter(exportAppStateAndTMValidators, "democoin")) + newApp, exportAppStateAndTMValidators) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.democoind") diff --git a/server/constructors.go b/server/constructors.go index 84be219bb..57282e43b 100644 --- a/server/constructors.go +++ b/server/constructors.go @@ -13,72 +13,29 @@ import ( ) type ( - // AppCreator reflects a function that allows us to lazily initialize an + // AppCreator is a function that allows us to lazily initialize an // application using various configurations. - AppCreator func(home string, logger log.Logger, traceStore string) (abci.Application, error) + AppCreator func(log.Logger, dbm.DB, io.Writer) abci.Application - // AppExporter reflects a function that dumps all app state to + // AppExporter is a function that dumps all app state to // JSON-serializable structure and returns the current validator set. - AppExporter func(home string, logger log.Logger, traceStore string) (json.RawMessage, []tmtypes.GenesisValidator, error) - - // AppCreatorInit reflects a function that performs initialization of an - // AppCreator. - AppCreatorInit func(log.Logger, dbm.DB, io.Writer) abci.Application - - // AppExporterInit reflects a function that performs initialization of an - // AppExporter. - AppExporterInit func(log.Logger, dbm.DB, io.Writer) (json.RawMessage, []tmtypes.GenesisValidator, error) + AppExporter func(log.Logger, dbm.DB, io.Writer) (json.RawMessage, []tmtypes.GenesisValidator, error) ) -// ConstructAppCreator returns an application generation function. -func ConstructAppCreator(appFn AppCreatorInit, name string) AppCreator { - return func(rootDir string, logger log.Logger, traceStore string) (abci.Application, error) { - dataDir := filepath.Join(rootDir, "data") - - db, err := dbm.NewGoLevelDB(name, dataDir) - if err != nil { - return nil, err - } - - var traceStoreWriter io.Writer - if traceStore != "" { - traceStoreWriter, err = os.OpenFile( - traceStore, - os.O_WRONLY|os.O_APPEND|os.O_CREATE, - 0666, - ) - if err != nil { - return nil, err - } - } - - app := appFn(logger, db, traceStoreWriter) - return app, nil - } +func openDB(rootDir string) (dbm.DB, error) { + dataDir := filepath.Join(rootDir, "data") + db, err := dbm.NewGoLevelDB("application", dataDir) + return db, err } -// ConstructAppExporter returns an application export function. -func ConstructAppExporter(appFn AppExporterInit, name string) AppExporter { - return func(rootDir string, logger log.Logger, traceStore string) (json.RawMessage, []tmtypes.GenesisValidator, error) { - dataDir := filepath.Join(rootDir, "data") - - db, err := dbm.NewGoLevelDB(name, dataDir) - if err != nil { - return nil, nil, err - } - - var traceStoreWriter io.Writer - if traceStore != "" { - traceStoreWriter, err = os.OpenFile( - traceStore, - os.O_WRONLY|os.O_APPEND|os.O_CREATE, - 0666, - ) - if err != nil { - return nil, nil, err - } - } - - return appFn(logger, db, traceStoreWriter) +func openTraceWriter(traceWriterFile string) (w io.Writer, err error) { + if traceWriterFile != "" { + w, err = os.OpenFile( + traceWriterFile, + os.O_WRONLY|os.O_APPEND|os.O_CREATE, + 0666, + ) + return } + return } diff --git a/server/export.go b/server/export.go index c3d6b5283..43ea10866 100644 --- a/server/export.go +++ b/server/export.go @@ -20,7 +20,7 @@ func ExportCmd(ctx *Context, cdc *codec.Codec, appExporter AppExporter) *cobra.C Short: "Export state to JSON", RunE: func(cmd *cobra.Command, args []string) error { home := viper.GetString("home") - traceStore := viper.GetString(flagTraceStore) + traceWriterFile := viper.GetString(flagTraceStore) emptyState, err := isEmptyState(home) if err != nil { return err @@ -37,7 +37,15 @@ func ExportCmd(ctx *Context, cdc *codec.Codec, appExporter AppExporter) *cobra.C return nil } - appState, validators, err := appExporter(home, ctx.Logger, traceStore) + db, err := openDB(home) + if err != nil { + return err + } + traceWriter, err := openTraceWriter(traceWriterFile) + if err != nil { + return err + } + appState, validators, err := appExporter(ctx.Logger, db, traceWriter) if err != nil { return errors.Errorf("error exporting state: %v\n", err) } diff --git a/server/export_test.go b/server/export_test.go deleted file mode 100644 index 999ba3c00..000000000 --- a/server/export_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package server - -import ( - "bytes" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/server/mock" - "github.com/stretchr/testify/require" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - "github.com/tendermint/tendermint/libs/log" - "io" - "os" - "testing" -) - -func TestEmptyState(t *testing.T) { - defer setupViper(t)() - logger := log.NewNopLogger() - cfg, err := tcmd.ParseConfig() - require.Nil(t, err) - ctx := NewContext(cfg, logger) - cdc := codec.New() - appInit := AppInit{ - AppGenTx: mock.AppGenTx, - AppGenState: mock.AppGenStateEmpty, - } - cmd := InitCmd(ctx, cdc, appInit) - err = cmd.RunE(nil, nil) - require.NoError(t, err) - - old := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w - cmd = ExportCmd(ctx, cdc, nil) - err = cmd.RunE(nil, nil) - require.NoError(t, err) - - outC := make(chan string) - go func() { - var buf bytes.Buffer - io.Copy(&buf, r) - outC <- buf.String() - }() - - w.Close() - os.Stdout = old - out := <-outC - require.Contains(t, out, "WARNING: State is not initialized") - require.Contains(t, out, "genesis_time") - require.Contains(t, out, "chain_id") - require.Contains(t, out, "consensus_params") - require.Contains(t, out, "validators") - require.Contains(t, out, "app_hash") -} diff --git a/server/init.go b/server/init.go index adec4fba3..091ffa948 100644 --- a/server/init.go +++ b/server/init.go @@ -3,26 +3,12 @@ package server import ( "encoding/json" "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "sort" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/pkg/errors" + "github.com/spf13/pflag" "github.com/tendermint/tendermint/crypto" - cfg "github.com/tendermint/tendermint/config" - tmcli "github.com/tendermint/tendermint/libs/cli" - cmn "github.com/tendermint/tendermint/libs/common" dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/p2p" - pvm "github.com/tendermint/tendermint/privval" tmtypes "github.com/tendermint/tendermint/types" clkeys "github.com/cosmos/cosmos-sdk/client/keys" @@ -62,303 +48,8 @@ type InitConfig struct { Overwrite bool } -// get cmd to initialize all files for tendermint and application -func GenTxCmd(ctx *Context, cdc *codec.Codec, appInit AppInit) *cobra.Command { - cmd := &cobra.Command{ - Use: "gen-tx", - Short: "Create genesis transaction file (under [--home]/config/gentx/gentx-[nodeID].json)", - Args: cobra.NoArgs, - RunE: func(_ *cobra.Command, args []string) error { - - config := ctx.Config - config.SetRoot(viper.GetString(tmcli.HomeFlag)) - - ip := viper.GetString(FlagIP) - if len(ip) == 0 { - eip, err := externalIP() - if err != nil { - return err - } - ip = eip - } - - genTxConfig := serverconfig.GenTx{ - viper.GetString(FlagName), - viper.GetString(FlagClientHome), - viper.GetBool(FlagOWK), - ip, - } - cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig) - if err != nil { - return err - } - toPrint := struct { - AppMessage json.RawMessage `json:"app_message"` - GenTxFile json.RawMessage `json:"gen_tx_file"` - }{ - cliPrint, - genTxFile, - } - out, err := codec.MarshalJSONIndent(cdc, toPrint) - if err != nil { - return err - } - fmt.Println(string(out)) - return nil - }, - } - cmd.Flags().String(FlagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine") - cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) - return cmd -} - -func gentxWithConfig(cdc *codec.Codec, appInit AppInit, config *cfg.Config, genTxConfig serverconfig.GenTx) ( - cliPrint json.RawMessage, genTxFile json.RawMessage, err error) { - nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) - if err != nil { - return - } - nodeID := string(nodeKey.ID()) - pubKey := readOrCreatePrivValidator(config) - - appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) - if err != nil { - return - } - - tx := GenesisTx{ - NodeID: nodeID, - IP: genTxConfig.IP, - Validator: validator, - AppGenTx: appGenTx, - } - bz, err := codec.MarshalJSONIndent(cdc, tx) - if err != nil { - return - } - genTxFile = json.RawMessage(bz) - name := fmt.Sprintf("gentx-%v.json", nodeID) - writePath := filepath.Join(config.RootDir, "config", "gentx") - file := filepath.Join(writePath, name) - err = cmn.EnsureDir(writePath, 0700) - if err != nil { - return - } - err = cmn.WriteFile(file, bz, 0644) - if err != nil { - return - } - - // Write updated config with moniker - config.Moniker = genTxConfig.Name - configFilePath := filepath.Join(config.RootDir, "config", "config.toml") - cfg.WriteConfigFile(configFilePath, config) - - return -} - -// get cmd to initialize all files for tendermint and application -func InitCmd(ctx *Context, cdc *codec.Codec, appInit AppInit) *cobra.Command { - cmd := &cobra.Command{ - Use: "init", - Short: "Initialize genesis config, priv-validator file, and p2p-node file", - Args: cobra.NoArgs, - RunE: func(_ *cobra.Command, _ []string) error { - - config := ctx.Config - config.SetRoot(viper.GetString(tmcli.HomeFlag)) - initConfig := InitConfig{ - viper.GetString(FlagChainID), - viper.GetBool(FlagWithTxs), - filepath.Join(config.RootDir, "config", "gentx"), - viper.GetBool(FlagOverwrite), - } - - chainID, nodeID, appMessage, err := initWithConfig(cdc, appInit, config, initConfig) - if err != nil { - return err - } - // print out some key information - toPrint := struct { - ChainID string `json:"chain_id"` - NodeID string `json:"node_id"` - AppMessage json.RawMessage `json:"app_message"` - }{ - chainID, - nodeID, - appMessage, - } - out, err := codec.MarshalJSONIndent(cdc, toPrint) - if err != nil { - return err - } - fmt.Println(string(out)) - return nil - }, - } - cmd.Flags().BoolP(FlagOverwrite, "o", false, "overwrite the genesis.json file") - cmd.Flags().String(FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") - cmd.Flags().Bool(FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/") - cmd.Flags().AddFlagSet(appInit.FlagsAppGenState) - cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided - cmd.AddCommand(GenTxCmd(ctx, cdc, appInit)) - return cmd -} - -func initWithConfig(cdc *codec.Codec, appInit AppInit, config *cfg.Config, initConfig InitConfig) ( - chainID string, nodeID string, appMessage json.RawMessage, err error) { - nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) - if err != nil { - return - } - nodeID = string(nodeKey.ID()) - pubKey := readOrCreatePrivValidator(config) - - if initConfig.ChainID == "" { - initConfig.ChainID = fmt.Sprintf("test-chain-%v", cmn.RandStr(6)) - } - chainID = initConfig.ChainID - - genFile := config.GenesisFile() - if !initConfig.Overwrite && cmn.FileExists(genFile) { - err = fmt.Errorf("genesis.json file already exists: %v", genFile) - return - } - - // process genesis transactions, or otherwise create one for defaults - var appGenTxs []json.RawMessage - var validators []tmtypes.GenesisValidator - var persistentPeers string - - if initConfig.GenTxs { - validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc) - if err != nil { - return - } - config.P2P.PersistentPeers = persistentPeers - configFilePath := filepath.Join(config.RootDir, "config", "config.toml") - cfg.WriteConfigFile(configFilePath, config) - } else { - genTxConfig := serverconfig.GenTx{ - viper.GetString(FlagName), - viper.GetString(FlagClientHome), - viper.GetBool(FlagOWK), - "127.0.0.1", - } - - // Write updated config with moniker - config.Moniker = genTxConfig.Name - configFilePath := filepath.Join(config.RootDir, "config", "config.toml") - cfg.WriteConfigFile(configFilePath, config) - appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) - appMessage = am - if err != nil { - return "", "", nil, err - } - validators = []tmtypes.GenesisValidator{validator} - appGenTxs = []json.RawMessage{appGenTx} - } - - appState, err := appInit.AppGenState(cdc, appGenTxs) - if err != nil { - return - } - - err = writeGenesisFile(cdc, genFile, initConfig.ChainID, validators, appState) - if err != nil { - return - } - - return -} - -// append a genesis-piece -func processGenTxs(genTxsDir string, cdc *codec.Codec) ( - validators []tmtypes.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) { - - var fos []os.FileInfo - fos, err = ioutil.ReadDir(genTxsDir) - if err != nil { - return - } - - genTxs := make(map[string]GenesisTx) - var nodeIDs []string - for _, fo := range fos { - filename := path.Join(genTxsDir, fo.Name()) - if !fo.IsDir() && (path.Ext(filename) != ".json") { - continue - } - - // get the genTx - var bz []byte - bz, err = ioutil.ReadFile(filename) - if err != nil { - return - } - var genTx GenesisTx - err = cdc.UnmarshalJSON(bz, &genTx) - if err != nil { - return - } - - genTxs[genTx.NodeID] = genTx - nodeIDs = append(nodeIDs, genTx.NodeID) - } - - sort.Strings(nodeIDs) - - for _, nodeID := range nodeIDs { - genTx := genTxs[nodeID] - - // combine some stuff - validators = append(validators, genTx.Validator) - appGenTxs = append(appGenTxs, genTx.AppGenTx) - - // Add a persistent peer - comma := "," - if len(persistentPeers) == 0 { - comma = "" - } - persistentPeers += fmt.Sprintf("%s%s@%s:26656", comma, genTx.NodeID, genTx.IP) - } - - return -} - //________________________________________________________________________________________ -// read of create the private key file for this config -func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { - // private validator - privValFile := tmConfig.PrivValidatorFile() - var privValidator *pvm.FilePV - if cmn.FileExists(privValFile) { - privValidator = pvm.LoadFilePV(privValFile) - } else { - privValidator = pvm.GenFilePV(privValFile) - privValidator.Save() - } - return privValidator.GetPubKey() -} - -// writeGenesisFile creates and writes the genesis configuration to disk. An -// error is returned if building or writing the configuration to file fails. -// nolint: unparam -func writeGenesisFile(cdc *codec.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { - genDoc := tmtypes.GenesisDoc{ - ChainID: chainID, - Validators: validators, - AppState: appState, - } - - if err := genDoc.ValidateAndComplete(); err != nil { - return err - } - - return genDoc.SaveAs(genesisFile) -} - //_____________________________________________________________________ // Core functionality passed from the application to the server init command diff --git a/server/init_test.go b/server/init_test.go deleted file mode 100644 index 1913ac671..000000000 --- a/server/init_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package server - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/tendermint/tendermint/libs/log" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/server/mock" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" -) - -// TODO update -func TestInitCmd(t *testing.T) { - defer setupViper(t)() - - logger := log.NewNopLogger() - cfg, err := tcmd.ParseConfig() - require.Nil(t, err) - ctx := NewContext(cfg, logger) - cdc := codec.New() - appInit := AppInit{ - AppGenState: mock.AppGenState, - AppGenTx: mock.AppGenTx, - } - cmd := InitCmd(ctx, cdc, appInit) - err = cmd.RunE(nil, nil) - require.NoError(t, err) -} - -func TestGenTxCmd(t *testing.T) { - // TODO -} - -func TestTestnetFilesCmd(t *testing.T) { - // TODO -} - -func TestSimpleAppGenTx(t *testing.T) { - // TODO -} - -func TestSimpleAppGenState(t *testing.T) { - // TODO -} diff --git a/server/start.go b/server/start.go index 170ff9dcb..82fbbbbeb 100644 --- a/server/start.go +++ b/server/start.go @@ -57,12 +57,18 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { func startStandAlone(ctx *Context, appCreator AppCreator) error { addr := viper.GetString(flagAddress) home := viper.GetString("home") - traceStore := viper.GetString(flagTraceStore) + traceWriterFile := viper.GetString(flagTraceStore) - app, err := appCreator(home, ctx.Logger, traceStore) + db, err := openDB(home) if err != nil { return err } + traceWriter, err := openTraceWriter(traceWriterFile) + if err != nil { + return err + } + + app := appCreator(ctx.Logger, db, traceWriter) svr, err := server.NewServer(addr, "socket", app) if err != nil { @@ -91,12 +97,18 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error { func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) { cfg := ctx.Config home := cfg.RootDir - traceStore := viper.GetString(flagTraceStore) + traceWriterFile := viper.GetString(flagTraceStore) - app, err := appCreator(home, ctx.Logger, traceStore) + db, err := openDB(home) if err != nil { return nil, err } + traceWriter, err := openTraceWriter(traceWriterFile) + if err != nil { + return nil, err + } + + app := appCreator(ctx.Logger, db, traceWriter) nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile()) if err != nil { diff --git a/server/start_test.go b/server/start_test.go deleted file mode 100644 index db9fcd40f..000000000 --- a/server/start_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package server - -import ( - "io/ioutil" - "os" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/server/mock" - "github.com/tendermint/tendermint/abci/server" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - "github.com/tendermint/tendermint/libs/log" -) - -func TestStartStandAlone(t *testing.T) { - home, err := ioutil.TempDir("", "mock-sdk-cmd") - require.Nil(t, err) - defer func() { - os.RemoveAll(home) - }() - - logger := log.NewNopLogger() - cfg, err := tcmd.ParseConfig() - require.Nil(t, err) - ctx := NewContext(cfg, logger) - cdc := codec.New() - appInit := AppInit{ - AppGenState: mock.AppGenState, - AppGenTx: mock.AppGenTx, - } - initCmd := InitCmd(ctx, cdc, appInit) - err = initCmd.RunE(nil, nil) - require.NoError(t, err) - - app, err := mock.NewApp(home, logger) - require.Nil(t, err) - svrAddr, _, err := FreeTCPAddr() - require.Nil(t, err) - svr, err := server.NewServer(svrAddr, "socket", app) - require.Nil(t, err, "error creating listener") - svr.SetLogger(logger.With("module", "abci-server")) - svr.Start() - - timer := time.NewTimer(time.Duration(2) * time.Second) - select { - case <-timer.C: - svr.Stop() - } -} diff --git a/server/test_helpers.go b/server/test_helpers.go index d1230898d..8de164e08 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -36,9 +36,9 @@ func FreeTCPAddr() (addr, port string, err error) { return } -// setupViper creates a homedir to run inside, +// SetupViper creates a homedir to run inside, // and returns a cleanup function to defer -func setupViper(t *testing.T) func() { +func SetupViper(t *testing.T) func() { rootDir, err := ioutil.TempDir("", "mock-sdk-cmd") require.Nil(t, err) viper.Set(cli.HomeFlag, rootDir) diff --git a/server/util.go b/server/util.go index 9508e0489..5199c1207 100644 --- a/server/util.go +++ b/server/util.go @@ -42,7 +42,7 @@ func NewContext(config *cfg.Config, logger log.Logger) *Context { // PersistentPreRunEFn returns a PersistentPreRunE function for cobra // that initailizes the passed in context with a properly configured -// logger and config objecy +// logger and config object. func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { if cmd.Name() == version.VersionCmd.Name() { @@ -85,7 +85,7 @@ func interceptLoadConfig() (conf *cfg.Config, err error) { if _, err := os.Stat(configFilePath); os.IsNotExist(err) { // the following parse config is needed to create directories - conf, _ = tcmd.ParseConfig() + conf, _ = tcmd.ParseConfig() // NOTE: ParseConfig() creates dir/files as necessary. conf.ProfListenAddress = "localhost:6060" conf.P2P.RecvRate = 5120000 conf.P2P.SendRate = 5120000 @@ -96,7 +96,7 @@ func interceptLoadConfig() (conf *cfg.Config, err error) { } if conf == nil { - conf, err = tcmd.ParseConfig() + conf, err = tcmd.ParseConfig() // NOTE: ParseConfig() creates dir/files as necessary. } cosmosConfigFilePath := filepath.Join(rootDir, "config/gaiad.toml") @@ -143,8 +143,6 @@ func AddCommands( ) rootCmd.AddCommand( - InitCmd(ctx, cdc, appInit), - TestnetFilesCmd(ctx, cdc, appInit), StartCmd(ctx, appCreator), UnsafeResetAllCmd(ctx), client.LineBreak, @@ -177,7 +175,7 @@ func InsertKeyJSON(cdc *codec.Codec, baseJSON []byte, key string, value json.Raw // https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go // TODO there must be a better way to get external IP -func externalIP() (string, error) { +func ExternalIP() (string, error) { ifaces, err := net.Interfaces() if err != nil { return "", err diff --git a/x/bank/client/cli/sendtx.go b/x/bank/client/cli/sendtx.go index 573e4d99b..8200563b0 100644 --- a/x/bank/client/cli/sendtx.go +++ b/x/bank/client/cli/sendtx.go @@ -66,7 +66,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command { // build and sign the transaction, then broadcast to Tendermint msg := client.CreateMsg(from, to, coins) if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index a7b0b4c5b..23e95105e 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -103,7 +103,7 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome } if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } // Build and sign the transaction, then broadcast to Tendermint @@ -183,7 +183,7 @@ func GetCmdDeposit(cdc *codec.Codec) *cobra.Command { } if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } // Build and sign the transaction, then broadcast to a Tendermint @@ -229,7 +229,7 @@ func GetCmdVote(cdc *codec.Codec) *cobra.Command { } if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]", diff --git a/x/ibc/client/cli/ibctx.go b/x/ibc/client/cli/ibctx.go index 3b024d9f9..be6dfc940 100644 --- a/x/ibc/client/cli/ibctx.go +++ b/x/ibc/client/cli/ibctx.go @@ -42,7 +42,7 @@ func IBCTransferCmd(cdc *codec.Codec) *cobra.Command { return err } if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) diff --git a/x/slashing/client/cli/tx.go b/x/slashing/client/cli/tx.go index a3508f880..f70be1871 100644 --- a/x/slashing/client/cli/tx.go +++ b/x/slashing/client/cli/tx.go @@ -31,7 +31,7 @@ func GetCmdUnjail(cdc *codec.Codec) *cobra.Command { msg := slashing.NewMsgUnjail(sdk.ValAddress(valAddr)) if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) }, diff --git a/x/stake/client/cli/tx.go b/x/stake/client/cli/tx.go index 4272f4e9f..9640c5c05 100644 --- a/x/stake/client/cli/tx.go +++ b/x/stake/client/cli/tx.go @@ -88,7 +88,7 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command { } if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, true) } // build and sign the transaction, then broadcast to Tendermint @@ -143,7 +143,7 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command { msg := stake.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate) if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } // build and sign the transaction, then broadcast to Tendermint @@ -186,7 +186,7 @@ func GetCmdDelegate(cdc *codec.Codec) *cobra.Command { msg := stake.NewMsgDelegate(delAddr, valAddr, amount) if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } // build and sign the transaction, then broadcast to Tendermint return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) @@ -256,7 +256,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *codec.Codec) *cobra.Command { msg := stake.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, sharesAmount) if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } // build and sign the transaction, then broadcast to Tendermint return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) @@ -319,7 +319,7 @@ func GetCmdBeginUnbonding(storeName string, cdc *codec.Codec) *cobra.Command { msg := stake.NewMsgBeginUnbonding(delAddr, valAddr, sharesAmount) if cliCtx.GenerateOnly { - return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false) } // build and sign the transaction, then broadcast to Tendermint return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg}) From 0ef1582aeb6114302c9401ef2beaaa0e4832d46f Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Thu, 11 Oct 2018 01:53:17 +0200 Subject: [PATCH 10/10] Disable unparam --- tools/gometalinter.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gometalinter.json b/tools/gometalinter.json index 74dc40330..1745cd9e0 100644 --- a/tools/gometalinter.json +++ b/tools/gometalinter.json @@ -2,7 +2,7 @@ "Linters": { "vet": "go tool vet -composites=false :PATH:LINE:MESSAGE" }, - "Enable": ["golint", "vet", "ineffassign", "unparam", "unconvert", "misspell"], + "Enable": ["golint", "vet", "ineffassign", "unconvert", "misspell"], "Deadline": "500s", "Vendor": true, "Cyclo": 11,