Browse Source

Merge pull request #123 from tendermint/sdk2

Merge sdk2 into develop
pull/1842/head
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
027c37281d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 194 additions and 203 deletions
  1. +4
    -0
      Makefile
  2. +1
    -21
      cli/setup.go
  3. +2
    -4
      common/repeat_timer.go
  4. +63
    -51
      common/repeat_timer_test.go
  5. +3
    -3
      db/backend_test.go
  6. +2
    -2
      db/c_level_db.go
  7. +2
    -2
      db/c_level_db_test.go
  8. +1
    -1
      db/common_test.go
  9. +10
    -8
      db/db.go
  10. +1
    -1
      db/fsdb.go
  11. +2
    -2
      db/go_level_db.go
  12. +1
    -1
      db/mem_db.go
  13. +19
    -32
      glide.lock
  14. +13
    -4
      glide.yaml
  15. +21
    -22
      merkle/simple_map.go
  16. +24
    -18
      merkle/simple_map_test.go
  17. +5
    -5
      merkle/simple_proof.go
  18. +16
    -22
      merkle/simple_tree.go
  19. +3
    -3
      merkle/simple_tree_test.go
  20. +1
    -1
      merkle/types.go

+ 4
- 0
Makefile View File

@ -62,12 +62,16 @@ get_vendor_deps:
@echo "--> Running glide install" @echo "--> Running glide install"
@glide install @glide install
######################################## ########################################
### Testing ### Testing
test: test:
go test -tags gcc `glide novendor` go test -tags gcc `glide novendor`
test100:
@for i in {1..100}; do make test; done
######################################## ########################################
### Formatting, linting, and vetting ### Formatting, linting, and vetting


+ 1
- 21
cli/setup.go View File

@ -8,9 +8,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
data "github.com/tendermint/go-wire/data"
"github.com/tendermint/go-wire/data/base58"
) )
const ( const (
@ -42,7 +39,7 @@ func PrepareBaseCmd(cmd *cobra.Command, envPrefix, defaultHome string) Executor
func PrepareMainCmd(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(EncodingFlag, "e", "hex", "Binary encoding (hex|b64|btc)")
cmd.PersistentFlags().StringP(OutputFlag, "o", "text", "Output format (text|json)") 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) return PrepareBaseCmd(cmd, envPrefix, defaultHome)
} }
@ -147,23 +144,6 @@ func bindFlagsLoadViper(cmd *cobra.Command, args []string) error {
return nil 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 { func validateOutput(cmd *cobra.Command, args []string) error {
// validate output format // validate output format
output := viper.GetString(OutputFlag) output := viper.GetString(OutputFlag)


+ 2
- 4
common/repeat_timer.go View File

@ -80,13 +80,11 @@ func (t *logicalTicker) fireRoutine(interval time.Duration) {
} }
// Init `lasttime` end // Init `lasttime` end
timeleft := interval
for { for {
select { select {
case newtime := <-source: case newtime := <-source:
elapsed := newtime.Sub(lasttime) elapsed := newtime.Sub(lasttime)
timeleft -= elapsed
if timeleft <= 0 {
if interval <= elapsed {
// Block for determinism until the ticker is stopped. // Block for determinism until the ticker is stopped.
select { select {
case t.ch <- newtime: case t.ch <- newtime:
@ -97,7 +95,7 @@ func (t *logicalTicker) fireRoutine(interval time.Duration) {
// Don't try to "catch up" by sending more. // Don't try to "catch up" by sending more.
// "Ticker adjusts the intervals or drops ticks to make up for // "Ticker adjusts the intervals or drops ticks to make up for
// slow receivers" - https://golang.org/pkg/time/#Ticker // slow receivers" - https://golang.org/pkg/time/#Ticker
timeleft = interval
lasttime = newtime
} }
case <-t.quit: case <-t.quit:
return // done return // done


+ 63
- 51
common/repeat_timer_test.go View File

@ -1,6 +1,7 @@
package common package common
import ( import (
"sync"
"testing" "testing"
"time" "time"
@ -13,29 +14,42 @@ func TestDefaultTicker(t *testing.T) {
ticker.Stop() ticker.Stop()
} }
func TestRepeat(t *testing.T) {
func TestRepeatTimer(t *testing.T) {
ch := make(chan time.Time, 100) 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 done := true
select { select {
case <-rt.Chan(): case <-rt.Chan():
@ -46,46 +60,44 @@ func TestRepeat(t *testing.T) {
} }
tm := NewLogicalTickerMaker(ch) 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. // After a stop, nothing more is sent.
rt.Stop() rt.Stop()
tock(t, rt, 0)
tock(t, rt, []int64{})
// Another stop panics. // Another stop panics.
assert.Panics(t, func() { rt.Stop() }) assert.Panics(t, func() { rt.Stop() })


+ 3
- 3
db/backend_test.go View File

@ -15,7 +15,7 @@ func cleanupDBDir(dir, name string) {
os.RemoveAll(filepath.Join(dir, name) + ".db") os.RemoveAll(filepath.Join(dir, name) + ".db")
} }
func testBackendGetSetDelete(t *testing.T, backend string) {
func testBackendGetSetDelete(t *testing.T, backend DBBackendType) {
// Default // Default
dir, dirname := cmn.Tempdir(fmt.Sprintf("test_backend_%s_", backend)) dir, dirname := cmn.Tempdir(fmt.Sprintf("test_backend_%s_", backend))
defer dir.Close() 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)) name := cmn.Fmt("test_%x", cmn.RandStr(12))
db := NewDB(name, GoLevelDBBackendStr, "")
db := NewDB(name, GoLevelDBBackend, "")
defer cleanupDBDir("", name) defer cleanupDBDir("", name)
_, ok := db.(*GoLevelDB) _, ok := db.(*GoLevelDB)


+ 2
- 2
db/c_level_db.go View File

@ -14,8 +14,8 @@ func init() {
dbCreator := func(name string, dir string) (DB, error) { dbCreator := func(name string, dir string) (DB, error) {
return NewCLevelDB(name, dir) return NewCLevelDB(name, dir)
} }
registerDBCreator(LevelDBBackendStr, dbCreator, true)
registerDBCreator(CLevelDBBackendStr, dbCreator, false)
registerDBCreator(LevelDBBackend, dbCreator, true)
registerDBCreator(CLevelDBBackend, dbCreator, false)
} }
var _ DB = (*CLevelDB)(nil) var _ DB = (*CLevelDB)(nil)


+ 2
- 2
db/c_level_db_test.go View File

@ -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)) name := cmn.Fmt("test_%x", cmn.RandStr(12))
db := NewDB(name, LevelDBBackendStr, "")
db := NewDB(name, LevelDBBackend, "")
defer cleanupDBDir("", name) defer cleanupDBDir("", name)
_, ok := db.(*CLevelDB) _, ok := db.(*CLevelDB)


+ 1
- 1
db/common_test.go View File

@ -45,7 +45,7 @@ func checkValuePanics(t *testing.T, itr Iterator) {
assert.Panics(t, func() { itr.Key() }, "checkValuePanics expected panic but didn't") 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") dir, dirname := cmn.Tempdir("test_go_iterator")
db = NewDB("testdb", backend, dirname) db = NewDB("testdb", backend, dirname)
dir.Close() dir.Close()


+ 10
- 8
db/db.go View File

@ -5,19 +5,21 @@ import "fmt"
//---------------------------------------- //----------------------------------------
// Main entry // Main entry
type DBBackendType string
const ( 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) 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] _, ok := backends[backend]
if !force && ok { if !force && ok {
return return
@ -25,7 +27,7 @@ func registerDBCreator(backend string, creator dbCreator, force bool) {
backends[backend] = creator 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) db, err := backends[backend](name, dir)
if err != nil { if err != nil {
panic(fmt.Sprintf("Error initializing DB: %v", err)) panic(fmt.Sprintf("Error initializing DB: %v", err))


+ 1
- 1
db/fsdb.go View File

@ -19,7 +19,7 @@ const (
) )
func init() { 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") dbPath := filepath.Join(dir, name+".db")
return NewFSDB(dbPath), nil return NewFSDB(dbPath), nil
}, false) }, false)


+ 2
- 2
db/go_level_db.go View File

@ -17,8 +17,8 @@ func init() {
dbCreator := func(name string, dir string) (DB, error) { dbCreator := func(name string, dir string) (DB, error) {
return NewGoLevelDB(name, dir) return NewGoLevelDB(name, dir)
} }
registerDBCreator(LevelDBBackendStr, dbCreator, false)
registerDBCreator(GoLevelDBBackendStr, dbCreator, false)
registerDBCreator(LevelDBBackend, dbCreator, false)
registerDBCreator(GoLevelDBBackend, dbCreator, false)
} }
var _ DB = (*GoLevelDB)(nil) var _ DB = (*GoLevelDB)(nil)


+ 1
- 1
db/mem_db.go View File

@ -7,7 +7,7 @@ import (
) )
func init() { func init() {
registerDBCreator(MemDBBackendStr, func(name string, dir string) (DB, error) {
registerDBCreator(MemDBBackend, func(name string, dir string) (DB, error) {
return NewMemDB(), nil return NewMemDB(), nil
}, false) }, false)
} }


+ 19
- 32
glide.lock View File

@ -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: imports:
- name: github.com/davecgh/go-spew
version: 346938d642f2ec3594ed81d874461961cd0faa76
subpackages:
- spew
- name: github.com/fsnotify/fsnotify - name: github.com/fsnotify/fsnotify
version: 4da3e2cfbabc9f751898f250b49f2439785783a1
version: c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9
- name: github.com/go-kit/kit - name: github.com/go-kit/kit
version: e2b298466b32c7cd5579a9b9b07e968fc9d9452c
version: 4dc7be5d2d12881735283bcab7352178e190fc71
subpackages: subpackages:
- log - log
- log/level - log/level
@ -14,7 +18,7 @@ imports:
- name: github.com/go-stack/stack - name: github.com/go-stack/stack
version: 817915b46b97fd7bb80e8ab6b69f01a53ac3eebf version: 817915b46b97fd7bb80e8ab6b69f01a53ac3eebf
- name: github.com/gogo/protobuf - name: github.com/gogo/protobuf
version: 342cbe0a04158f6dcb03ca0079991a51a4248c02
version: 1adfc126b41513cc696b209667c8656ea7aac67c
subpackages: subpackages:
- gogoproto - gogoproto
- proto - proto
@ -39,21 +43,15 @@ imports:
- name: github.com/kr/logfmt - name: github.com/kr/logfmt
version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0 version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0
- name: github.com/magiconair/properties - 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 - name: github.com/mitchellh/mapstructure
version: 06020f85339e21b2478f756a78e295255ffa4d6a
- name: github.com/pelletier/go-buffruneio
version: c37440a7cf42ac63b919c752ca73a85067e05992
version: b4575eea38cca1123ec2dc90c26529b5c5acfcff
- name: github.com/pelletier/go-toml - name: github.com/pelletier/go-toml
version: 13d49d4606eb801b8f01ae542b4afc4c6ee3d84a
version: acdc4509485b587f5e675510c4f2c63e90ff68a8
- name: github.com/pkg/errors - name: github.com/pkg/errors
version: 645ef00459ed84a119197bfb8d8205042c6df63d version: 645ef00459ed84a119197bfb8d8205042c6df63d
- name: github.com/spf13/afero - name: github.com/spf13/afero
version: 5660eeed305fe5f69c8fc6cf899132a459a97064
version: bb8f1927f2a9d3ab41c9340aa034f6b803f4359c
subpackages: subpackages:
- mem - mem
- name: github.com/spf13/cast - name: github.com/spf13/cast
@ -61,11 +59,11 @@ imports:
- name: github.com/spf13/cobra - name: github.com/spf13/cobra
version: 7b2c5ac9fc04fc5efafb60700713d4fa609b777b version: 7b2c5ac9fc04fc5efafb60700713d4fa609b777b
- name: github.com/spf13/jwalterweatherman - name: github.com/spf13/jwalterweatherman
version: 12bd96e66386c1960ab0f74ced1362f66f552f7b
version: 7c0cea34c8ece3fbeb2b27ab9b59511d360fb394
- name: github.com/spf13/pflag - name: github.com/spf13/pflag
version: 97afa5e7ca8a08a383cb259e06636b5e2cc7897f version: 97afa5e7ca8a08a383cb259e06636b5e2cc7897f
- name: github.com/spf13/viper - name: github.com/spf13/viper
version: 8ef37cbca71638bf32f3d5e194117d4cb46da163
version: 25b30aa063fc18e48662b86996252eabdcf2f0c7
- name: github.com/syndtr/goleveldb - name: github.com/syndtr/goleveldb
version: b89cc31ef7977104127d34c1bd31ebd1a9db2199 version: b89cc31ef7977104127d34c1bd31ebd1a9db2199
subpackages: subpackages:
@ -82,20 +80,13 @@ imports:
- leveldb/table - leveldb/table
- leveldb/util - leveldb/util
- name: github.com/tendermint/go-wire - 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 - name: golang.org/x/crypto
version: edd5e9b0879d13ee6970a50153d85b8fec9f7686 version: edd5e9b0879d13ee6970a50153d85b8fec9f7686
subpackages: subpackages:
- ripemd160 - ripemd160
- name: golang.org/x/sys - name: golang.org/x/sys
version: 8dbc5d05d6edcc104950cc299a1ce6641235bc86
version: 37707fdb30a5b38865cfb95e5aab41707daec7fd
subpackages: subpackages:
- unix - unix
- name: golang.org/x/text - name: golang.org/x/text
@ -104,18 +95,14 @@ imports:
- transform - transform
- unicode/norm - unicode/norm
- name: gopkg.in/yaml.v2 - name: gopkg.in/yaml.v2
version: eb3733d160e74a9c7e442f435eb3bea458e1d19f
version: d670f9405373e636a5a2765eea47fac0c9bc91a4
testImports: testImports:
- name: github.com/davecgh/go-spew
version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9
subpackages:
- spew
- name: github.com/pmezard/go-difflib - name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages: subpackages:
- difflib - difflib
- name: github.com/stretchr/testify - name: github.com/stretchr/testify
version: 2aa2c176b9dab406a6970f6a55f513e8a8c8b18f
version: 12b6f73e6084dad08a7c6e575284b177ecafbc71
subpackages: subpackages:
- assert - assert
- require - require

+ 13
- 4
glide.yaml View File

@ -1,30 +1,39 @@
package: github.com/tendermint/tmlibs package: github.com/tendermint/tmlibs
import: import:
- package: github.com/go-kit/kit - package: github.com/go-kit/kit
version: ^0.6.0
subpackages: subpackages:
- log - log
- log/level - log/level
- log/term - log/term
- package: github.com/go-logfmt/logfmt - 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/jmhodges/levigo
- package: github.com/pkg/errors - package: github.com/pkg/errors
version: ^0.8.0
- package: github.com/spf13/cobra - package: github.com/spf13/cobra
version: ^0.0.1
- package: github.com/spf13/viper - package: github.com/spf13/viper
version: ^1.0.0
- package: github.com/syndtr/goleveldb - package: github.com/syndtr/goleveldb
subpackages: subpackages:
- leveldb - leveldb
- leveldb/errors - leveldb/errors
- leveldb/iterator
- leveldb/opt - leveldb/opt
- package: github.com/tendermint/go-wire - package: github.com/tendermint/go-wire
subpackages:
- data
- data/base58
- package: github.com/tendermint/log15
version: develop
- package: golang.org/x/crypto - package: golang.org/x/crypto
subpackages: subpackages:
- ripemd160 - ripemd160
testImport: testImport:
- package: github.com/stretchr/testify - package: github.com/stretchr/testify
version: ^1.2.1
subpackages: subpackages:
- assert - assert
- require - require

+ 21
- 22
merkle/simple_map.go View File

@ -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 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{ 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 { func (sm *SimpleMap) Hash() []byte {
sm.Sort() sm.Sort()
return hashKVPairs(sm.kvs) return hashKVPairs(sm.kvs)
@ -51,7 +51,6 @@ func (sm *SimpleMap) Sort() {
} }
// Returns a copy of sorted KVPairs. // Returns a copy of sorted KVPairs.
// CONTRACT: The returned slice must not be mutated.
func (sm *SimpleMap) KVPairs() cmn.KVPairs { func (sm *SimpleMap) KVPairs() cmn.KVPairs {
sm.Sort() sm.Sort()
kvs := make(cmn.KVPairs, len(sm.kvs)) kvs := make(cmn.KVPairs, len(sm.kvs))
@ -65,22 +64,22 @@ func (sm *SimpleMap) KVPairs() cmn.KVPairs {
type kvPair cmn.KVPair type kvPair cmn.KVPair
func (kv kvPair) Hash() []byte { 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) return hasher.Sum(nil)
} }
func hashKVPairs(kvs cmn.KVPairs) []byte { func hashKVPairs(kvs cmn.KVPairs) []byte {
kvsH := make([]Hashable, 0, len(kvs))
kvsH := make([]Hasher, 0, len(kvs))
for _, kvp := range kvs { for _, kvp := range kvs {
kvsH = append(kvsH, kvPair(kvp)) kvsH = append(kvsH, kvPair(kvp))
} }
return SimpleHashFromHashables(kvsH)
return SimpleHashFromHashers(kvsH)
} }

+ 24
- 18
merkle/simple_map_test.go View File

@ -7,41 +7,47 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type strHasher string
func (str strHasher) Hash() []byte {
return SimpleHashFromBytes([]byte(str))
}
func TestSimpleMap(t *testing.T) { func TestSimpleMap(t *testing.T) {
{ {
db := NewSimpleMap() 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 := 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 := 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 := 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 := 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 := 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")
} }
} }

+ 5
- 5
merkle/simple_proof.go View File

@ -10,8 +10,8 @@ type SimpleProof struct {
} }
// proofs[0] is the proof for items[0]. // 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 rootHash = rootSPN.Hash
proofs = make([]*SimpleProof, len(items)) proofs = make([]*SimpleProof, len(items))
for i, trail := range trails { 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[0].Hash is the leaf hash for items[0].
// trails[i].Parent.Parent....Parent == root for all i. // 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. // Recursive impl.
switch len(items) { switch len(items) {
case 0: case 0:
@ -118,8 +118,8 @@ func trailsFromHashables(items []Hashable) (trails []*SimpleProofNode, root *Sim
trail := &SimpleProofNode{items[0].Hash(), nil, nil, nil} trail := &SimpleProofNode{items[0].Hash(), nil, nil, nil}
return []*SimpleProofNode{trail}, trail return []*SimpleProofNode{trail}, trail
default: 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) rootHash := SimpleHashFromTwoHashes(leftRoot.Hash, rightRoot.Hash)
root := &SimpleProofNode{rootHash, nil, nil, nil} root := &SimpleProofNode{rootHash, nil, nil, nil}
leftRoot.Parent = root leftRoot.Parent = root


+ 16
- 22
merkle/simple_tree.go View File

@ -28,17 +28,14 @@ import (
"golang.org/x/crypto/ripemd160" "golang.org/x/crypto/ripemd160"
"github.com/tendermint/go-wire" "github.com/tendermint/go-wire"
. "github.com/tendermint/tmlibs/common"
) )
func SimpleHashFromTwoHashes(left []byte, right []byte) []byte { func SimpleHashFromTwoHashes(left []byte, right []byte) []byte {
var n int
var err error
var hasher = ripemd160.New() 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 { if err != nil {
PanicCrisis(err)
panic(err)
} }
return hasher.Sum(nil) 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) 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) return hasher.Sum(nil)
} }
// Convenience for SimpleHashFromHashes.
func SimpleHashFromHashables(items []Hashable) []byte {
func SimpleHashFromHashers(items []Hasher) []byte {
hashes := make([][]byte, len(items)) hashes := make([][]byte, len(items))
for i, item := range items { for i, item := range items {
hash := item.Hash() hash := item.Hash()
@ -86,8 +81,7 @@ func SimpleHashFromHashables(items []Hashable) []byte {
return SimpleHashFromHashes(hashes) return SimpleHashFromHashes(hashes)
} }
// Convenience for SimpleHashFromHashes.
func SimpleHashFromMap(m map[string]interface{}) []byte {
func SimpleHashFromMap(m map[string]Hasher) []byte {
sm := NewSimpleMap() sm := NewSimpleMap()
for k, v := range m { for k, v := range m {
sm.Set(k, v) sm.Set(k, v)


+ 3
- 3
merkle/simple_tree_test.go View File

@ -19,14 +19,14 @@ func TestSimpleProof(t *testing.T) {
total := 100 total := 100
items := make([]Hashable, total)
items := make([]Hasher, total)
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
items[i] = testItem(RandBytes(32)) items[i] = testItem(RandBytes(32))
} }
rootHash := SimpleHashFromHashables(items)
rootHash := SimpleHashFromHashers(items)
rootHash2, proofs := SimpleProofsFromHashables(items)
rootHash2, proofs := SimpleProofsFromHashers(items)
if !bytes.Equal(rootHash, rootHash2) { if !bytes.Equal(rootHash, rootHash2) {
t.Errorf("Unmatched root hashes: %X vs %X", rootHash, rootHash2) t.Errorf("Unmatched root hashes: %X vs %X", rootHash, rootHash2)


+ 1
- 1
merkle/types.go View File

@ -18,6 +18,6 @@ type Tree interface {
IterateRange(start []byte, end []byte, ascending bool, fx func(key []byte, value []byte) (stop bool)) (stopped bool) 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 Hash() []byte
} }

Loading…
Cancel
Save