4395cea344
In the unlikely event of overlapping hash block written to the DB we might end up with wrong hash list. That happened to me for some reason when synching with the testnet leading to the following keys with respective values: 150000 -> 2000 hashes 152000 -> 2000 hashes 153999 -> 2000 hashes Reading it hashes number 153999 and 154000 got the same values and the chain couldn't sync correctly.
95 lines
2.5 KiB
Go
95 lines
2.5 KiB
Go
package storage
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"sort"
|
|
|
|
"github.com/CityOfZion/neo-go/pkg/util"
|
|
)
|
|
|
|
// Version will attempt to get the current version stored in the
|
|
// underlying Store.
|
|
func Version(s Store) (string, error) {
|
|
version, err := s.Get(SYSVersion.Bytes())
|
|
return string(version), err
|
|
}
|
|
|
|
// PutVersion will store the given version in the underlying Store.
|
|
func PutVersion(s Store, v string) error {
|
|
return s.Put(SYSVersion.Bytes(), []byte(v))
|
|
}
|
|
|
|
// CurrentBlockHeight returns the current block height found in the
|
|
// underlying Store.
|
|
func CurrentBlockHeight(s Store) (uint32, error) {
|
|
b, err := s.Get(SYSCurrentBlock.Bytes())
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return binary.LittleEndian.Uint32(b[32:36]), nil
|
|
}
|
|
|
|
// CurrentHeaderHeight returns the current header height and hash from
|
|
// the underlying Store.
|
|
func CurrentHeaderHeight(s Store) (i uint32, h util.Uint256, err error) {
|
|
var b []byte
|
|
b, err = s.Get(SYSCurrentHeader.Bytes())
|
|
if err != nil {
|
|
return
|
|
}
|
|
i = binary.LittleEndian.Uint32(b[32:36])
|
|
h, err = util.Uint256DecodeReverseBytes(b[:32])
|
|
return
|
|
}
|
|
|
|
// uint32Slice attaches the methods of Interface to []int, sorting in increasing order.
|
|
type uint32Slice []uint32
|
|
|
|
func (p uint32Slice) Len() int { return len(p) }
|
|
func (p uint32Slice) Less(i, j int) bool { return p[i] < p[j] }
|
|
func (p uint32Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
|
|
|
// HeaderHashes returns a sorted list of header hashes retrieved from
|
|
// the given underlying Store.
|
|
func HeaderHashes(s Store) ([]util.Uint256, error) {
|
|
hashMap := make(map[uint32][]util.Uint256)
|
|
s.Seek(IXHeaderHashList.Bytes(), func(k, v []byte) {
|
|
storedCount := binary.LittleEndian.Uint32(k[1:])
|
|
hashes, err := read2000Uint256Hashes(v)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
hashMap[storedCount] = hashes
|
|
})
|
|
|
|
var (
|
|
hashes = make([]util.Uint256, 0, len(hashMap))
|
|
sortedKeys = make([]uint32, 0, len(hashMap))
|
|
)
|
|
|
|
for k := range hashMap {
|
|
sortedKeys = append(sortedKeys, k)
|
|
}
|
|
sort.Sort(uint32Slice(sortedKeys))
|
|
|
|
for _, key := range sortedKeys {
|
|
hashes = append(hashes[:key], hashMap[key]...)
|
|
}
|
|
|
|
return hashes, nil
|
|
}
|
|
|
|
// read2000Uint256Hashes attempts to read 2000 Uint256 hashes from
|
|
// the given byte array.
|
|
func read2000Uint256Hashes(b []byte) ([]util.Uint256, error) {
|
|
r := bytes.NewReader(b)
|
|
br := util.BinReader{R: r}
|
|
lenHashes := br.ReadVarUint()
|
|
hashes := make([]util.Uint256, lenHashes)
|
|
br.ReadLE(hashes)
|
|
if br.Err != nil {
|
|
return nil, br.Err
|
|
}
|
|
return hashes, nil
|
|
}
|