diff --git a/Makefile b/Makefile index e15356c2c..ae2c71610 100644 --- a/Makefile +++ b/Makefile @@ -62,12 +62,16 @@ get_vendor_deps: @echo "--> Running glide install" @glide install + ######################################## ### Testing test: go test -tags gcc `glide novendor` +test100: + @for i in {1..100}; do make test; done + ######################################## ### Formatting, linting, and vetting diff --git a/cli/setup.go b/cli/setup.go index 295477598..2dcadb407 100644 --- a/cli/setup.go +++ b/cli/setup.go @@ -8,9 +8,6 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" - - data "github.com/tendermint/go-wire/data" - "github.com/tendermint/go-wire/data/base58" ) const ( @@ -42,7 +39,7 @@ func PrepareBaseCmd(cmd *cobra.Command, envPrefix, defaultHome string) Executor func PrepareMainCmd(cmd *cobra.Command, envPrefix, defaultHome string) Executor { cmd.PersistentFlags().StringP(EncodingFlag, "e", "hex", "Binary encoding (hex|b64|btc)") cmd.PersistentFlags().StringP(OutputFlag, "o", "text", "Output format (text|json)") - cmd.PersistentPreRunE = concatCobraCmdFuncs(setEncoding, validateOutput, cmd.PersistentPreRunE) + cmd.PersistentPreRunE = concatCobraCmdFuncs(validateOutput, cmd.PersistentPreRunE) return PrepareBaseCmd(cmd, envPrefix, defaultHome) } @@ -147,23 +144,6 @@ func bindFlagsLoadViper(cmd *cobra.Command, args []string) error { return nil } -// setEncoding reads the encoding flag -func setEncoding(cmd *cobra.Command, args []string) error { - // validate and set encoding - enc := viper.GetString("encoding") - switch enc { - case "hex": - data.Encoder = data.HexEncoder - case "b64": - data.Encoder = data.B64Encoder - case "btc": - data.Encoder = base58.BTCEncoder - default: - return errors.Errorf("Unsupported encoding: %s", enc) - } - return nil -} - func validateOutput(cmd *cobra.Command, args []string) error { // validate output format output := viper.GetString(OutputFlag) diff --git a/common/repeat_timer.go b/common/repeat_timer.go index 2e6cb81c8..cb227199e 100644 --- a/common/repeat_timer.go +++ b/common/repeat_timer.go @@ -80,13 +80,11 @@ func (t *logicalTicker) fireRoutine(interval time.Duration) { } // Init `lasttime` end - timeleft := interval for { select { case newtime := <-source: elapsed := newtime.Sub(lasttime) - timeleft -= elapsed - if timeleft <= 0 { + if interval <= elapsed { // Block for determinism until the ticker is stopped. select { case t.ch <- newtime: @@ -97,7 +95,7 @@ func (t *logicalTicker) fireRoutine(interval time.Duration) { // Don't try to "catch up" by sending more. // "Ticker adjusts the intervals or drops ticks to make up for // slow receivers" - https://golang.org/pkg/time/#Ticker - timeleft = interval + lasttime = newtime } case <-t.quit: return // done diff --git a/common/repeat_timer_test.go b/common/repeat_timer_test.go index 5a3a4c0a6..5598922c5 100644 --- a/common/repeat_timer_test.go +++ b/common/repeat_timer_test.go @@ -1,6 +1,7 @@ package common import ( + "sync" "testing" "time" @@ -13,29 +14,42 @@ func TestDefaultTicker(t *testing.T) { ticker.Stop() } -func TestRepeat(t *testing.T) { +func TestRepeatTimer(t *testing.T) { ch := make(chan time.Time, 100) - lt := time.Time{} // zero time is year 1 + mtx := new(sync.Mutex) - // tick fires `cnt` times for each second. - tick := func(cnt int) { - for i := 0; i < cnt; i++ { - lt = lt.Add(time.Second) - ch <- lt - } + // tick() fires from start to end + // (exclusive) in milliseconds with incr. + // It locks on mtx, so subsequent calls + // run in series. + tick := func(startMs, endMs, incrMs time.Duration) { + mtx.Lock() + go func() { + for tMs := startMs; tMs < endMs; tMs += incrMs { + lt := time.Time{} + lt = lt.Add(tMs * time.Millisecond) + ch <- lt + } + mtx.Unlock() + }() } - // tock consumes Ticker.Chan() events `cnt` times. - tock := func(t *testing.T, rt *RepeatTimer, cnt int) { - for i := 0; i < cnt; i++ { - timeout := time.After(time.Second * 10) - select { - case <-rt.Chan(): - case <-timeout: - panic("expected RepeatTimer to fire") - } + // tock consumes Ticker.Chan() events and checks them against the ms in "timesMs". + tock := func(t *testing.T, rt *RepeatTimer, timesMs []int64) { + + // Check against timesMs. + for _, timeMs := range timesMs { + tyme := <-rt.Chan() + sinceMs := tyme.Sub(time.Time{}) / time.Millisecond + assert.Equal(t, timeMs, int64(sinceMs)) } + + // TODO detect number of running + // goroutines to ensure that + // no other times will fire. + // See https://github.com/tendermint/tmlibs/issues/120. + time.Sleep(time.Millisecond * 100) done := true select { case <-rt.Chan(): @@ -46,46 +60,44 @@ func TestRepeat(t *testing.T) { } tm := NewLogicalTickerMaker(ch) - dur := time.Duration(10 * time.Millisecond) // less than a second - rt := NewRepeatTimerWithTickerMaker("bar", dur, tm) - - // Start at 0. - tock(t, rt, 0) - tick(1) // init time + rt := NewRepeatTimerWithTickerMaker("bar", time.Second, tm) - tock(t, rt, 0) - tick(1) // wait 1 periods - tock(t, rt, 1) - tick(2) // wait 2 periods - tock(t, rt, 2) - tick(3) // wait 3 periods - tock(t, rt, 3) - tick(4) // wait 4 periods - tock(t, rt, 4) - - // Multiple resets leads to no firing. - for i := 0; i < 20; i++ { - time.Sleep(time.Millisecond) - rt.Reset() - } + /* NOTE: Useful for debugging deadlocks... + go func() { + time.Sleep(time.Second * 3) + trace := make([]byte, 102400) + count := runtime.Stack(trace, true) + fmt.Printf("Stack of %d bytes: %s\n", count, trace) + }() + */ - // After this, it works as new. - tock(t, rt, 0) - tick(1) // init time + tick(0, 1000, 10) + tock(t, rt, []int64{}) + tick(1000, 2000, 10) + tock(t, rt, []int64{1000}) + tick(2005, 5000, 10) + tock(t, rt, []int64{2005, 3005, 4005}) + tick(5001, 5999, 1) + // Read 5005 instead of 5001 because + // it's 1 second greater than 4005. + tock(t, rt, []int64{5005}) + tick(6000, 7005, 1) + tock(t, rt, []int64{6005}) + tick(7033, 8032, 1) + tock(t, rt, []int64{7033}) - tock(t, rt, 0) - tick(1) // wait 1 periods - tock(t, rt, 1) - tick(2) // wait 2 periods - tock(t, rt, 2) - tick(3) // wait 3 periods - tock(t, rt, 3) - tick(4) // wait 4 periods - tock(t, rt, 4) + // After a reset, nothing happens + // until two ticks are received. + rt.Reset() + tock(t, rt, []int64{}) + tick(8040, 8041, 1) + tock(t, rt, []int64{}) + tick(9555, 9556, 1) + tock(t, rt, []int64{9555}) // After a stop, nothing more is sent. rt.Stop() - tock(t, rt, 0) + tock(t, rt, []int64{}) // Another stop panics. assert.Panics(t, func() { rt.Stop() }) diff --git a/db/backend_test.go b/db/backend_test.go index 0f4346f2e..80fbbb140 100644 --- a/db/backend_test.go +++ b/db/backend_test.go @@ -15,7 +15,7 @@ func cleanupDBDir(dir, name string) { os.RemoveAll(filepath.Join(dir, name) + ".db") } -func testBackendGetSetDelete(t *testing.T, backend string) { +func testBackendGetSetDelete(t *testing.T, backend DBBackendType) { // Default dir, dirname := cmn.Tempdir(fmt.Sprintf("test_backend_%s_", backend)) defer dir.Close() @@ -141,9 +141,9 @@ func TestBackendsNilKeys(t *testing.T) { } } -func TestGoLevelDBBackendStr(t *testing.T) { +func TestGoLevelDBBackend(t *testing.T) { name := cmn.Fmt("test_%x", cmn.RandStr(12)) - db := NewDB(name, GoLevelDBBackendStr, "") + db := NewDB(name, GoLevelDBBackend, "") defer cleanupDBDir("", name) _, ok := db.(*GoLevelDB) diff --git a/db/c_level_db.go b/db/c_level_db.go index f1a5a3aef..a59137883 100644 --- a/db/c_level_db.go +++ b/db/c_level_db.go @@ -14,8 +14,8 @@ func init() { dbCreator := func(name string, dir string) (DB, error) { return NewCLevelDB(name, dir) } - registerDBCreator(LevelDBBackendStr, dbCreator, true) - registerDBCreator(CLevelDBBackendStr, dbCreator, false) + registerDBCreator(LevelDBBackend, dbCreator, true) + registerDBCreator(CLevelDBBackend, dbCreator, false) } var _ DB = (*CLevelDB)(nil) diff --git a/db/c_level_db_test.go b/db/c_level_db_test.go index 89993fbac..34bb72273 100644 --- a/db/c_level_db_test.go +++ b/db/c_level_db_test.go @@ -86,9 +86,9 @@ func bytes2Int64(buf []byte) int64 { } */ -func TestCLevelDBBackendStr(t *testing.T) { +func TestCLevelDBBackend(t *testing.T) { name := cmn.Fmt("test_%x", cmn.RandStr(12)) - db := NewDB(name, LevelDBBackendStr, "") + db := NewDB(name, LevelDBBackend, "") defer cleanupDBDir("", name) _, ok := db.(*CLevelDB) diff --git a/db/common_test.go b/db/common_test.go index 2a5d01818..1b0f00416 100644 --- a/db/common_test.go +++ b/db/common_test.go @@ -45,7 +45,7 @@ func checkValuePanics(t *testing.T, itr Iterator) { assert.Panics(t, func() { itr.Key() }, "checkValuePanics expected panic but didn't") } -func newTempDB(t *testing.T, backend string) (db DB) { +func newTempDB(t *testing.T, backend DBBackendType) (db DB) { dir, dirname := cmn.Tempdir("test_go_iterator") db = NewDB("testdb", backend, dirname) dir.Close() diff --git a/db/db.go b/db/db.go index 25ff93ec5..869937660 100644 --- a/db/db.go +++ b/db/db.go @@ -5,19 +5,21 @@ import "fmt" //---------------------------------------- // Main entry +type DBBackendType string + const ( - LevelDBBackendStr = "leveldb" // legacy, defaults to goleveldb unless +gcc - CLevelDBBackendStr = "cleveldb" - GoLevelDBBackendStr = "goleveldb" - MemDBBackendStr = "memdb" - FSDBBackendStr = "fsdb" // using the filesystem naively + LevelDBBackend DBBackendType = "leveldb" // legacy, defaults to goleveldb unless +gcc + CLevelDBBackend DBBackendType = "cleveldb" + GoLevelDBBackend DBBackendType = "goleveldb" + MemDBBackend DBBackendType = "memdb" + FSDBBackend DBBackendType = "fsdb" // using the filesystem naively ) type dbCreator func(name string, dir string) (DB, error) -var backends = map[string]dbCreator{} +var backends = map[DBBackendType]dbCreator{} -func registerDBCreator(backend string, creator dbCreator, force bool) { +func registerDBCreator(backend DBBackendType, creator dbCreator, force bool) { _, ok := backends[backend] if !force && ok { return @@ -25,7 +27,7 @@ func registerDBCreator(backend string, creator dbCreator, force bool) { backends[backend] = creator } -func NewDB(name string, backend string, dir string) DB { +func NewDB(name string, backend DBBackendType, dir string) DB { db, err := backends[backend](name, dir) if err != nil { panic(fmt.Sprintf("Error initializing DB: %v", err)) diff --git a/db/fsdb.go b/db/fsdb.go index 45c3231f6..578c1785a 100644 --- a/db/fsdb.go +++ b/db/fsdb.go @@ -19,7 +19,7 @@ const ( ) func init() { - registerDBCreator(FSDBBackendStr, func(name string, dir string) (DB, error) { + registerDBCreator(FSDBBackend, func(name string, dir string) (DB, error) { dbPath := filepath.Join(dir, name+".db") return NewFSDB(dbPath), nil }, false) diff --git a/db/go_level_db.go b/db/go_level_db.go index 7d60e060f..9fed329bf 100644 --- a/db/go_level_db.go +++ b/db/go_level_db.go @@ -17,8 +17,8 @@ func init() { dbCreator := func(name string, dir string) (DB, error) { return NewGoLevelDB(name, dir) } - registerDBCreator(LevelDBBackendStr, dbCreator, false) - registerDBCreator(GoLevelDBBackendStr, dbCreator, false) + registerDBCreator(LevelDBBackend, dbCreator, false) + registerDBCreator(GoLevelDBBackend, dbCreator, false) } var _ DB = (*GoLevelDB)(nil) diff --git a/db/mem_db.go b/db/mem_db.go index 1e3bee5a5..f2c484fa7 100644 --- a/db/mem_db.go +++ b/db/mem_db.go @@ -7,7 +7,7 @@ import ( ) func init() { - registerDBCreator(MemDBBackendStr, func(name string, dir string) (DB, error) { + registerDBCreator(MemDBBackend, func(name string, dir string) (DB, error) { return NewMemDB(), nil }, false) } diff --git a/glide.lock b/glide.lock index aaf7c07e2..875f9837b 100644 --- a/glide.lock +++ b/glide.lock @@ -1,10 +1,14 @@ -hash: 325b2f9c7e84696f88fa88126a22eb1e1e91c2be5f60402d17bfaad6713b33c2 -updated: 2017-12-28T18:27:21.247160207-08:00 +hash: 22e22759d9adc51e3ce0728955143321386891907ce54eb952245d57285d8784 +updated: 2018-02-02T18:08:31.85309+01:00 imports: +- name: github.com/davecgh/go-spew + version: 346938d642f2ec3594ed81d874461961cd0faa76 + subpackages: + - spew - name: github.com/fsnotify/fsnotify - version: 4da3e2cfbabc9f751898f250b49f2439785783a1 + version: c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9 - name: github.com/go-kit/kit - version: e2b298466b32c7cd5579a9b9b07e968fc9d9452c + version: 4dc7be5d2d12881735283bcab7352178e190fc71 subpackages: - log - log/level @@ -14,7 +18,7 @@ imports: - name: github.com/go-stack/stack version: 817915b46b97fd7bb80e8ab6b69f01a53ac3eebf - name: github.com/gogo/protobuf - version: 342cbe0a04158f6dcb03ca0079991a51a4248c02 + version: 1adfc126b41513cc696b209667c8656ea7aac67c subpackages: - gogoproto - proto @@ -39,21 +43,15 @@ imports: - name: github.com/kr/logfmt version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0 - name: github.com/magiconair/properties - version: 8d7837e64d3c1ee4e54a880c5a920ab4316fc90a -- name: github.com/mattn/go-colorable - version: 6fcc0c1fd9b620311d821b106a400b35dc95c497 -- name: github.com/mattn/go-isatty - version: a5cdd64afdee435007ee3e9f6ed4684af949d568 + version: 49d762b9817ba1c2e9d0c69183c2b4a8b8f1d934 - name: github.com/mitchellh/mapstructure - version: 06020f85339e21b2478f756a78e295255ffa4d6a -- name: github.com/pelletier/go-buffruneio - version: c37440a7cf42ac63b919c752ca73a85067e05992 + version: b4575eea38cca1123ec2dc90c26529b5c5acfcff - name: github.com/pelletier/go-toml - version: 13d49d4606eb801b8f01ae542b4afc4c6ee3d84a + version: acdc4509485b587f5e675510c4f2c63e90ff68a8 - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/spf13/afero - version: 5660eeed305fe5f69c8fc6cf899132a459a97064 + version: bb8f1927f2a9d3ab41c9340aa034f6b803f4359c subpackages: - mem - name: github.com/spf13/cast @@ -61,11 +59,11 @@ imports: - name: github.com/spf13/cobra version: 7b2c5ac9fc04fc5efafb60700713d4fa609b777b - name: github.com/spf13/jwalterweatherman - version: 12bd96e66386c1960ab0f74ced1362f66f552f7b + version: 7c0cea34c8ece3fbeb2b27ab9b59511d360fb394 - name: github.com/spf13/pflag version: 97afa5e7ca8a08a383cb259e06636b5e2cc7897f - name: github.com/spf13/viper - version: 8ef37cbca71638bf32f3d5e194117d4cb46da163 + version: 25b30aa063fc18e48662b86996252eabdcf2f0c7 - name: github.com/syndtr/goleveldb version: b89cc31ef7977104127d34c1bd31ebd1a9db2199 subpackages: @@ -82,20 +80,13 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/go-wire - version: 27be46e25124ddf775e23317a83647ce62a93f6b - subpackages: - - data - - data/base58 -- name: github.com/tendermint/log15 - version: f91285dece9f4875421b481da3e613d83d44f29b - subpackages: - - term + version: e723d95ac2838b7ae9919ada25004859236c32ff - name: golang.org/x/crypto version: edd5e9b0879d13ee6970a50153d85b8fec9f7686 subpackages: - ripemd160 - name: golang.org/x/sys - version: 8dbc5d05d6edcc104950cc299a1ce6641235bc86 + version: 37707fdb30a5b38865cfb95e5aab41707daec7fd subpackages: - unix - name: golang.org/x/text @@ -104,18 +95,14 @@ imports: - transform - unicode/norm - name: gopkg.in/yaml.v2 - version: eb3733d160e74a9c7e442f435eb3bea458e1d19f + version: d670f9405373e636a5a2765eea47fac0c9bc91a4 testImports: -- name: github.com/davecgh/go-spew - version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9 - subpackages: - - spew - name: github.com/pmezard/go-difflib version: d8ed2627bdf02c080bf22230dbb337003b7aba2d subpackages: - difflib - name: github.com/stretchr/testify - version: 2aa2c176b9dab406a6970f6a55f513e8a8c8b18f + version: 12b6f73e6084dad08a7c6e575284b177ecafbc71 subpackages: - assert - require diff --git a/glide.yaml b/glide.yaml index 2df880175..42d43e4be 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,30 +1,39 @@ package: github.com/tendermint/tmlibs import: - package: github.com/go-kit/kit + version: ^0.6.0 subpackages: - log - log/level - log/term - package: github.com/go-logfmt/logfmt + version: ^0.3.0 +- package: github.com/gogo/protobuf + version: ^1.0.0 + subpackages: + - gogoproto + - proto - package: github.com/jmhodges/levigo - package: github.com/pkg/errors + version: ^0.8.0 - package: github.com/spf13/cobra + version: ^0.0.1 - package: github.com/spf13/viper + version: ^1.0.0 - package: github.com/syndtr/goleveldb subpackages: - leveldb - leveldb/errors + - leveldb/iterator - leveldb/opt - package: github.com/tendermint/go-wire - subpackages: - - data - - data/base58 -- package: github.com/tendermint/log15 + version: develop - package: golang.org/x/crypto subpackages: - ripemd160 testImport: - package: github.com/stretchr/testify + version: ^1.2.1 subpackages: - assert - require diff --git a/merkle/simple_map.go b/merkle/simple_map.go index 003c7cd42..b09b71d54 100644 --- a/merkle/simple_map.go +++ b/merkle/simple_map.go @@ -18,25 +18,25 @@ func NewSimpleMap() *SimpleMap { } } -func (sm *SimpleMap) Set(key string, value interface{}) { +func (sm *SimpleMap) Set(key string, value Hasher) { sm.sorted = false - // Is value Hashable? - var vBytes []byte - if hashable, ok := value.(Hashable); ok { - vBytes = hashable.Hash() - } else { - vBytes = wire.BinaryBytes(value) - } + // Hash the key to blind it... why not? + khash := SimpleHashFromBytes([]byte(key)) + + // And the value is hashed too, so you can + // check for equality with a cached value (say) + // and make a determination to fetch or not. + vhash := value.Hash() sm.kvs = append(sm.kvs, cmn.KVPair{ - Key: []byte(key), - Value: vBytes, + Key: khash, + Value: vhash, }) } -// Merkle root hash of items sorted by key. -// NOTE: Behavior is undefined when key is duplicate. +// Merkle root hash of items sorted by key +// (UNSTABLE: and by value too if duplicate key). func (sm *SimpleMap) Hash() []byte { sm.Sort() return hashKVPairs(sm.kvs) @@ -51,7 +51,6 @@ func (sm *SimpleMap) Sort() { } // Returns a copy of sorted KVPairs. -// CONTRACT: The returned slice must not be mutated. func (sm *SimpleMap) KVPairs() cmn.KVPairs { sm.Sort() kvs := make(cmn.KVPairs, len(sm.kvs)) @@ -65,22 +64,22 @@ func (sm *SimpleMap) KVPairs() cmn.KVPairs { type kvPair cmn.KVPair func (kv kvPair) Hash() []byte { - hasher, n, err := ripemd160.New(), new(int), new(error) - wire.WriteByteSlice(kv.Key, hasher, n, err) - if *err != nil { - panic(*err) + hasher := ripemd160.New() + err := wire.EncodeByteSlice(hasher, kv.Key) + if err != nil { + panic(err) } - wire.WriteByteSlice(kv.Value, hasher, n, err) - if *err != nil { - panic(*err) + err = wire.EncodeByteSlice(hasher, kv.Value) + if err != nil { + panic(err) } return hasher.Sum(nil) } func hashKVPairs(kvs cmn.KVPairs) []byte { - kvsH := make([]Hashable, 0, len(kvs)) + kvsH := make([]Hasher, 0, len(kvs)) for _, kvp := range kvs { kvsH = append(kvsH, kvPair(kvp)) } - return SimpleHashFromHashables(kvsH) + return SimpleHashFromHashers(kvsH) } diff --git a/merkle/simple_map_test.go b/merkle/simple_map_test.go index 8ba7ce66b..61210132b 100644 --- a/merkle/simple_map_test.go +++ b/merkle/simple_map_test.go @@ -7,41 +7,47 @@ import ( "github.com/stretchr/testify/assert" ) +type strHasher string + +func (str strHasher) Hash() []byte { + return SimpleHashFromBytes([]byte(str)) +} + func TestSimpleMap(t *testing.T) { { db := NewSimpleMap() - db.Set("key1", "value1") - assert.Equal(t, "3bb53f017d2f5b4f144692aa829a5c245ac2b123", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") + db.Set("key1", strHasher("value1")) + assert.Equal(t, "19618304d1ad2635c4238bce87f72331b22a11a1", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") } { db := NewSimpleMap() - db.Set("key1", "value2") - assert.Equal(t, "14a68db29e3f930ffaafeff5e07c17a439384f39", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") + db.Set("key1", strHasher("value2")) + assert.Equal(t, "51cb96d3d41e1714def72eb4bacc211de9ddf284", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") } { db := NewSimpleMap() - db.Set("key1", "value1") - db.Set("key2", "value2") - assert.Equal(t, "275c6367f4be335f9c482b6ef72e49c84e3f8bda", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") + db.Set("key1", strHasher("value1")) + db.Set("key2", strHasher("value2")) + assert.Equal(t, "58a0a99d5019fdcad4bcf55942e833b2dfab9421", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") } { db := NewSimpleMap() - db.Set("key2", "value2") // NOTE: out of order - db.Set("key1", "value1") - assert.Equal(t, "275c6367f4be335f9c482b6ef72e49c84e3f8bda", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") + db.Set("key2", strHasher("value2")) // NOTE: out of order + db.Set("key1", strHasher("value1")) + assert.Equal(t, "58a0a99d5019fdcad4bcf55942e833b2dfab9421", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") } { db := NewSimpleMap() - db.Set("key1", "value1") - db.Set("key2", "value2") - db.Set("key3", "value3") - assert.Equal(t, "48d60701cb4c96916f68a958b3368205ebe3809b", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") + db.Set("key1", strHasher("value1")) + db.Set("key2", strHasher("value2")) + db.Set("key3", strHasher("value3")) + assert.Equal(t, "cb56db3c7993e977f4c2789559ae3e5e468a6e9b", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") } { db := NewSimpleMap() - db.Set("key2", "value2") // NOTE: out of order - db.Set("key1", "value1") - db.Set("key3", "value3") - assert.Equal(t, "48d60701cb4c96916f68a958b3368205ebe3809b", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") + db.Set("key2", strHasher("value2")) // NOTE: out of order + db.Set("key1", strHasher("value1")) + db.Set("key3", strHasher("value3")) + assert.Equal(t, "cb56db3c7993e977f4c2789559ae3e5e468a6e9b", fmt.Sprintf("%x", db.Hash()), "Hash didn't match") } } diff --git a/merkle/simple_proof.go b/merkle/simple_proof.go index f75568fd9..83f89e598 100644 --- a/merkle/simple_proof.go +++ b/merkle/simple_proof.go @@ -10,8 +10,8 @@ type SimpleProof struct { } // proofs[0] is the proof for items[0]. -func SimpleProofsFromHashables(items []Hashable) (rootHash []byte, proofs []*SimpleProof) { - trails, rootSPN := trailsFromHashables(items) +func SimpleProofsFromHashers(items []Hasher) (rootHash []byte, proofs []*SimpleProof) { + trails, rootSPN := trailsFromHashers(items) rootHash = rootSPN.Hash proofs = make([]*SimpleProof, len(items)) for i, trail := range trails { @@ -109,7 +109,7 @@ func (spn *SimpleProofNode) FlattenAunts() [][]byte { // trails[0].Hash is the leaf hash for items[0]. // trails[i].Parent.Parent....Parent == root for all i. -func trailsFromHashables(items []Hashable) (trails []*SimpleProofNode, root *SimpleProofNode) { +func trailsFromHashers(items []Hasher) (trails []*SimpleProofNode, root *SimpleProofNode) { // Recursive impl. switch len(items) { case 0: @@ -118,8 +118,8 @@ func trailsFromHashables(items []Hashable) (trails []*SimpleProofNode, root *Sim trail := &SimpleProofNode{items[0].Hash(), nil, nil, nil} return []*SimpleProofNode{trail}, trail default: - lefts, leftRoot := trailsFromHashables(items[:(len(items)+1)/2]) - rights, rightRoot := trailsFromHashables(items[(len(items)+1)/2:]) + lefts, leftRoot := trailsFromHashers(items[:(len(items)+1)/2]) + rights, rightRoot := trailsFromHashers(items[(len(items)+1)/2:]) rootHash := SimpleHashFromTwoHashes(leftRoot.Hash, rightRoot.Hash) root := &SimpleProofNode{rootHash, nil, nil, nil} leftRoot.Parent = root diff --git a/merkle/simple_tree.go b/merkle/simple_tree.go index 3a82f4edc..182f2fdaa 100644 --- a/merkle/simple_tree.go +++ b/merkle/simple_tree.go @@ -28,17 +28,14 @@ import ( "golang.org/x/crypto/ripemd160" "github.com/tendermint/go-wire" - . "github.com/tendermint/tmlibs/common" ) func SimpleHashFromTwoHashes(left []byte, right []byte) []byte { - var n int - var err error var hasher = ripemd160.New() - wire.WriteByteSlice(left, hasher, &n, &err) - wire.WriteByteSlice(right, hasher, &n, &err) + err := wire.EncodeByteSlice(hasher, left) + err = wire.EncodeByteSlice(hasher, right) if err != nil { - PanicCrisis(err) + panic(err) } return hasher.Sum(nil) } @@ -57,27 +54,25 @@ func SimpleHashFromHashes(hashes [][]byte) []byte { } } -// Convenience for SimpleHashFromHashes. -func SimpleHashFromBinaries(items []interface{}) []byte { - hashes := make([][]byte, len(items)) - for i, item := range items { - hashes[i] = SimpleHashFromBinary(item) +// NOTE: Do not implement this, use SimpleHashFromByteslices instead. +// type Byteser interface { Bytes() []byte } +// func SimpleHashFromBytesers(items []Byteser) []byte { ... } + +func SimpleHashFromByteslices(bzs [][]byte) []byte { + hashes := make([][]byte, len(bzs)) + for i, bz := range bzs { + hashes[i] = SimpleHashFromBytes(bz) } return SimpleHashFromHashes(hashes) } -// General Convenience -func SimpleHashFromBinary(item interface{}) []byte { - hasher, n, err := ripemd160.New(), new(int), new(error) - wire.WriteBinary(item, hasher, n, err) - if *err != nil { - PanicCrisis(err) - } +func SimpleHashFromBytes(bz []byte) []byte { + hasher := ripemd160.New() + hasher.Write(bz) return hasher.Sum(nil) } -// Convenience for SimpleHashFromHashes. -func SimpleHashFromHashables(items []Hashable) []byte { +func SimpleHashFromHashers(items []Hasher) []byte { hashes := make([][]byte, len(items)) for i, item := range items { hash := item.Hash() @@ -86,8 +81,7 @@ func SimpleHashFromHashables(items []Hashable) []byte { return SimpleHashFromHashes(hashes) } -// Convenience for SimpleHashFromHashes. -func SimpleHashFromMap(m map[string]interface{}) []byte { +func SimpleHashFromMap(m map[string]Hasher) []byte { sm := NewSimpleMap() for k, v := range m { sm.Set(k, v) diff --git a/merkle/simple_tree_test.go b/merkle/simple_tree_test.go index 6299fa33b..26f35c807 100644 --- a/merkle/simple_tree_test.go +++ b/merkle/simple_tree_test.go @@ -19,14 +19,14 @@ func TestSimpleProof(t *testing.T) { total := 100 - items := make([]Hashable, total) + items := make([]Hasher, total) for i := 0; i < total; i++ { items[i] = testItem(RandBytes(32)) } - rootHash := SimpleHashFromHashables(items) + rootHash := SimpleHashFromHashers(items) - rootHash2, proofs := SimpleProofsFromHashables(items) + rootHash2, proofs := SimpleProofsFromHashers(items) if !bytes.Equal(rootHash, rootHash2) { t.Errorf("Unmatched root hashes: %X vs %X", rootHash, rootHash2) diff --git a/merkle/types.go b/merkle/types.go index 93541eda5..1a6d75e0c 100644 --- a/merkle/types.go +++ b/merkle/types.go @@ -18,6 +18,6 @@ type Tree interface { IterateRange(start []byte, end []byte, ascending bool, fx func(key []byte, value []byte) (stop bool)) (stopped bool) } -type Hashable interface { +type Hasher interface { Hash() []byte }