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 | 122 ++++++++++++++++++++++++++++++++------ store/prefixstore_test.go | 71 +++++++++++++++++++++- 2 files changed, 173 insertions(+), 20 deletions(-) diff --git a/store/prefixstore.go b/store/prefixstore.go index 835a210385c4..af9e59b64387 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 { + var newstart []byte + if start == nil { + newstart = cpIncr(s.prefix) + } else { + 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...) } + + 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 49bc68037a72..cf50b9dd4cb3 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 af9e59b64387..c060bf5c3633 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 c060bf5c3633..2b70a28ff80f 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 2b70a28ff80f..a29459e4e85c 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 cf50b9dd4cb3..499f30d50078 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 a29459e4e85c..04d268057d3e 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 04d268057d3e..981d821311dd 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 981d821311dd..55af1084e3de 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 e9448bca82c7..b42bb3592662 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 | 311 +---------------------- 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, 532 insertions(+), 562 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 c6713cae8cfe..dec322b7bafd 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 9e72c552d1e8..364b9e692fb6 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 0b5f0e505e67..adfb12d5735d 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 000000000000..a04c1d2ae77e --- /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 000000000000..3a7f0a358d47 --- /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 e76263160813..48b714f2de21 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 420508e723ee..36219354449b 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 e22b0fc3e043..7f8c7c54d17f 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 84be219bbbdd..57282e43b1df 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 c3d6b5283afb..43ea10866e92 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 999ba3c00581..000000000000 --- 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 adec4fba3975..091ffa9484e6 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/cosmos/cosmos-sdk/crypto/keys" "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/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 1913ac671722..000000000000 --- 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 170ff9dcb3e1..82fbbbbebadd 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 db9fcd40f840..000000000000 --- 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 d1230898ddfd..8de164e08ae4 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 9508e0489402..5199c12071e1 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 573e4d99b760..8200563b0e6e 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 a7b0b4c5b040..23e95105e0ed 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 3b024d9f952c..be6dfc940da7 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 a3508f88086a..f70be1871218 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 4272f4e9fa08..9640c5c05069 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 74dc40330856..1745cd9e0cdc 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,