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.

86 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 interface{}) {
  18. sm.sorted = false
  19. // Is value Hashable?
  20. var vBytes []byte
  21. if hashable, ok := value.(Hashable); ok {
  22. vBytes = hashable.Hash()
  23. } else {
  24. vBytes = wire.BinaryBytes(value)
  25. }
  26. sm.kvs = append(sm.kvs, cmn.KVPair{
  27. Key: []byte(key),
  28. Value: vBytes,
  29. })
  30. }
  31. // Merkle root hash of items sorted by key.
  32. // NOTE: Behavior is undefined when key is duplicate.
  33. func (sm *SimpleMap) Hash() []byte {
  34. sm.Sort()
  35. return hashKVPairs(sm.kvs)
  36. }
  37. func (sm *SimpleMap) Sort() {
  38. if sm.sorted {
  39. return
  40. }
  41. sm.kvs.Sort()
  42. sm.sorted = true
  43. }
  44. // Returns a copy of sorted KVPairs.
  45. // CONTRACT: The returned slice must not be mutated.
  46. func (sm *SimpleMap) KVPairs() cmn.KVPairs {
  47. sm.Sort()
  48. kvs := make(cmn.KVPairs, len(sm.kvs))
  49. copy(kvs, sm.kvs)
  50. return kvs
  51. }
  52. //----------------------------------------
  53. // A local extension to KVPair that can be hashed.
  54. type kvPair cmn.KVPair
  55. func (kv kvPair) Hash() []byte {
  56. hasher, n, err := ripemd160.New(), new(int), new(error)
  57. wire.WriteByteSlice(kv.Key, hasher, n, err)
  58. if *err != nil {
  59. panic(*err)
  60. }
  61. wire.WriteByteSlice(kv.Value, hasher, n, err)
  62. if *err != nil {
  63. panic(*err)
  64. }
  65. return hasher.Sum(nil)
  66. }
  67. func hashKVPairs(kvs cmn.KVPairs) []byte {
  68. kvsH := make([]Hashable, 0, len(kvs))
  69. for _, kvp := range kvs {
  70. kvsH = append(kvsH, kvPair(kvp))
  71. }
  72. return SimpleHashFromHashables(kvsH)
  73. }