You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

85 lines
1.6 KiB

  1. package merkle
  2. import (
  3. "github.com/tendermint/go-wire"
  4. cmn "github.com/tendermint/tmlibs/common"
  5. "golang.org/x/crypto/ripemd160"
  6. )
  7. type SimpleMap struct {
  8. kvs cmn.KVPairs
  9. sorted bool
  10. }
  11. func NewSimpleMap() *SimpleMap {
  12. return &SimpleMap{
  13. kvs: nil,
  14. sorted: false,
  15. }
  16. }
  17. func (sm *SimpleMap) Set(key string, value Hasher) {
  18. sm.sorted = false
  19. // Hash the key to blind it... why not?
  20. khash := SimpleHashFromBytes([]byte(key))
  21. // And the value is hashed too, so you can
  22. // check for equality with a cached value (say)
  23. // and make a determination to fetch or not.
  24. vhash := value.Hash()
  25. sm.kvs = append(sm.kvs, cmn.KVPair{
  26. Key: khash,
  27. Value: vhash,
  28. })
  29. }
  30. // Merkle root hash of items sorted by key
  31. // (UNSTABLE: and by value too if duplicate key).
  32. func (sm *SimpleMap) Hash() []byte {
  33. sm.Sort()
  34. return hashKVPairs(sm.kvs)
  35. }
  36. func (sm *SimpleMap) Sort() {
  37. if sm.sorted {
  38. return
  39. }
  40. sm.kvs.Sort()
  41. sm.sorted = true
  42. }
  43. // Returns a copy of sorted KVPairs.
  44. func (sm *SimpleMap) KVPairs() cmn.KVPairs {
  45. sm.Sort()
  46. kvs := make(cmn.KVPairs, len(sm.kvs))
  47. copy(kvs, sm.kvs)
  48. return kvs
  49. }
  50. //----------------------------------------
  51. // A local extension to KVPair that can be hashed.
  52. type kvPair cmn.KVPair
  53. func (kv kvPair) Hash() []byte {
  54. hasher := ripemd160.New()
  55. err := wire.EncodeByteSlice(hasher, kv.Key)
  56. if err != nil {
  57. panic(err)
  58. }
  59. err = wire.EncodeByteSlice(hasher, kv.Value)
  60. if err != nil {
  61. panic(err)
  62. }
  63. return hasher.Sum(nil)
  64. }
  65. func hashKVPairs(kvs cmn.KVPairs) []byte {
  66. kvsH := make([]Hasher, 0, len(kvs))
  67. for _, kvp := range kvs {
  68. kvsH = append(kvsH, kvPair(kvp))
  69. }
  70. return SimpleHashFromHashers(kvsH)
  71. }