[#40] container: Save container size estimations
Container size estimations used for basic income settlement. Also may be used for network statistic. Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
parent
8d7e5ce20a
commit
73277b88dc
1 changed files with 109 additions and 0 deletions
|
@ -17,6 +17,10 @@ type (
|
||||||
key []byte
|
key []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
storageNode struct {
|
||||||
|
info []byte
|
||||||
|
}
|
||||||
|
|
||||||
ballot struct {
|
ballot struct {
|
||||||
id []byte // id of the voting decision
|
id []byte // id of the voting decision
|
||||||
n [][]byte // already voted inner ring nodes
|
n [][]byte // already voted inner ring nodes
|
||||||
|
@ -28,6 +32,16 @@ type (
|
||||||
sig []byte
|
sig []byte
|
||||||
pub interop.PublicKey
|
pub interop.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
estimation struct {
|
||||||
|
from interop.PublicKey
|
||||||
|
size int
|
||||||
|
}
|
||||||
|
|
||||||
|
containerSizes struct {
|
||||||
|
cid []byte
|
||||||
|
estimations []estimation
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -42,6 +56,8 @@ const (
|
||||||
containerFeeKey = "ContainerFee"
|
containerFeeKey = "ContainerFee"
|
||||||
|
|
||||||
containerIDSize = 32 // SHA256 size
|
containerIDSize = 32 // SHA256 size
|
||||||
|
|
||||||
|
estimateKeyPrefix = "cnr"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -277,6 +293,60 @@ func EACL(containerID []byte) extendedACL {
|
||||||
return eacl
|
return eacl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PutContainerSize(epoch int, cid []byte, usedSize int, pubKey interop.PublicKey) bool {
|
||||||
|
if !runtime.CheckWitness(pubKey) {
|
||||||
|
panic("container: invalid witness for size estimation")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isStorageNode(pubKey) {
|
||||||
|
panic("container: only storage nodes can save size estimations")
|
||||||
|
}
|
||||||
|
|
||||||
|
key := estimationKey(epoch, cid)
|
||||||
|
s := getContainerSizeEstimation(key, cid)
|
||||||
|
|
||||||
|
// do not add estimation twice
|
||||||
|
for i := range s.estimations {
|
||||||
|
est := s.estimations[i]
|
||||||
|
if bytesEqual(est.from, pubKey) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.estimations = append(s.estimations, estimation{
|
||||||
|
from: pubKey,
|
||||||
|
size: usedSize,
|
||||||
|
})
|
||||||
|
|
||||||
|
storage.Put(ctx, key, binary.Serialize(s))
|
||||||
|
|
||||||
|
runtime.Log("container: saved container size estimation")
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetContainerSize(id []byte) containerSizes {
|
||||||
|
return getContainerSizeEstimation(id, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListContainerSizes(epoch int) [][]byte {
|
||||||
|
var buf interface{} = epoch
|
||||||
|
|
||||||
|
key := []byte(estimateKeyPrefix)
|
||||||
|
key = append(key, buf.([]byte)...)
|
||||||
|
|
||||||
|
it := storage.Find(ctx, key)
|
||||||
|
|
||||||
|
var result [][]byte
|
||||||
|
|
||||||
|
for iterator.Next(it) {
|
||||||
|
key := iterator.Key(it).([]byte)
|
||||||
|
result = append(result, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func Version() int {
|
func Version() int {
|
||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
|
@ -516,3 +586,42 @@ func isOwnerFromKey(owner []byte, key []byte) bool {
|
||||||
|
|
||||||
return bytesEqual(ownerSH, keySH)
|
return bytesEqual(ownerSH, keySH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func estimationKey(epoch int, cid []byte) []byte {
|
||||||
|
var buf interface{} = epoch
|
||||||
|
|
||||||
|
result := []byte(estimateKeyPrefix)
|
||||||
|
result = append(result, buf.([]byte)...)
|
||||||
|
|
||||||
|
return append(result, cid...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getContainerSizeEstimation(key, cid []byte) containerSizes {
|
||||||
|
data := storage.Get(ctx, key)
|
||||||
|
if data != nil {
|
||||||
|
return binary.Deserialize(data.([]byte)).(containerSizes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return containerSizes{
|
||||||
|
cid: cid,
|
||||||
|
estimations: []estimation{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isStorageNode looks into _previous_ epoch network map, because storage node
|
||||||
|
// announce container size estimation of previous epoch.
|
||||||
|
func isStorageNode(key interop.PublicKey) bool {
|
||||||
|
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
|
||||||
|
snapshot := contract.Call(netmapContractAddr, "snapshot", 1).([]storageNode)
|
||||||
|
|
||||||
|
for i := range snapshot {
|
||||||
|
nodeInfo := snapshot[i].info
|
||||||
|
nodeKey := nodeInfo[2:35] // offset:2, len:33
|
||||||
|
|
||||||
|
if bytesEqual(key, nodeKey) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue