github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/history/kv_encoding.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package history 8 9 import ( 10 "bytes" 11 12 "github.com/hechain20/hechain/common/ledger/util" 13 "github.com/pkg/errors" 14 ) 15 16 type ( 17 dataKey []byte 18 rangeScan struct { 19 startKey, endKey []byte 20 } 21 ) 22 23 var ( 24 compositeKeySep = []byte{0x00} // used as a separator between different components of dataKey 25 savePointKey = []byte{'s'} // a single key in db for persisting savepoint 26 emptyValue = []byte{} // used to store as value for keys where only key needs to be stored (e.g., dataKeys) 27 ) 28 29 // constructDataKey builds the key of the format namespace~len(key)~key~blocknum~trannum 30 // using an order preserving encoding so that history query results are ordered by height 31 // Note: this key format is different than the format in pre-v2.0 releases and requires 32 // a historydb rebuild when upgrading an older version to v2.0. 33 func constructDataKey(ns string, key string, blocknum uint64, trannum uint64) dataKey { 34 k := append([]byte(ns), compositeKeySep...) 35 k = append(k, util.EncodeOrderPreservingVarUint64(uint64(len(key)))...) 36 k = append(k, []byte(key)...) 37 k = append(k, compositeKeySep...) 38 k = append(k, util.EncodeOrderPreservingVarUint64(blocknum)...) 39 k = append(k, util.EncodeOrderPreservingVarUint64(trannum)...) 40 return dataKey(k) 41 } 42 43 // constructRangescanKeys returns start and endKey for performing a range scan 44 // that covers all the keys for <ns, key>. 45 // startKey = namespace~len(key)~key~ 46 // endKey = namespace~len(key)~key~0xff 47 func constructRangeScan(ns string, key string) *rangeScan { 48 k := append([]byte(ns), compositeKeySep...) 49 k = append(k, util.EncodeOrderPreservingVarUint64(uint64(len(key)))...) 50 k = append(k, []byte(key)...) 51 k = append(k, compositeKeySep...) 52 53 return &rangeScan{ 54 startKey: k, 55 endKey: append(k, 0xff), 56 } 57 } 58 59 func (r *rangeScan) decodeBlockNumTranNum(dataKey dataKey) (uint64, uint64, error) { 60 blockNumTranNumBytes := bytes.TrimPrefix(dataKey, r.startKey) 61 blockNum, blockBytesConsumed, err := util.DecodeOrderPreservingVarUint64(blockNumTranNumBytes) 62 if err != nil { 63 return 0, 0, err 64 } 65 66 tranNum, tranBytesConsumed, err := util.DecodeOrderPreservingVarUint64(blockNumTranNumBytes[blockBytesConsumed:]) 67 if err != nil { 68 return 0, 0, err 69 } 70 71 // The following error should never happen. Keep the check just in case there is some unknown bug. 72 if blockBytesConsumed+tranBytesConsumed != len(blockNumTranNumBytes) { 73 return 0, 0, errors.Errorf("number of decoded bytes (%d) is not equal to the length of blockNumTranNumBytes (%d)", 74 blockBytesConsumed+tranBytesConsumed, len(blockNumTranNumBytes)) 75 } 76 return blockNum, tranNum, nil 77 }