github.com/evdatsion/aphelion-dpos-bft@v0.32.1/crypto/merkle/simple_map.go (about)

     1  package merkle
     2  
     3  import (
     4  	"bytes"
     5  
     6  	amino "github.com/evdatsion/go-amino"
     7  	"github.com/evdatsion/aphelion-dpos-bft/crypto/tmhash"
     8  	cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common"
     9  )
    10  
    11  // Merkle tree from a map.
    12  // Leaves are `hash(key) | hash(value)`.
    13  // Leaves are sorted before Merkle hashing.
    14  type simpleMap struct {
    15  	kvs    cmn.KVPairs
    16  	sorted bool
    17  }
    18  
    19  func newSimpleMap() *simpleMap {
    20  	return &simpleMap{
    21  		kvs:    nil,
    22  		sorted: false,
    23  	}
    24  }
    25  
    26  // Set creates a kv pair of the key and the hash of the value,
    27  // and then appends it to simpleMap's kv pairs.
    28  func (sm *simpleMap) Set(key string, value []byte) {
    29  	sm.sorted = false
    30  
    31  	// The value is hashed, so you can
    32  	// check for equality with a cached value (say)
    33  	// and make a determination to fetch or not.
    34  	vhash := tmhash.Sum(value)
    35  
    36  	sm.kvs = append(sm.kvs, cmn.KVPair{
    37  		Key:   []byte(key),
    38  		Value: vhash,
    39  	})
    40  }
    41  
    42  // Hash Merkle root hash of items sorted by key
    43  // (UNSTABLE: and by value too if duplicate key).
    44  func (sm *simpleMap) Hash() []byte {
    45  	sm.Sort()
    46  	return hashKVPairs(sm.kvs)
    47  }
    48  
    49  func (sm *simpleMap) Sort() {
    50  	if sm.sorted {
    51  		return
    52  	}
    53  	sm.kvs.Sort()
    54  	sm.sorted = true
    55  }
    56  
    57  // Returns a copy of sorted KVPairs.
    58  // NOTE these contain the hashed key and value.
    59  func (sm *simpleMap) KVPairs() cmn.KVPairs {
    60  	sm.Sort()
    61  	kvs := make(cmn.KVPairs, len(sm.kvs))
    62  	copy(kvs, sm.kvs)
    63  	return kvs
    64  }
    65  
    66  //----------------------------------------
    67  
    68  // A local extension to KVPair that can be hashed.
    69  // Key and value are length prefixed and concatenated,
    70  // then hashed.
    71  type KVPair cmn.KVPair
    72  
    73  // Bytes returns key || value, with both the
    74  // key and value length prefixed.
    75  func (kv KVPair) Bytes() []byte {
    76  	var b bytes.Buffer
    77  	err := amino.EncodeByteSlice(&b, kv.Key)
    78  	if err != nil {
    79  		panic(err)
    80  	}
    81  	err = amino.EncodeByteSlice(&b, kv.Value)
    82  	if err != nil {
    83  		panic(err)
    84  	}
    85  	return b.Bytes()
    86  }
    87  
    88  func hashKVPairs(kvs cmn.KVPairs) []byte {
    89  	kvsH := make([][]byte, len(kvs))
    90  	for i, kvp := range kvs {
    91  		kvsH[i] = KVPair(kvp).Bytes()
    92  	}
    93  	return SimpleHashFromByteSlices(kvsH)
    94  }