2018-04-09 16:58:09 +00:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
2019-08-28 11:38:57 +00:00
|
|
|
"bytes"
|
2018-04-09 16:58:09 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"sort"
|
|
|
|
|
2019-09-16 09:18:13 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/io"
|
2018-04-09 16:58:09 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/util"
|
|
|
|
)
|
|
|
|
|
2019-10-22 14:56:03 +00:00
|
|
|
// Version attempts to get the current version stored in the
|
2018-04-09 16:58:09 +00:00
|
|
|
// underlying Store.
|
|
|
|
func Version(s Store) (string, error) {
|
|
|
|
version, err := s.Get(SYSVersion.Bytes())
|
|
|
|
return string(version), err
|
|
|
|
}
|
|
|
|
|
2019-10-22 14:56:03 +00:00
|
|
|
// PutVersion stores the given version in the underlying Store.
|
2018-04-09 16:58:09 +00:00
|
|
|
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])
|
2019-11-27 09:23:18 +00:00
|
|
|
h, err = util.Uint256DecodeBytesLE(b[:32])
|
2018-04-09 16:58:09 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-11-26 15:56:45 +00:00
|
|
|
// 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] }
|
|
|
|
|
2018-04-09 16:58:09 +00:00
|
|
|
// 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:])
|
2019-08-28 11:38:57 +00:00
|
|
|
hashes, err := read2000Uint256Hashes(v)
|
2018-04-09 16:58:09 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
hashMap[storedCount] = hashes
|
|
|
|
})
|
|
|
|
|
|
|
|
var (
|
2019-02-19 13:22:33 +00:00
|
|
|
hashes = make([]util.Uint256, 0, len(hashMap))
|
2018-11-26 15:56:45 +00:00
|
|
|
sortedKeys = make([]uint32, 0, len(hashMap))
|
2018-04-09 16:58:09 +00:00
|
|
|
)
|
|
|
|
|
2018-11-26 15:56:45 +00:00
|
|
|
for k := range hashMap {
|
|
|
|
sortedKeys = append(sortedKeys, k)
|
2018-04-09 16:58:09 +00:00
|
|
|
}
|
2018-11-26 15:56:45 +00:00
|
|
|
sort.Sort(uint32Slice(sortedKeys))
|
2018-04-09 16:58:09 +00:00
|
|
|
|
|
|
|
for _, key := range sortedKeys {
|
2019-09-11 17:33:41 +00:00
|
|
|
hashes = append(hashes[:key], hashMap[key]...)
|
2018-04-09 16:58:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return hashes, nil
|
|
|
|
}
|
2019-08-28 11:38:57 +00:00
|
|
|
|
|
|
|
// read2000Uint256Hashes attempts to read 2000 Uint256 hashes from
|
|
|
|
// the given byte array.
|
|
|
|
func read2000Uint256Hashes(b []byte) ([]util.Uint256, error) {
|
|
|
|
r := bytes.NewReader(b)
|
2019-09-16 09:18:13 +00:00
|
|
|
br := io.NewBinReaderFromIO(r)
|
2019-08-28 16:27:06 +00:00
|
|
|
lenHashes := br.ReadVarUint()
|
2019-08-28 11:38:57 +00:00
|
|
|
hashes := make([]util.Uint256, lenHashes)
|
2019-08-28 16:27:06 +00:00
|
|
|
br.ReadLE(hashes)
|
|
|
|
if br.Err != nil {
|
|
|
|
return nil, br.Err
|
2019-08-28 11:38:57 +00:00
|
|
|
}
|
|
|
|
return hashes, nil
|
|
|
|
}
|