Hashable -> Hasher; SimpleMap upgrade; No "SimpleHashFromBinary" (#128)
* Update SimpleMap to hash both keys and values for benefit; Hashable is Hasher; Don't assume go-wire
This commit is contained in:
parent
7ef6d4b813
commit
580c3db8f9
|
@ -1,5 +1,5 @@
|
||||||
hash: 1990fb145d5c5098b5ee467c59506e81b6c3b973667eeb63d83abd7ef831b919
|
hash: 1990fb145d5c5098b5ee467c59506e81b6c3b973667eeb63d83abd7ef831b919
|
||||||
updated: 2018-01-14T21:24:21.241420637-08:00
|
updated: 2018-01-21T03:46:56.821595635-08:00
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/davecgh/go-spew
|
- name: github.com/davecgh/go-spew
|
||||||
version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9
|
version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9
|
||||||
|
@ -65,7 +65,7 @@ imports:
|
||||||
- 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,7 +82,7 @@ imports:
|
||||||
- leveldb/table
|
- leveldb/table
|
||||||
- leveldb/util
|
- leveldb/util
|
||||||
- name: github.com/tendermint/go-wire
|
- name: github.com/tendermint/go-wire
|
||||||
version: b93ebdd4f306833936c243561ec30af3455dc764
|
version: 0cce10e82786f2d501827fbe158747dbc4ceeb43
|
||||||
- name: github.com/tendermint/log15
|
- name: github.com/tendermint/log15
|
||||||
version: f91285dece9f4875421b481da3e613d83d44f29b
|
version: f91285dece9f4875421b481da3e613d83d44f29b
|
||||||
- name: golang.org/x/crypto
|
- name: golang.org/x/crypto
|
||||||
|
|
|
@ -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?
|
// Hash the key to blind it... why not?
|
||||||
var vBytes []byte
|
khash := SimpleHashFromBytes([]byte(key))
|
||||||
if hashable, ok := value.(Hashable); ok {
|
|
||||||
vBytes = hashable.Hash()
|
// And the value is hashed too, so you can
|
||||||
} else {
|
// check for equality with a cached value (say)
|
||||||
vBytes, _ = wire.MarshalBinary(value)
|
// 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),
|
Key: khash,
|
||||||
Value: vBytes,
|
Value: vhash,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merkle root hash of items sorted by key.
|
// Merkle root hash of items sorted by key
|
||||||
// NOTE: Behavior is undefined when key is duplicate.
|
// (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))
|
||||||
|
@ -78,9 +77,9 @@ func (kv kvPair) Hash() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
db.Set("key1", strHasher("value1"))
|
||||||
assert.Equal(t, "d7df3e1d47fe38b51f8d897a88828026807a86b6", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
assert.Equal(t, "19618304d1ad2635c4238bce87f72331b22a11a1", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
db := NewSimpleMap()
|
db := NewSimpleMap()
|
||||||
db.Set("key1", "value2")
|
db.Set("key1", strHasher("value2"))
|
||||||
assert.Equal(t, "db415336c9be129ac38259b935a49d8e9c248c88", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
assert.Equal(t, "51cb96d3d41e1714def72eb4bacc211de9ddf284", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
db := NewSimpleMap()
|
db := NewSimpleMap()
|
||||||
db.Set("key1", "value1")
|
db.Set("key1", strHasher("value1"))
|
||||||
db.Set("key2", "value2")
|
db.Set("key2", strHasher("value2"))
|
||||||
assert.Equal(t, "fdb900a04c1de42bd3d924fc644e28a4bdce30ce", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
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("key2", strHasher("value2")) // NOTE: out of order
|
||||||
db.Set("key1", "value1")
|
db.Set("key1", strHasher("value1"))
|
||||||
assert.Equal(t, "fdb900a04c1de42bd3d924fc644e28a4bdce30ce", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
assert.Equal(t, "58a0a99d5019fdcad4bcf55942e833b2dfab9421", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
db := NewSimpleMap()
|
db := NewSimpleMap()
|
||||||
db.Set("key1", "value1")
|
db.Set("key1", strHasher("value1"))
|
||||||
db.Set("key2", "value2")
|
db.Set("key2", strHasher("value2"))
|
||||||
db.Set("key3", "value3")
|
db.Set("key3", strHasher("value3"))
|
||||||
assert.Equal(t, "488cfdaea108ef8bd406f6163555752392ae1b4a", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
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("key2", strHasher("value2")) // NOTE: out of order
|
||||||
db.Set("key1", "value1")
|
db.Set("key1", strHasher("value1"))
|
||||||
db.Set("key3", "value3")
|
db.Set("key3", strHasher("value3"))
|
||||||
assert.Equal(t, "488cfdaea108ef8bd406f6163555752392ae1b4a", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
assert.Equal(t, "cb56db3c7993e977f4c2789559ae3e5e468a6e9b", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
func SimpleProofsFromHashers(items []Hasher) (rootHash []byte, proofs []*SimpleProof) {
|
||||||
trails, rootSPN := trailsFromHashables(items)
|
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])
|
lefts, leftRoot := trailsFromHashers(items[:(len(items)+1)/2])
|
||||||
rights, rightRoot := trailsFromHashables(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
|
||||||
|
|
|
@ -54,28 +54,25 @@ func SimpleHashFromHashes(hashes [][]byte) []byte {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience for SimpleHashFromHashes.
|
// NOTE: Do not implement this, use SimpleHashFromByteslices instead.
|
||||||
func SimpleHashFromBinaries(items []interface{}) []byte {
|
// type Byteser interface { Bytes() []byte }
|
||||||
hashes := make([][]byte, len(items))
|
// func SimpleHashFromBytesers(items []Byteser) []byte { ... }
|
||||||
for i, item := range items {
|
|
||||||
hashes[i] = SimpleHashFromBinary(item)
|
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 SimpleHashFromBytes(bz []byte) []byte {
|
||||||
func SimpleHashFromBinary(item interface{}) []byte {
|
|
||||||
hasher := ripemd160.New()
|
hasher := ripemd160.New()
|
||||||
bz, err := wire.MarshalBinary(item)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
hasher.Write(bz)
|
hasher.Write(bz)
|
||||||
return hasher.Sum(nil)
|
return hasher.Sum(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience for SimpleHashFromHashes.
|
func SimpleHashFromHashers(items []Hasher) []byte {
|
||||||
func SimpleHashFromHashables(items []Hashable) []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()
|
||||||
|
@ -84,8 +81,7 @@ func SimpleHashFromHashables(items []Hashable) []byte {
|
||||||
return SimpleHashFromHashes(hashes)
|
return SimpleHashFromHashes(hashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience for SimpleHashFromHashes.
|
func SimpleHashFromMap(m map[string]Hasher) []byte {
|
||||||
func SimpleHashFromMap(m map[string]interface{}) []byte {
|
|
||||||
sm := NewSimpleMap()
|
sm := NewSimpleMap()
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
sm.Set(k, v)
|
sm.Set(k, v)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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…
Reference in New Issue