WIP: IR unit tests #279
56 changed files with 3080 additions and 225 deletions
|
@ -104,13 +104,13 @@ func (l GlagoliticLetter) String() string {
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
type alphabetContracts map[GlagoliticLetter]util.Uint160
|
type AlphabetContracts map[GlagoliticLetter]util.Uint160
|
||||||
|
|
||||||
func newAlphabetContracts() alphabetContracts {
|
func NewAlphabetContracts() AlphabetContracts {
|
||||||
return make(map[GlagoliticLetter]util.Uint160, lastLetterNum)
|
return make(map[GlagoliticLetter]util.Uint160, lastLetterNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a alphabetContracts) GetByIndex(ind int) (util.Uint160, bool) {
|
func (a AlphabetContracts) GetByIndex(ind int) (util.Uint160, bool) {
|
||||||
if ind < 0 || ind >= int(lastLetterNum) {
|
if ind < 0 || ind >= int(lastLetterNum) {
|
||||||
return util.Uint160{}, false
|
return util.Uint160{}, false
|
||||||
}
|
}
|
||||||
|
@ -120,16 +120,16 @@ func (a alphabetContracts) GetByIndex(ind int) (util.Uint160, bool) {
|
||||||
return contract, ok
|
return contract, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a alphabetContracts) indexOutOfRange(ind int) bool {
|
func (a AlphabetContracts) indexOutOfRange(ind int) bool {
|
||||||
return ind < 0 && ind >= len(a)
|
return ind < 0 && ind >= len(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a alphabetContracts) iterate(f func(GlagoliticLetter, util.Uint160)) {
|
func (a AlphabetContracts) iterate(f func(GlagoliticLetter, util.Uint160)) {
|
||||||
for letter, contract := range a {
|
for letter, contract := range a {
|
||||||
f(letter, contract)
|
f(letter, contract)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *alphabetContracts) set(l GlagoliticLetter, h util.Uint160) {
|
func (a *AlphabetContracts) set(l GlagoliticLetter, h util.Uint160) {
|
||||||
(*a)[l] = h
|
(*a)[l] = h
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,10 @@ type (
|
||||||
|
|
||||||
newEpochHandler func()
|
newEpochHandler func()
|
||||||
|
|
||||||
|
containerEstimationStopper interface {
|
||||||
|
StopEstimation(p container.StopEstimationPrm) error
|
||||||
|
}
|
||||||
|
|
||||||
epochTimerArgs struct {
|
epochTimerArgs struct {
|
||||||
l *logger.Logger
|
l *logger.Logger
|
||||||
|
|
||||||
|
@ -40,7 +44,7 @@ type (
|
||||||
|
|
||||||
newEpochHandlers []newEpochHandler
|
newEpochHandlers []newEpochHandler
|
||||||
|
|
||||||
cnrWrapper *container.Client // to invoke stop container estimation
|
cnrWrapper containerEstimationStopper // to invoke stop container estimation
|
||||||
epoch epochState // to specify which epoch to stop, and epoch duration
|
epoch epochState // to specify which epoch to stop, and epoch duration
|
||||||
|
|
||||||
stopEstimationDMul uint32 // X: X/Y of epoch in blocks
|
stopEstimationDMul uint32 // X: X/Y of epoch in blocks
|
||||||
|
|
167
pkg/innerring/blocktimer_test.go
Normal file
167
pkg/innerring/blocktimer_test.go
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
package innerring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEpochTimer(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
alphaState := &testAlphabetState{isAlphabet: true}
|
||||||
|
neh := &testNewEpochHandler{}
|
||||||
|
cnrStopper := &testContainerEstStopper{}
|
||||||
|
epochState := &testEpochState{
|
||||||
|
counter: 99,
|
||||||
|
duration: 10,
|
||||||
|
}
|
||||||
|
collectHandler := &testEventHandler{}
|
||||||
|
distributeHandler := &testEventHandler{}
|
||||||
|
|
||||||
|
args := &epochTimerArgs{
|
||||||
|
l: test.NewLogger(t, true),
|
||||||
|
alphabetState: alphaState,
|
||||||
|
newEpochHandlers: []newEpochHandler{neh.Handle},
|
||||||
|
cnrWrapper: cnrStopper,
|
||||||
|
epoch: epochState,
|
||||||
|
stopEstimationDMul: 2,
|
||||||
|
stopEstimationDDiv: 10,
|
||||||
|
collectBasicIncome: subEpochEventHandler{
|
||||||
|
handler: collectHandler.Handle,
|
||||||
|
durationMul: 3,
|
||||||
|
durationDiv: 10,
|
||||||
|
},
|
||||||
|
distributeBasicIncome: subEpochEventHandler{
|
||||||
|
handler: distributeHandler.Handle,
|
||||||
|
durationMul: 4,
|
||||||
|
durationDiv: 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
et := newEpochTimer(args)
|
||||||
|
err := et.Reset()
|
||||||
|
require.NoError(t, err, "failed to reset timer")
|
||||||
|
|
||||||
|
et.Tick(100)
|
||||||
|
require.Equal(t, 0, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 0, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 0, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 0, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
|
||||||
|
et.Tick(101)
|
||||||
|
require.Equal(t, 0, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 1, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 0, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 0, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
|
||||||
|
et.Tick(102)
|
||||||
|
require.Equal(t, 0, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 1, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 1, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 0, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
|
||||||
|
et.Tick(103)
|
||||||
|
require.Equal(t, 0, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 1, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 1, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 1, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
|
||||||
|
var h uint32
|
||||||
|
for h = 104; h < 109; h++ {
|
||||||
|
et.Tick(h)
|
||||||
|
require.Equal(t, 0, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 1, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 1, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 1, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
}
|
||||||
|
|
||||||
|
et.Tick(109)
|
||||||
|
require.Equal(t, 1, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 1, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 1, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 1, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
|
||||||
|
et.Tick(110)
|
||||||
|
require.Equal(t, 1, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 1, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 1, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 1, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
|
||||||
|
et.Tick(111)
|
||||||
|
require.Equal(t, 1, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 2, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 1, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 1, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
|
||||||
|
et.Tick(112)
|
||||||
|
require.Equal(t, 1, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 2, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 2, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 1, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
|
||||||
|
et.Tick(113)
|
||||||
|
require.Equal(t, 1, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 2, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 2, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 2, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
|
||||||
|
for h = 114; h < 119; h++ {
|
||||||
|
et.Tick(h)
|
||||||
|
require.Equal(t, 1, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 2, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 2, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 2, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
}
|
||||||
|
et.Tick(120)
|
||||||
|
require.Equal(t, 2, neh.called, "invalid new epoch handler calls")
|
||||||
|
require.Equal(t, 2, cnrStopper.called, "invalid container stop handler calls")
|
||||||
|
require.Equal(t, 2, collectHandler.called, "invalid collect basic income calls")
|
||||||
|
require.Equal(t, 2, distributeHandler.called, "invalid distribute basic income calls")
|
||||||
|
}
|
||||||
|
|
||||||
|
type testAlphabetState struct {
|
||||||
|
isAlphabet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testAlphabetState) IsAlphabet() bool {
|
||||||
|
return s.isAlphabet
|
||||||
|
}
|
||||||
|
|
||||||
|
type testNewEpochHandler struct {
|
||||||
|
called int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *testNewEpochHandler) Handle() {
|
||||||
|
h.called++
|
||||||
|
}
|
||||||
|
|
||||||
|
type testContainerEstStopper struct {
|
||||||
|
called int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testContainerEstStopper) StopEstimation(_ container.StopEstimationPrm) error {
|
||||||
|
s.called++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testEpochState struct {
|
||||||
|
counter uint64
|
||||||
|
duration uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testEpochState) EpochCounter() uint64 {
|
||||||
|
return s.counter
|
||||||
|
}
|
||||||
|
func (s *testEpochState) EpochDuration() uint64 {
|
||||||
|
return s.duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type testEventHandler struct {
|
||||||
|
called int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *testEventHandler) Handle(e event.Event) {
|
||||||
|
h.called++
|
||||||
|
}
|
68
pkg/innerring/config/fee_test.go
Normal file
68
pkg/innerring/config/fee_test.go
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfig(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
t.Run("all set", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
file := strings.NewReader(
|
||||||
|
`
|
||||||
|
fee:
|
||||||
|
main_chain: 50000000
|
||||||
|
side_chain: 200000000
|
||||||
|
named_container_register: 2500000000
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
err := v.ReadConfig(file)
|
||||||
|
require.NoError(t, err, "read config file failed")
|
||||||
|
|
||||||
|
config := NewFeeConfig(v)
|
||||||
|
require.Equal(t, fixedn.Fixed8(50000000), config.MainChainFee(), "main chain fee invalid")
|
||||||
|
require.Equal(t, fixedn.Fixed8(200000000), config.SideChainFee(), "side chain fee invalid")
|
||||||
|
require.Equal(t, fixedn.Fixed8(2500000000), config.NamedContainerRegistrationFee(), "named container register fee invalid")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nothing set", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
file := strings.NewReader("")
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
err := v.ReadConfig(file)
|
||||||
|
require.NoError(t, err, "read config file failed")
|
||||||
|
|
||||||
|
config := NewFeeConfig(v)
|
||||||
|
require.Equal(t, fixedn.Fixed8(0), config.MainChainFee(), "main chain fee invalid")
|
||||||
|
require.Equal(t, fixedn.Fixed8(0), config.SideChainFee(), "side chain fee invalid")
|
||||||
|
require.Equal(t, fixedn.Fixed8(0), config.NamedContainerRegistrationFee(), "named container register fee invalid")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("partially set", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
file := strings.NewReader(
|
||||||
|
`
|
||||||
|
fee:
|
||||||
|
main_chain: 10
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
err := v.ReadConfig(file)
|
||||||
|
require.NoError(t, err, "read config file failed")
|
||||||
|
|
||||||
|
config := NewFeeConfig(v)
|
||||||
|
require.Equal(t, fixedn.Fixed8(10), config.MainChainFee(), "main chain fee invalid")
|
||||||
|
require.Equal(t, fixedn.Fixed8(0), config.SideChainFee(), "side chain fee invalid")
|
||||||
|
require.Equal(t, fixedn.Fixed8(0), config.NamedContainerRegistrationFee(), "named container register fee invalid")
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -20,10 +20,10 @@ type contracts struct {
|
||||||
processing util.Uint160 // in mainnet
|
processing util.Uint160 // in mainnet
|
||||||
frostfsID util.Uint160 // in morph
|
frostfsID util.Uint160 // in morph
|
||||||
|
|
||||||
alphabet alphabetContracts // in morph
|
alphabet AlphabetContracts // in morph
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseContracts(cfg *viper.Viper, morph *client.Client, withoutMainNet, withoutMainNotary, withoutSideNotary bool) (*contracts, error) {
|
func parseContracts(cfg *viper.Viper, morph nnsResolver, withoutMainNet, withoutMainNotary, withoutSideNotary bool) (*contracts, error) {
|
||||||
var (
|
var (
|
||||||
result = new(contracts)
|
result = new(contracts)
|
||||||
err error
|
err error
|
||||||
|
@ -78,9 +78,9 @@ func parseContracts(cfg *viper.Viper, morph *client.Client, withoutMainNet, with
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseAlphabetContracts(cfg *viper.Viper, morph *client.Client) (alphabetContracts, error) {
|
func parseAlphabetContracts(cfg *viper.Viper, morph nnsResolver) (AlphabetContracts, error) {
|
||||||
num := GlagoliticLetter(cfg.GetUint("contracts.alphabet.amount"))
|
num := GlagoliticLetter(cfg.GetUint("contracts.alphabet.amount"))
|
||||||
alpha := newAlphabetContracts()
|
alpha := NewAlphabetContracts()
|
||||||
|
|
||||||
if num > lastLetterNum {
|
if num > lastLetterNum {
|
||||||
return nil, fmt.Errorf("amount of alphabet contracts overflows glagolitsa %d > %d", num, lastLetterNum)
|
return nil, fmt.Errorf("amount of alphabet contracts overflows glagolitsa %d > %d", num, lastLetterNum)
|
||||||
|
@ -117,7 +117,7 @@ func parseAlphabetContracts(cfg *viper.Viper, morph *client.Client) (alphabetCon
|
||||||
return alpha, nil
|
return alpha, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseContract(cfg *viper.Viper, morph *client.Client, cfgName, nnsName string) (res util.Uint160, err error) {
|
func parseContract(cfg *viper.Viper, morph nnsResolver, cfgName, nnsName string) (res util.Uint160, err error) {
|
||||||
contractStr := cfg.GetString(cfgName)
|
contractStr := cfg.GetString(cfgName)
|
||||||
if len(contractStr) == 0 {
|
if len(contractStr) == 0 {
|
||||||
return morph.NNSContractAddress(nnsName)
|
return morph.NNSContractAddress(nnsName)
|
||||||
|
@ -125,3 +125,7 @@ func parseContract(cfg *viper.Viper, morph *client.Client, cfgName, nnsName stri
|
||||||
|
|
||||||
return util.Uint160DecodeStringLE(contractStr)
|
return util.Uint160DecodeStringLE(contractStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type nnsResolver interface {
|
||||||
|
NNSContractAddress(name string) (sh util.Uint160, err error)
|
||||||
|
}
|
||||||
|
|
222
pkg/innerring/contracts_test.go
Normal file
222
pkg/innerring/contracts_test.go
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
package innerring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseContractsSuccess(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
file := strings.NewReader(`
|
||||||
|
contracts:
|
||||||
|
frostfs: ee3dee6d05dc79c24a5b8f6985e10d68b7cacc62
|
||||||
|
processing: 597f5894867113a41e192801709c02497f611de8
|
||||||
|
audit: 219e37aed2180b87e7fe945dbf97d67125e8d73f
|
||||||
|
balance: d2aa48d14b17b11bc4c68205027884a96706dd16
|
||||||
|
container: ed4a7a66fe3f9bfe50f214b49be8f215a3c886b6
|
||||||
|
frostfsid: 9f5866decbc751a099e74c7c7bc89f609201755a
|
||||||
|
netmap: 83c600c81d47a1b1b7cf58eb49ae7ee7240dc742
|
||||||
|
proxy: abc8794bb40a21f2db5f21ae62741eb46c8cad1c
|
||||||
|
alphabet:
|
||||||
|
amount: 2
|
||||||
|
az: c1d211fceeb4b1dc76b8e4054d11fdf887e418ea
|
||||||
|
buky: e2ba789320899658b100f331bdebb74474757920
|
||||||
|
`)
|
||||||
|
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
err := v.ReadConfig(file)
|
||||||
|
require.NoError(t, err, "read config file failed")
|
||||||
|
|
||||||
|
t.Run("all enabled", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c, err := parseContracts(v, nil, false, false, false)
|
||||||
|
require.NoError(t, err, "failed to parse contracts")
|
||||||
|
|
||||||
|
frostfsExp, _ := util.Uint160DecodeStringLE("ee3dee6d05dc79c24a5b8f6985e10d68b7cacc62")
|
||||||
|
require.Equal(t, frostfsExp, c.frostfs, "invalid frostfs")
|
||||||
|
|
||||||
|
processingExp, _ := util.Uint160DecodeStringLE("597f5894867113a41e192801709c02497f611de8")
|
||||||
|
require.Equal(t, processingExp, c.processing, "invalid processing")
|
||||||
|
|
||||||
|
auditExp, _ := util.Uint160DecodeStringLE("219e37aed2180b87e7fe945dbf97d67125e8d73f")
|
||||||
|
require.Equal(t, auditExp, c.audit, "invalid audit")
|
||||||
|
|
||||||
|
balanceExp, _ := util.Uint160DecodeStringLE("d2aa48d14b17b11bc4c68205027884a96706dd16")
|
||||||
|
require.Equal(t, balanceExp, c.balance, "invalid balance")
|
||||||
|
|
||||||
|
containerExp, _ := util.Uint160DecodeStringLE("ed4a7a66fe3f9bfe50f214b49be8f215a3c886b6")
|
||||||
|
require.Equal(t, containerExp, c.container, "invalid container")
|
||||||
|
|
||||||
|
frostfsIDExp, _ := util.Uint160DecodeStringLE("9f5866decbc751a099e74c7c7bc89f609201755a")
|
||||||
|
require.Equal(t, frostfsIDExp, c.frostfsID, "invalid frostfsID")
|
||||||
|
|
||||||
|
netmapIDExp, _ := util.Uint160DecodeStringLE("83c600c81d47a1b1b7cf58eb49ae7ee7240dc742")
|
||||||
|
require.Equal(t, netmapIDExp, c.netmap, "invalid netmap")
|
||||||
|
|
||||||
|
proxyExp, _ := util.Uint160DecodeStringLE("abc8794bb40a21f2db5f21ae62741eb46c8cad1c")
|
||||||
|
require.Equal(t, proxyExp, c.proxy, "invalid proxy")
|
||||||
|
|
||||||
|
require.Equal(t, 2, len(c.alphabet), "invalid alphabet contracts length")
|
||||||
|
|
||||||
|
azExp, _ := util.Uint160DecodeStringLE("c1d211fceeb4b1dc76b8e4054d11fdf887e418ea")
|
||||||
|
require.Equal(t, azExp, c.alphabet[az], "invalid az")
|
||||||
|
|
||||||
|
bukyExp, _ := util.Uint160DecodeStringLE("e2ba789320899658b100f331bdebb74474757920")
|
||||||
|
require.Equal(t, bukyExp, c.alphabet[buky], "invalid buky")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("all disabled", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c, err := parseContracts(v, nil, true, true, true)
|
||||||
|
require.NoError(t, err, "failed to parse contracts")
|
||||||
|
|
||||||
|
require.Equal(t, util.Uint160{}, c.frostfs, "invalid frostfs")
|
||||||
|
|
||||||
|
require.Equal(t, util.Uint160{}, c.processing, "invalid processing")
|
||||||
|
|
||||||
|
auditExp, _ := util.Uint160DecodeStringLE("219e37aed2180b87e7fe945dbf97d67125e8d73f")
|
||||||
|
require.Equal(t, auditExp, c.audit, "invalid audit")
|
||||||
|
|
||||||
|
balanceExp, _ := util.Uint160DecodeStringLE("d2aa48d14b17b11bc4c68205027884a96706dd16")
|
||||||
|
require.Equal(t, balanceExp, c.balance, "invalid balance")
|
||||||
|
|
||||||
|
containerExp, _ := util.Uint160DecodeStringLE("ed4a7a66fe3f9bfe50f214b49be8f215a3c886b6")
|
||||||
|
require.Equal(t, containerExp, c.container, "invalid container")
|
||||||
|
|
||||||
|
frostfsIDExp, _ := util.Uint160DecodeStringLE("9f5866decbc751a099e74c7c7bc89f609201755a")
|
||||||
|
require.Equal(t, frostfsIDExp, c.frostfsID, "invalid frostfsID")
|
||||||
|
|
||||||
|
netmapIDExp, _ := util.Uint160DecodeStringLE("83c600c81d47a1b1b7cf58eb49ae7ee7240dc742")
|
||||||
|
require.Equal(t, netmapIDExp, c.netmap, "invalid netmap")
|
||||||
|
|
||||||
|
require.Equal(t, util.Uint160{}, c.proxy, "invalid proxy")
|
||||||
|
|
||||||
|
require.Equal(t, 2, len(c.alphabet), "invalid alphabet contracts length")
|
||||||
|
|
||||||
|
azExp, _ := util.Uint160DecodeStringLE("c1d211fceeb4b1dc76b8e4054d11fdf887e418ea")
|
||||||
|
require.Equal(t, azExp, c.alphabet[az], "invalid az")
|
||||||
|
|
||||||
|
bukyExp, _ := util.Uint160DecodeStringLE("e2ba789320899658b100f331bdebb74474757920")
|
||||||
|
require.Equal(t, bukyExp, c.alphabet[buky], "invalid buky")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("main notary & side notary disabled", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
c, err := parseContracts(v, nil, false, true, true)
|
||||||
|
require.NoError(t, err, "failed to parse contracts")
|
||||||
|
|
||||||
|
frostfsExp, _ := util.Uint160DecodeStringLE("ee3dee6d05dc79c24a5b8f6985e10d68b7cacc62")
|
||||||
|
require.Equal(t, frostfsExp, c.frostfs, "invalid frostfs")
|
||||||
|
|
||||||
|
require.Equal(t, util.Uint160{}, c.processing, "invalid processing")
|
||||||
|
|
||||||
|
auditExp, _ := util.Uint160DecodeStringLE("219e37aed2180b87e7fe945dbf97d67125e8d73f")
|
||||||
|
require.Equal(t, auditExp, c.audit, "invalid audit")
|
||||||
|
|
||||||
|
balanceExp, _ := util.Uint160DecodeStringLE("d2aa48d14b17b11bc4c68205027884a96706dd16")
|
||||||
|
require.Equal(t, balanceExp, c.balance, "invalid balance")
|
||||||
|
|
||||||
|
containerExp, _ := util.Uint160DecodeStringLE("ed4a7a66fe3f9bfe50f214b49be8f215a3c886b6")
|
||||||
|
require.Equal(t, containerExp, c.container, "invalid container")
|
||||||
|
|
||||||
|
frostfsIDExp, _ := util.Uint160DecodeStringLE("9f5866decbc751a099e74c7c7bc89f609201755a")
|
||||||
|
require.Equal(t, frostfsIDExp, c.frostfsID, "invalid frostfsID")
|
||||||
|
|
||||||
|
netmapIDExp, _ := util.Uint160DecodeStringLE("83c600c81d47a1b1b7cf58eb49ae7ee7240dc742")
|
||||||
|
require.Equal(t, netmapIDExp, c.netmap, "invalid netmap")
|
||||||
|
|
||||||
|
require.Equal(t, util.Uint160{}, c.proxy, "invalid proxy")
|
||||||
|
|
||||||
|
require.Equal(t, 2, len(c.alphabet), "invalid alphabet contracts length")
|
||||||
|
|
||||||
|
azExp, _ := util.Uint160DecodeStringLE("c1d211fceeb4b1dc76b8e4054d11fdf887e418ea")
|
||||||
|
require.Equal(t, azExp, c.alphabet[az], "invalid az")
|
||||||
|
|
||||||
|
bukyExp, _ := util.Uint160DecodeStringLE("e2ba789320899658b100f331bdebb74474757920")
|
||||||
|
require.Equal(t, bukyExp, c.alphabet[buky], "invalid buky")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseContractsInvalid(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
t.Run("invalid audit contract", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
file := strings.NewReader(`
|
||||||
|
contracts:
|
||||||
|
frostfs: invalid_data
|
||||||
|
processing: 597f5894867113a41e192801709c02497f611de8
|
||||||
|
audit: 219e37aed2180b87e7fe945dbf97d67125e8d73f
|
||||||
|
balance: d2aa48d14b17b11bc4c68205027884a96706dd16
|
||||||
|
container: ed4a7a66fe3f9bfe50f214b49be8f215a3c886b6
|
||||||
|
frostfsid: 9f5866decbc751a099e74c7c7bc89f609201755a
|
||||||
|
netmap: 83c600c81d47a1b1b7cf58eb49ae7ee7240dc742
|
||||||
|
proxy: abc8794bb40a21f2db5f21ae62741eb46c8cad1c
|
||||||
|
alphabet:
|
||||||
|
amount: 2
|
||||||
|
az: c1d211fceeb4b1dc76b8e4054d11fdf887e418ea
|
||||||
|
buky: e2ba789320899658b100f331bdebb74474757920
|
||||||
|
`)
|
||||||
|
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
err := v.ReadConfig(file)
|
||||||
|
require.NoError(t, err, "read config file failed")
|
||||||
|
|
||||||
|
_, err = parseContracts(v, nil, false, false, false)
|
||||||
|
require.Error(t, err, "unexpected success")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid alphabet count", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
file := strings.NewReader(`
|
||||||
|
contracts:
|
||||||
|
frostfs: ee3dee6d05dc79c24a5b8f6985e10d68b7cacc62
|
||||||
|
processing: 597f5894867113a41e192801709c02497f611de8
|
||||||
|
audit: 219e37aed2180b87e7fe945dbf97d67125e8d73f
|
||||||
|
balance: d2aa48d14b17b11bc4c68205027884a96706dd16
|
||||||
|
container: ed4a7a66fe3f9bfe50f214b49be8f215a3c886b6
|
||||||
|
frostfsid: 9f5866decbc751a099e74c7c7bc89f609201755a
|
||||||
|
netmap: 83c600c81d47a1b1b7cf58eb49ae7ee7240dc742
|
||||||
|
proxy: abc8794bb40a21f2db5f21ae62741eb46c8cad1c
|
||||||
|
alphabet:
|
||||||
|
amount: 3
|
||||||
|
az: c1d211fceeb4b1dc76b8e4054d11fdf887e418ea
|
||||||
|
buky: e2ba789320899658b100f331bdebb74474757920
|
||||||
|
`)
|
||||||
|
|
||||||
|
v := viper.New()
|
||||||
|
v.SetConfigType("yaml")
|
||||||
|
err := v.ReadConfig(file)
|
||||||
|
require.NoError(t, err, "read config file failed")
|
||||||
|
|
||||||
|
azExp, _ := util.Uint160DecodeStringLE("c1d211fceeb4b1dc76b8e4054d11fdf887e418ea")
|
||||||
|
bukyExp, _ := util.Uint160DecodeStringLE("e2ba789320899658b100f331bdebb74474757920")
|
||||||
|
|
||||||
|
morph := &testParserMorph{
|
||||||
|
values: map[string]util.Uint160{
|
||||||
|
"az": azExp,
|
||||||
|
"buky": bukyExp,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = parseContracts(v, morph, false, false, false)
|
||||||
|
require.ErrorContains(t, err, "could not read all contracts: required 3, read 2", "unexpected success")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type testParserMorph struct {
|
||||||
|
values map[string]util.Uint160
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *testParserMorph) NNSContractAddress(name string) (sh util.Uint160, err error) {
|
||||||
|
if value, found := m.values[name]; found {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
return util.Uint160{}, client.ErrNNSRecordNotFound
|
||||||
|
}
|
225
pkg/innerring/indexer_test.go
Normal file
225
pkg/innerring/indexer_test.go
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
package innerring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIndexerReturnsIndexes(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{
|
||||||
|
"03ff65b6ae79134a4dce9d0d39d3851e9bab4ee97abf86e81e1c5bbc50cd2826ae",
|
||||||
|
"022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131",
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "convert string to commitee public keys failed")
|
||||||
|
cf := &testCommiteeFetcher{
|
||||||
|
keys: commiteeKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
irKeys, err := keys.NewPublicKeysFromStrings([]string{
|
||||||
|
"038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35",
|
||||||
|
"02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3",
|
||||||
|
"022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131",
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "convert string to IR public keys failed")
|
||||||
|
irf := &testIRFetcher{
|
||||||
|
keys: irKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("success", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
key := irKeys[2]
|
||||||
|
|
||||||
|
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
|
||||||
|
|
||||||
|
idx, err := indexer.AlphabetIndex()
|
||||||
|
require.NoError(t, err, "failed to get alphabet index")
|
||||||
|
require.Equal(t, int32(1), idx, "invalid alphabet index")
|
||||||
|
|
||||||
|
idx, err = indexer.InnerRingIndex()
|
||||||
|
require.NoError(t, err, "failed to get IR index")
|
||||||
|
require.Equal(t, int32(2), idx, "invalid IR index")
|
||||||
|
|
||||||
|
size, err := indexer.InnerRingSize()
|
||||||
|
require.NoError(t, err, "failed to get IR size")
|
||||||
|
require.Equal(t, int32(3), size, "invalid IR size")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("not found alphabet", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
key := irKeys[0]
|
||||||
|
|
||||||
|
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
|
||||||
|
|
||||||
|
idx, err := indexer.AlphabetIndex()
|
||||||
|
require.NoError(t, err, "failed to get alphabet index")
|
||||||
|
require.Equal(t, int32(-1), idx, "invalid alphabet index")
|
||||||
|
|
||||||
|
idx, err = indexer.InnerRingIndex()
|
||||||
|
require.NoError(t, err, "failed to get IR index")
|
||||||
|
require.Equal(t, int32(0), idx, "invalid IR index")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("not found IR", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
key := commiteeKeys[0]
|
||||||
|
|
||||||
|
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
|
||||||
|
|
||||||
|
idx, err := indexer.AlphabetIndex()
|
||||||
|
require.NoError(t, err, "failed to get alphabet index")
|
||||||
|
require.Equal(t, int32(0), idx, "invalid alphabet index")
|
||||||
|
|
||||||
|
idx, err = indexer.InnerRingIndex()
|
||||||
|
require.NoError(t, err, "failed to get IR index")
|
||||||
|
require.Equal(t, int32(-1), idx, "invalid IR index")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIndexerCachesIndexes(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{})
|
||||||
|
require.NoError(t, err, "convert string to commitee public keys failed")
|
||||||
|
cf := &testCommiteeFetcher{
|
||||||
|
keys: commiteeKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
irKeys, err := keys.NewPublicKeysFromStrings([]string{})
|
||||||
|
require.NoError(t, err, "convert string to IR public keys failed")
|
||||||
|
irf := &testIRFetcher{
|
||||||
|
keys: irKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := keys.NewPublicKeyFromString("022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131")
|
||||||
|
require.NoError(t, err, "convert string to public key failed")
|
||||||
|
|
||||||
|
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
|
||||||
|
|
||||||
|
idx, err := indexer.AlphabetIndex()
|
||||||
|
require.NoError(t, err, "failed to get alphabet index")
|
||||||
|
require.Equal(t, int32(-1), idx, "invalid alphabet index")
|
||||||
|
|
||||||
|
idx, err = indexer.InnerRingIndex()
|
||||||
|
require.NoError(t, err, "failed to get IR index")
|
||||||
|
require.Equal(t, int32(-1), idx, "invalid IR index")
|
||||||
|
|
||||||
|
size, err := indexer.InnerRingSize()
|
||||||
|
require.NoError(t, err, "failed to get IR size")
|
||||||
|
require.Equal(t, int32(0), size, "invalid IR size")
|
||||||
|
|
||||||
|
require.Equal(t, int32(1), cf.calls.Load(), "invalid commitee calls count")
|
||||||
|
require.Equal(t, int32(1), irf.calls.Load(), "invalid IR calls count")
|
||||||
|
|
||||||
|
idx, err = indexer.AlphabetIndex()
|
||||||
|
require.NoError(t, err, "failed to get alphabet index")
|
||||||
|
require.Equal(t, int32(-1), idx, "invalid alphabet index")
|
||||||
|
|
||||||
|
idx, err = indexer.InnerRingIndex()
|
||||||
|
require.NoError(t, err, "failed to get IR index")
|
||||||
|
require.Equal(t, int32(-1), idx, "invalid IR index")
|
||||||
|
|
||||||
|
size, err = indexer.InnerRingSize()
|
||||||
|
require.NoError(t, err, "failed to get IR size")
|
||||||
|
require.Equal(t, int32(0), size, "invalid IR size")
|
||||||
|
|
||||||
|
require.Equal(t, int32(1), cf.calls.Load(), "invalid commitee calls count")
|
||||||
|
require.Equal(t, int32(1), irf.calls.Load(), "invalid IR calls count")
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
idx, err = indexer.AlphabetIndex()
|
||||||
|
require.NoError(t, err, "failed to get alphabet index")
|
||||||
|
require.Equal(t, int32(-1), idx, "invalid alphabet index")
|
||||||
|
|
||||||
|
idx, err = indexer.InnerRingIndex()
|
||||||
|
require.NoError(t, err, "failed to get IR index")
|
||||||
|
require.Equal(t, int32(-1), idx, "invalid IR index")
|
||||||
|
|
||||||
|
size, err = indexer.InnerRingSize()
|
||||||
|
require.NoError(t, err, "failed to get IR size")
|
||||||
|
require.Equal(t, int32(0), size, "invalid IR size")
|
||||||
|
|
||||||
|
require.Equal(t, int32(2), cf.calls.Load(), "invalid commitee calls count")
|
||||||
|
require.Equal(t, int32(2), irf.calls.Load(), "invalid IR calls count")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIndexerThrowsErrors(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
cf := &testCommiteeFetcher{
|
||||||
|
err: fmt.Errorf("test commitee error"),
|
||||||
|
}
|
||||||
|
|
||||||
|
irKeys, err := keys.NewPublicKeysFromStrings([]string{})
|
||||||
|
require.NoError(t, err, "convert string to IR public keys failed")
|
||||||
|
irf := &testIRFetcher{
|
||||||
|
keys: irKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := keys.NewPublicKeyFromString("022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131")
|
||||||
|
require.NoError(t, err, "convert string to public key failed")
|
||||||
|
|
||||||
|
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
|
||||||
|
|
||||||
|
idx, err := indexer.AlphabetIndex()
|
||||||
|
require.ErrorContains(t, err, "test commitee error", "error from commitee not throwed")
|
||||||
|
require.Equal(t, int32(0), idx, "invalid alphabet index")
|
||||||
|
|
||||||
|
idx, err = indexer.InnerRingIndex()
|
||||||
|
require.ErrorContains(t, err, "test commitee error", "error from IR not throwed")
|
||||||
|
require.Equal(t, int32(0), idx, "invalid IR index")
|
||||||
|
|
||||||
|
size, err := indexer.InnerRingSize()
|
||||||
|
require.ErrorContains(t, err, "test commitee error", "error from IR not throwed")
|
||||||
|
require.Equal(t, int32(0), size, "invalid IR size")
|
||||||
|
|
||||||
|
commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{})
|
||||||
|
require.NoError(t, err, "convert string to commitee public keys failed")
|
||||||
|
cf = &testCommiteeFetcher{
|
||||||
|
keys: commiteeKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
irf = &testIRFetcher{
|
||||||
|
err: fmt.Errorf("test IR error"),
|
||||||
|
}
|
||||||
|
|
||||||
|
indexer = newInnerRingIndexer(cf, irf, key, time.Second)
|
||||||
|
|
||||||
|
idx, err = indexer.AlphabetIndex()
|
||||||
|
require.ErrorContains(t, err, "test IR error", "error from commitee not throwed")
|
||||||
|
require.Equal(t, int32(0), idx, "invalid alphabet index")
|
||||||
|
|
||||||
|
idx, err = indexer.InnerRingIndex()
|
||||||
|
require.ErrorContains(t, err, "test IR error", "error from IR not throwed")
|
||||||
|
require.Equal(t, int32(0), idx, "invalid IR index")
|
||||||
|
|
||||||
|
size, err = indexer.InnerRingSize()
|
||||||
|
require.ErrorContains(t, err, "test IR error", "error from IR not throwed")
|
||||||
|
require.Equal(t, int32(0), size, "invalid IR size")
|
||||||
|
}
|
||||||
|
|
||||||
|
type testCommiteeFetcher struct {
|
||||||
|
keys keys.PublicKeys
|
||||||
|
err error
|
||||||
|
calls atomic.Int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *testCommiteeFetcher) Committee() (keys.PublicKeys, error) {
|
||||||
|
f.calls.Inc()
|
||||||
|
return f.keys, f.err
|
||||||
|
}
|
||||||
|
|
||||||
|
type testIRFetcher struct {
|
||||||
|
keys keys.PublicKeys
|
||||||
|
err error
|
||||||
|
calls atomic.Int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *testIRFetcher) InnerRingKeys() (keys.PublicKeys, error) {
|
||||||
|
f.calls.Inc()
|
||||||
|
return f.keys, f.err
|
||||||
|
}
|
|
@ -63,7 +63,7 @@ func (s *Server) initNetmapProcessor(cfg *viper.Viper,
|
||||||
s.netmapProcessor, err = netmap.New(&netmap.Params{
|
s.netmapProcessor, err = netmap.New(&netmap.Params{
|
||||||
Log: s.log,
|
Log: s.log,
|
||||||
PoolSize: cfg.GetInt("workers.netmap"),
|
PoolSize: cfg.GetInt("workers.netmap"),
|
||||||
NetmapClient: s.netmapClient,
|
NetmapClient: netmap.NewNetmapClient(s.netmapClient),
|
||||||
EpochTimer: s,
|
EpochTimer: s,
|
||||||
EpochState: s,
|
EpochState: s,
|
||||||
AlphabetState: s,
|
AlphabetState: s,
|
||||||
|
|
282
pkg/innerring/processors/alphabet/handlers_test.go
Normal file
282
pkg/innerring/processors/alphabet/handlers_test.go
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
package alphabet_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/alphabet"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/timers"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProcessorEmitsGasToNetmapAndAlphabet(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
var emission uint64 = 100_000
|
||||||
|
var index int = 5
|
||||||
|
var parsedWallets []util.Uint160 = []util.Uint160{{20}, {25}}
|
||||||
|
|
||||||
|
alphabetContracts := innerring.NewAlphabetContracts()
|
||||||
|
for i := 0; i <= index; i++ {
|
||||||
|
alphabetContracts[innerring.GlagoliticLetter(i)] = util.Uint160{uint8(i)}
|
||||||
|
}
|
||||||
|
|
||||||
|
morphClient := &testMorphClient{}
|
||||||
|
|
||||||
|
var node1 netmap.NodeInfo
|
||||||
|
key1, err := keys.NewPublicKeyFromString("038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35")
|
||||||
|
require.NoError(t, err, "failed to parse key1")
|
||||||
|
node1.SetPublicKey(key1.Bytes())
|
||||||
|
|
||||||
|
var node2 netmap.NodeInfo
|
||||||
|
key2, err := keys.NewPublicKeyFromString("02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3")
|
||||||
|
require.NoError(t, err, "failed to parse key2")
|
||||||
|
node2.SetPublicKey(key2.Bytes())
|
||||||
|
|
||||||
|
nodes := []netmap.NodeInfo{node1, node2}
|
||||||
|
|
||||||
|
network := &netmap.NetMap{}
|
||||||
|
network.SetNodes(nodes)
|
||||||
|
|
||||||
|
netmapClient := &testNetmapClient{
|
||||||
|
netmap: network,
|
||||||
|
}
|
||||||
|
|
||||||
|
params := &alphabet.Params{
|
||||||
|
ParsedWallets: parsedWallets,
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 2,
|
||||||
|
StorageEmission: emission,
|
||||||
|
IRList: &testIndexer{index: index},
|
||||||
|
AlphabetContracts: alphabetContracts,
|
||||||
|
MorphClient: morphClient,
|
||||||
|
NetmapClient: netmapClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
processor, err := alphabet.New(params)
|
||||||
|
require.NoError(t, err, "failed to create processor instance")
|
||||||
|
|
||||||
|
processor.HandleGasEmission(timers.NewAlphabetEmitTick{})
|
||||||
|
|
||||||
|
processor.WaitPoolRunning()
|
||||||
|
|
||||||
|
require.EqualValues(t, []invokedMethod{
|
||||||
|
{
|
||||||
|
contract: alphabetContracts[innerring.GlagoliticLetter(index)],
|
||||||
|
fee: 0,
|
||||||
|
method: "emit",
|
||||||
|
},
|
||||||
|
}, morphClient.invokedMethods, "invalid invoked morph methods")
|
||||||
|
|
||||||
|
require.EqualValues(t, []transferGas{
|
||||||
|
{
|
||||||
|
receiver: key1.GetScriptHash(),
|
||||||
|
amount: fixedn.Fixed8(25_000),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
receiver: key2.GetScriptHash(),
|
||||||
|
amount: fixedn.Fixed8(25_000),
|
||||||
|
},
|
||||||
|
}, morphClient.transferedGas, "invalid transfered Gas")
|
||||||
|
|
||||||
|
require.EqualValues(t, []batchTransferGas{
|
||||||
|
{
|
||||||
|
receivers: parsedWallets,
|
||||||
|
amount: fixedn.Fixed8(25_000),
|
||||||
|
},
|
||||||
|
}, morphClient.batchTransferedGas, "invalid batch transfered Gas")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcessorEmitsGasToNetmapIfNoParsedWallets(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
var emission uint64 = 100_000
|
||||||
|
var index int = 5
|
||||||
|
var parsedWallets []util.Uint160 = []util.Uint160{}
|
||||||
|
|
||||||
|
alphabetContracts := innerring.NewAlphabetContracts()
|
||||||
|
for i := 0; i <= index; i++ {
|
||||||
|
alphabetContracts[innerring.GlagoliticLetter(i)] = util.Uint160{uint8(i)}
|
||||||
|
}
|
||||||
|
|
||||||
|
morphClient := &testMorphClient{}
|
||||||
|
|
||||||
|
var node1 netmap.NodeInfo
|
||||||
|
key1, err := keys.NewPublicKeyFromString("038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35")
|
||||||
|
require.NoError(t, err, "failed to parse key1")
|
||||||
|
node1.SetPublicKey(key1.Bytes())
|
||||||
|
|
||||||
|
var node2 netmap.NodeInfo
|
||||||
|
key2, err := keys.NewPublicKeyFromString("02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3")
|
||||||
|
require.NoError(t, err, "failed to parse key2")
|
||||||
|
node2.SetPublicKey(key2.Bytes())
|
||||||
|
|
||||||
|
nodes := []netmap.NodeInfo{node1, node2}
|
||||||
|
|
||||||
|
network := &netmap.NetMap{}
|
||||||
|
network.SetNodes(nodes)
|
||||||
|
|
||||||
|
netmapClient := &testNetmapClient{
|
||||||
|
netmap: network,
|
||||||
|
}
|
||||||
|
|
||||||
|
params := &alphabet.Params{
|
||||||
|
ParsedWallets: parsedWallets,
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 2,
|
||||||
|
StorageEmission: emission,
|
||||||
|
IRList: &testIndexer{index: index},
|
||||||
|
AlphabetContracts: alphabetContracts,
|
||||||
|
MorphClient: morphClient,
|
||||||
|
NetmapClient: netmapClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
processor, err := alphabet.New(params)
|
||||||
|
require.NoError(t, err, "failed to create processor instance")
|
||||||
|
|
||||||
|
processor.HandleGasEmission(timers.NewAlphabetEmitTick{})
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
require.EqualValues(t, []invokedMethod{
|
||||||
|
{
|
||||||
|
contract: alphabetContracts[innerring.GlagoliticLetter(index)],
|
||||||
|
fee: 0,
|
||||||
|
method: "emit",
|
||||||
|
},
|
||||||
|
}, morphClient.invokedMethods, "invalid invoked morph methods")
|
||||||
|
|
||||||
|
require.EqualValues(t, []transferGas{
|
||||||
|
{
|
||||||
|
receiver: key1.GetScriptHash(),
|
||||||
|
amount: fixedn.Fixed8(50_000),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
receiver: key2.GetScriptHash(),
|
||||||
|
amount: fixedn.Fixed8(50_000),
|
||||||
|
},
|
||||||
|
}, morphClient.transferedGas, "invalid transfered Gas")
|
||||||
|
|
||||||
|
require.Equal(t, 0, len(morphClient.batchTransferedGas), "invalid batch transfered Gas")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcessorDoesntEmitGasIfNoNetmapOrParsedWallets(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
var emission uint64 = 100_000
|
||||||
|
var index int = 5
|
||||||
|
var parsedWallets []util.Uint160 = []util.Uint160{}
|
||||||
|
|
||||||
|
alphabetContracts := innerring.NewAlphabetContracts()
|
||||||
|
for i := 0; i <= index; i++ {
|
||||||
|
alphabetContracts[innerring.GlagoliticLetter(i)] = util.Uint160{uint8(i)}
|
||||||
|
}
|
||||||
|
|
||||||
|
morphClient := &testMorphClient{}
|
||||||
|
|
||||||
|
nodes := []netmap.NodeInfo{}
|
||||||
|
network := &netmap.NetMap{}
|
||||||
|
network.SetNodes(nodes)
|
||||||
|
|
||||||
|
netmapClient := &testNetmapClient{
|
||||||
|
netmap: network,
|
||||||
|
}
|
||||||
|
|
||||||
|
params := &alphabet.Params{
|
||||||
|
ParsedWallets: parsedWallets,
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 2,
|
||||||
|
StorageEmission: emission,
|
||||||
|
IRList: &testIndexer{index: index},
|
||||||
|
AlphabetContracts: alphabetContracts,
|
||||||
|
MorphClient: morphClient,
|
||||||
|
NetmapClient: netmapClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
processor, err := alphabet.New(params)
|
||||||
|
require.NoError(t, err, "failed to create processor instance")
|
||||||
|
|
||||||
|
processor.HandleGasEmission(timers.NewAlphabetEmitTick{})
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
require.EqualValues(t, []invokedMethod{
|
||||||
|
{
|
||||||
|
contract: alphabetContracts[innerring.GlagoliticLetter(index)],
|
||||||
|
fee: 0,
|
||||||
|
method: "emit",
|
||||||
|
},
|
||||||
|
}, morphClient.invokedMethods, "invalid invoked morph methods")
|
||||||
|
|
||||||
|
require.Equal(t, 0, len(morphClient.transferedGas), "invalid transfered Gas")
|
||||||
|
|
||||||
|
require.Equal(t, 0, len(morphClient.batchTransferedGas), "invalid batch transfered Gas")
|
||||||
|
}
|
||||||
|
|
||||||
|
type testIndexer struct {
|
||||||
|
index int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *testIndexer) AlphabetIndex() int {
|
||||||
|
return i.index
|
||||||
|
}
|
||||||
|
|
||||||
|
type invokedMethod struct {
|
||||||
|
contract util.Uint160
|
||||||
|
fee fixedn.Fixed8
|
||||||
|
method string
|
||||||
|
args []any
|
||||||
|
}
|
||||||
|
|
||||||
|
type transferGas struct {
|
||||||
|
receiver util.Uint160
|
||||||
|
amount fixedn.Fixed8
|
||||||
|
}
|
||||||
|
|
||||||
|
type batchTransferGas struct {
|
||||||
|
receivers []util.Uint160
|
||||||
|
amount fixedn.Fixed8
|
||||||
|
}
|
||||||
|
|
||||||
|
type testMorphClient struct {
|
||||||
|
invokedMethods []invokedMethod
|
||||||
|
transferedGas []transferGas
|
||||||
|
batchTransferedGas []batchTransferGas
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testMorphClient) Invoke(contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) error {
|
||||||
|
c.invokedMethods = append(c.invokedMethods,
|
||||||
|
invokedMethod{
|
||||||
|
contract: contract,
|
||||||
|
fee: fee,
|
||||||
|
method: method,
|
||||||
|
args: args,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *testMorphClient) TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error {
|
||||||
|
c.transferedGas = append(c.transferedGas, transferGas{
|
||||||
|
receiver: receiver,
|
||||||
|
amount: amount,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testMorphClient) BatchTransferGas(receivers []util.Uint160, amount fixedn.Fixed8) error {
|
||||||
|
c.batchTransferedGas = append(c.batchTransferedGas, batchTransferGas{
|
||||||
|
receivers: receivers,
|
||||||
|
amount: amount,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testNetmapClient struct {
|
||||||
|
netmap *netmap.NetMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testNetmapClient) NetMap() (*netmap.NetMap, error) {
|
||||||
|
return c.netmap, nil
|
||||||
|
}
|
|
@ -3,12 +3,13 @@ package alphabet
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
|
||||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
@ -32,14 +33,24 @@ type (
|
||||||
GetByIndex(int) (util.Uint160, bool)
|
GetByIndex(int) (util.Uint160, bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netmapClient interface {
|
||||||
|
NetMap() (*netmap.NetMap, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
morphClient interface {
|
||||||
|
Invoke(contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) error
|
||||||
|
TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error
|
||||||
|
BatchTransferGas(receivers []util.Uint160, amount fixedn.Fixed8) error
|
||||||
|
}
|
||||||
|
|
||||||
// Processor of events produced for alphabet contracts in the sidechain.
|
// Processor of events produced for alphabet contracts in the sidechain.
|
||||||
Processor struct {
|
Processor struct {
|
||||||
parsedWallets []util.Uint160
|
parsedWallets []util.Uint160
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
pool *ants.Pool
|
pool *ants.Pool
|
||||||
alphabetContracts Contracts
|
alphabetContracts Contracts
|
||||||
netmapClient *nmClient.Client
|
netmapClient netmapClient
|
||||||
morphClient *client.Client
|
morphClient morphClient
|
||||||
irList Indexer
|
irList Indexer
|
||||||
storageEmission uint64
|
storageEmission uint64
|
||||||
}
|
}
|
||||||
|
@ -50,8 +61,8 @@ type (
|
||||||
Log *logger.Logger
|
Log *logger.Logger
|
||||||
PoolSize int
|
PoolSize int
|
||||||
AlphabetContracts Contracts
|
AlphabetContracts Contracts
|
||||||
NetmapClient *nmClient.Client
|
NetmapClient netmapClient
|
||||||
MorphClient *client.Client
|
MorphClient morphClient
|
||||||
IRList Indexer
|
IRList Indexer
|
||||||
StorageEmission uint64
|
StorageEmission uint64
|
||||||
}
|
}
|
||||||
|
@ -106,3 +117,11 @@ func (ap *Processor) ListenerNotaryParsers() []event.NotaryParserInfo {
|
||||||
func (ap *Processor) ListenerNotaryHandlers() []event.NotaryHandlerInfo {
|
func (ap *Processor) ListenerNotaryHandlers() []event.NotaryHandlerInfo {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WaitPoolRunning waits while pool has running tasks
|
||||||
|
// For use in test only.
|
||||||
|
func (ap *Processor) WaitPoolRunning() {
|
||||||
|
for ap.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
90
pkg/innerring/processors/balance/handlers_test.go
Normal file
90
pkg/innerring/processors/balance/handlers_test.go
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
package balance
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
frostfscontract "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfs"
|
||||||
|
balanceEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/balance"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestProcessorCallsFrostFSContractForLockEvent(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
as := &testAlphabetState{
|
||||||
|
isAlphabet: true,
|
||||||
|
}
|
||||||
|
conv := &testPresicionConverter{}
|
||||||
|
cl := &testFrostFSContractClient{}
|
||||||
|
bsc := util.Uint160{100}
|
||||||
|
|
||||||
|
processor, err := New(&Params{
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 2,
|
||||||
|
FrostFSClient: cl,
|
||||||
|
BalanceSC: bsc,
|
||||||
|
AlphabetState: as,
|
||||||
|
Converter: conv,
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
processor.handleLock(balanceEvent.Lock{})
|
||||||
|
|
||||||
|
for processor.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, 1, cl.chequeCalls, "invalid Cheque calls")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcessorDoesntCallFrostFSContractIfNotAlphabet(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
as := &testAlphabetState{}
|
||||||
|
conv := &testPresicionConverter{}
|
||||||
|
cl := &testFrostFSContractClient{}
|
||||||
|
bsc := util.Uint160{100}
|
||||||
|
|
||||||
|
processor, err := New(&Params{
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 2,
|
||||||
|
FrostFSClient: cl,
|
||||||
|
BalanceSC: bsc,
|
||||||
|
AlphabetState: as,
|
||||||
|
Converter: conv,
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
processor.handleLock(balanceEvent.Lock{})
|
||||||
|
|
||||||
|
for processor.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, 0, cl.chequeCalls, "invalid Cheque calls")
|
||||||
|
}
|
||||||
|
|
||||||
|
type testAlphabetState struct {
|
||||||
|
isAlphabet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testAlphabetState) IsAlphabet() bool {
|
||||||
|
return s.isAlphabet
|
||||||
|
}
|
||||||
|
|
||||||
|
type testPresicionConverter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testPresicionConverter) ToFixed8(v int64) int64 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
type testFrostFSContractClient struct {
|
||||||
|
chequeCalls int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testFrostFSContractClient) Cheque(p frostfscontract.ChequePrm) error {
|
||||||
|
c.chequeCalls++
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -25,11 +25,15 @@ type (
|
||||||
ToFixed8(int64) int64
|
ToFixed8(int64) int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FrostFSClient interface {
|
||||||
|
Cheque(p frostfscontract.ChequePrm) error
|
||||||
|
}
|
||||||
|
|
||||||
// Processor of events produced by balance contract in the morphchain.
|
// Processor of events produced by balance contract in the morphchain.
|
||||||
Processor struct {
|
Processor struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
pool *ants.Pool
|
pool *ants.Pool
|
||||||
frostfsClient *frostfscontract.Client
|
frostfsClient FrostFSClient
|
||||||
balanceSC util.Uint160
|
balanceSC util.Uint160
|
||||||
alphabetState AlphabetState
|
alphabetState AlphabetState
|
||||||
converter PrecisionConverter
|
converter PrecisionConverter
|
||||||
|
@ -39,7 +43,7 @@ type (
|
||||||
Params struct {
|
Params struct {
|
||||||
Log *logger.Logger
|
Log *logger.Logger
|
||||||
PoolSize int
|
PoolSize int
|
||||||
FrostFSClient *frostfscontract.Client
|
FrostFSClient FrostFSClient
|
||||||
BalanceSC util.Uint160
|
BalanceSC util.Uint160
|
||||||
AlphabetState AlphabetState
|
AlphabetState AlphabetState
|
||||||
Converter PrecisionConverter
|
Converter PrecisionConverter
|
||||||
|
|
|
@ -36,7 +36,7 @@ func (cp *Processor) handleDelete(ev event.Event) {
|
||||||
|
|
||||||
// send an event to the worker pool
|
// send an event to the worker pool
|
||||||
|
|
||||||
err := cp.pool.Submit(func() { cp.processContainerDelete(&del) })
|
err := cp.pool.Submit(func() { cp.processContainerDelete(del) })
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// there system can be moved into controlled degradation stage
|
// there system can be moved into controlled degradation stage
|
||||||
cp.log.Warn(logs.ContainerContainerProcessorWorkerPoolDrained,
|
cp.log.Warn(logs.ContainerContainerProcessorWorkerPoolDrained,
|
||||||
|
|
337
pkg/innerring/processors/container/handlers_test.go
Normal file
337
pkg/innerring/processors/container/handlers_test.go
Normal file
|
@ -0,0 +1,337 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"encoding/hex"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||||
|
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||||
|
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||||
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||||
|
containerSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
||||||
|
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPutEvent(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
nst := &testNetworkState{
|
||||||
|
homHashDisabled: true,
|
||||||
|
epoch: 100,
|
||||||
|
}
|
||||||
|
cc := &testContainerClient{
|
||||||
|
get: make(map[string]*containercore.Container),
|
||||||
|
}
|
||||||
|
|
||||||
|
proc, err := New(&Params{
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 2,
|
||||||
|
AlphabetState: &testAlphabetState{isAlphabet: true},
|
||||||
|
FrostFSIDClient: &testIDClient{},
|
||||||
|
NotaryDisabled: true,
|
||||||
|
NetworkState: nst,
|
||||||
|
ContainerClient: cc,
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
p, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
var usr user.ID
|
||||||
|
user.IDFromKey(&usr, (ecdsa.PublicKey)(*p.PublicKey()))
|
||||||
|
|
||||||
|
var pp netmap.PlacementPolicy
|
||||||
|
pp.AddReplicas(netmap.ReplicaDescriptor{})
|
||||||
|
|
||||||
|
var cnr containerSDK.Container
|
||||||
|
cnr.Init()
|
||||||
|
cnr.SetOwner(usr)
|
||||||
|
cnr.SetPlacementPolicy(pp)
|
||||||
|
cnr.SetBasicACL(acl.Private)
|
||||||
|
containerSDK.DisableHomomorphicHashing(&cnr)
|
||||||
|
|
||||||
|
event := &testPutEvent{
|
||||||
|
cnr: &cnr,
|
||||||
|
pk: p,
|
||||||
|
st: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handlePut(event)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedPut cntClient.PutPrm
|
||||||
|
expectedPut.SetContainer(cnr.Marshal())
|
||||||
|
expectedPut.SetKey(p.PublicKey().Bytes())
|
||||||
|
expectedPut.SetSignature(p.Sign(cnr.Marshal()))
|
||||||
|
expectedPut.SetZone("container")
|
||||||
|
|
||||||
|
require.EqualValues(t, []cntClient.PutPrm{expectedPut}, cc.put, "invalid put requests")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteEvent(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
nst := &testNetworkState{
|
||||||
|
homHashDisabled: true,
|
||||||
|
epoch: 100,
|
||||||
|
}
|
||||||
|
cc := &testContainerClient{
|
||||||
|
get: make(map[string]*containercore.Container),
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
idc := &testIDClient{
|
||||||
|
publicKeys: []*keys.PublicKey{
|
||||||
|
p.PublicKey(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc, err := New(&Params{
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 2,
|
||||||
|
AlphabetState: &testAlphabetState{isAlphabet: true},
|
||||||
|
FrostFSIDClient: idc,
|
||||||
|
NotaryDisabled: true,
|
||||||
|
NetworkState: nst,
|
||||||
|
ContainerClient: cc,
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
var usr user.ID
|
||||||
|
user.IDFromKey(&usr, (ecdsa.PublicKey)(*p.PublicKey()))
|
||||||
|
|
||||||
|
var pp netmap.PlacementPolicy
|
||||||
|
pp.AddReplicas(netmap.ReplicaDescriptor{})
|
||||||
|
|
||||||
|
var cnr containerSDK.Container
|
||||||
|
cnr.Init()
|
||||||
|
cnr.SetOwner(usr)
|
||||||
|
cnr.SetPlacementPolicy(pp)
|
||||||
|
cnr.SetBasicACL(acl.Private)
|
||||||
|
containerSDK.DisableHomomorphicHashing(&cnr)
|
||||||
|
|
||||||
|
var cid cid.ID
|
||||||
|
containerSDK.CalculateID(&cid, cnr)
|
||||||
|
cidBin := make([]byte, 32)
|
||||||
|
cid.Encode(cidBin)
|
||||||
|
|
||||||
|
ev := containerEvent.Delete{
|
||||||
|
ContainerIDValue: cidBin,
|
||||||
|
SignatureValue: p.Sign(cidBin),
|
||||||
|
}
|
||||||
|
|
||||||
|
var signature frostfscrypto.Signature
|
||||||
|
signer := frostfsecdsa.Signer(p.PrivateKey)
|
||||||
|
require.NoError(t, signature.Calculate(signer, ev.ContainerID()), "failed to calculate signature")
|
||||||
|
cc.get[hex.EncodeToString(ev.ContainerID())] = &containercore.Container{
|
||||||
|
Value: cnr,
|
||||||
|
Signature: signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleDelete(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedDelete cntClient.DeletePrm
|
||||||
|
expectedDelete.SetCID(ev.ContainerID())
|
||||||
|
expectedDelete.SetSignature(ev.Signature())
|
||||||
|
|
||||||
|
require.EqualValues(t, []cntClient.DeletePrm{expectedDelete}, cc.delete, "invalid delete requests")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetEACLEvent(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
nst := &testNetworkState{
|
||||||
|
homHashDisabled: true,
|
||||||
|
epoch: 100,
|
||||||
|
}
|
||||||
|
cc := &testContainerClient{
|
||||||
|
get: make(map[string]*containercore.Container),
|
||||||
|
}
|
||||||
|
|
||||||
|
proc, err := New(&Params{
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 2,
|
||||||
|
AlphabetState: &testAlphabetState{isAlphabet: true},
|
||||||
|
FrostFSIDClient: &testIDClient{},
|
||||||
|
NotaryDisabled: true,
|
||||||
|
NetworkState: nst,
|
||||||
|
ContainerClient: cc,
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
p, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var usr user.ID
|
||||||
|
user.IDFromKey(&usr, (ecdsa.PublicKey)(*p.PublicKey()))
|
||||||
|
|
||||||
|
var pp netmap.PlacementPolicy
|
||||||
|
pp.AddReplicas(netmap.ReplicaDescriptor{})
|
||||||
|
|
||||||
|
var cnr containerSDK.Container
|
||||||
|
cnr.Init()
|
||||||
|
cnr.SetOwner(usr)
|
||||||
|
cnr.SetPlacementPolicy(pp)
|
||||||
|
cnr.SetBasicACL(acl.PrivateExtended)
|
||||||
|
containerSDK.DisableHomomorphicHashing(&cnr)
|
||||||
|
|
||||||
|
var cid cid.ID
|
||||||
|
containerSDK.CalculateID(&cid, cnr)
|
||||||
|
cidBytes := make([]byte, 32)
|
||||||
|
cid.Encode(cidBytes)
|
||||||
|
|
||||||
|
var signature frostfscrypto.Signature
|
||||||
|
signer := frostfsecdsa.Signer(p.PrivateKey)
|
||||||
|
require.NoError(t, signature.Calculate(signer, cidBytes), "failed to calculate signature")
|
||||||
|
|
||||||
|
cc.get[hex.EncodeToString(cidBytes)] = &containercore.Container{
|
||||||
|
Value: cnr,
|
||||||
|
Signature: signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
table := eacl.NewTable()
|
||||||
|
table.SetCID(cid)
|
||||||
|
table.SetVersion(version.Current())
|
||||||
|
|
||||||
|
r := &eacl.Record{}
|
||||||
|
r.AddObjectContainerIDFilter(eacl.MatchStringEqual, cid)
|
||||||
|
|
||||||
|
table.AddRecord(r)
|
||||||
|
|
||||||
|
event := containerEvent.SetEACL{
|
||||||
|
TableValue: table.ToV2().StableMarshal(nil),
|
||||||
|
PublicKeyValue: p.PublicKey().Bytes(),
|
||||||
|
SignatureValue: p.Sign(table.ToV2().StableMarshal(nil)),
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleSetEACL(event)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedPutEACL cntClient.PutEACLPrm
|
||||||
|
expectedPutEACL.SetTable(table.ToV2().StableMarshal(nil))
|
||||||
|
expectedPutEACL.SetKey(p.PublicKey().Bytes())
|
||||||
|
expectedPutEACL.SetSignature(p.Sign(table.ToV2().StableMarshal(nil)))
|
||||||
|
|
||||||
|
require.EqualValues(t, []cntClient.PutEACLPrm{expectedPutEACL}, cc.putEACL, "invalid set EACL requests")
|
||||||
|
}
|
||||||
|
|
||||||
|
type testAlphabetState struct {
|
||||||
|
isAlphabet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testAlphabetState) IsAlphabet() bool {
|
||||||
|
return s.isAlphabet
|
||||||
|
}
|
||||||
|
|
||||||
|
type testNetworkState struct {
|
||||||
|
homHashDisabled bool
|
||||||
|
epoch uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testNetworkState) HomomorphicHashDisabled() (bool, error) {
|
||||||
|
return s.homHashDisabled, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testNetworkState) Epoch() (uint64, error) {
|
||||||
|
return s.epoch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testContainerClient struct {
|
||||||
|
contractAddress util.Uint160
|
||||||
|
put []cntClient.PutPrm
|
||||||
|
get map[string]*containercore.Container
|
||||||
|
delete []cntClient.DeletePrm
|
||||||
|
putEACL []cntClient.PutEACLPrm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContainerClient) ContractAddress() util.Uint160 {
|
||||||
|
return c.contractAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContainerClient) Morph() *client.Client {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContainerClient) Put(p cntClient.PutPrm) error {
|
||||||
|
c.put = append(c.put, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContainerClient) Get(cid []byte) (*containercore.Container, error) {
|
||||||
|
key := hex.EncodeToString(cid)
|
||||||
|
if cont, found := c.get[key]; found {
|
||||||
|
return cont, nil
|
||||||
|
}
|
||||||
|
return nil, apistatus.ContainerNotFound{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContainerClient) Delete(p cntClient.DeletePrm) error {
|
||||||
|
c.delete = append(c.delete, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContainerClient) PutEACL(p cntClient.PutEACLPrm) error {
|
||||||
|
c.putEACL = append(c.putEACL, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testIDClient struct {
|
||||||
|
publicKeys keys.PublicKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testIDClient) AccountKeys(p frostfsid.AccountKeysPrm) (keys.PublicKeys, error) {
|
||||||
|
return c.publicKeys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ putEvent = &testPutEvent{}
|
||||||
|
|
||||||
|
type testPutEvent struct {
|
||||||
|
cnr *containerSDK.Container
|
||||||
|
pk *keys.PrivateKey
|
||||||
|
st []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *testPutEvent) MorphEvent() {}
|
||||||
|
|
||||||
|
func (e *testPutEvent) Container() []byte {
|
||||||
|
return e.cnr.Marshal()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *testPutEvent) PublicKey() []byte {
|
||||||
|
return e.pk.PublicKey().Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *testPutEvent) Signature() []byte {
|
||||||
|
return e.pk.Sign(e.cnr.Marshal())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *testPutEvent) SessionToken() []byte {
|
||||||
|
return e.st
|
||||||
|
}
|
||||||
|
func (e *testPutEvent) NotaryRequest() *payload.P2PNotaryRequest {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -120,7 +120,7 @@ func (cp *Processor) approvePutContainer(ctx *putContainerContext) {
|
||||||
|
|
||||||
// Process delete container operation from the user by checking container sanity
|
// Process delete container operation from the user by checking container sanity
|
||||||
// and sending approve tx back to morph.
|
// and sending approve tx back to morph.
|
||||||
func (cp *Processor) processContainerDelete(e *containerEvent.Delete) {
|
func (cp *Processor) processContainerDelete(e containerEvent.Delete) {
|
||||||
if !cp.alphabetState.IsAlphabet() {
|
if !cp.alphabetState.IsAlphabet() {
|
||||||
cp.log.Info(logs.ContainerNonAlphabetModeIgnoreContainerDelete)
|
cp.log.Info(logs.ContainerNonAlphabetModeIgnoreContainerDelete)
|
||||||
return
|
return
|
||||||
|
@ -138,7 +138,7 @@ func (cp *Processor) processContainerDelete(e *containerEvent.Delete) {
|
||||||
cp.approveDeleteContainer(e)
|
cp.approveDeleteContainer(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) checkDeleteContainer(e *containerEvent.Delete) error {
|
func (cp *Processor) checkDeleteContainer(e containerEvent.Delete) error {
|
||||||
binCnr := e.ContainerID()
|
binCnr := e.ContainerID()
|
||||||
|
|
||||||
var idCnr cid.ID
|
var idCnr cid.ID
|
||||||
|
@ -170,7 +170,7 @@ func (cp *Processor) checkDeleteContainer(e *containerEvent.Delete) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) approveDeleteContainer(e *containerEvent.Delete) {
|
func (cp *Processor) approveDeleteContainer(e containerEvent.Delete) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
prm := cntClient.DeletePrm{}
|
prm := cntClient.DeletePrm{}
|
||||||
|
|
|
@ -6,13 +6,13 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||||
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cp *Processor) processSetEACL(e container.SetEACL) {
|
func (cp *Processor) processSetEACL(e containerEvent.SetEACL) {
|
||||||
if !cp.alphabetState.IsAlphabet() {
|
if !cp.alphabetState.IsAlphabet() {
|
||||||
cp.log.Info(logs.ContainerNonAlphabetModeIgnoreSetEACL)
|
cp.log.Info(logs.ContainerNonAlphabetModeIgnoreSetEACL)
|
||||||
return
|
return
|
||||||
|
@ -30,7 +30,7 @@ func (cp *Processor) processSetEACL(e container.SetEACL) {
|
||||||
cp.approveSetEACL(e)
|
cp.approveSetEACL(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) checkSetEACL(e container.SetEACL) error {
|
func (cp *Processor) checkSetEACL(e containerEvent.SetEACL) error {
|
||||||
binTable := e.Table()
|
binTable := e.Table()
|
||||||
|
|
||||||
// unmarshal table
|
// unmarshal table
|
||||||
|
@ -74,7 +74,7 @@ func (cp *Processor) checkSetEACL(e container.SetEACL) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *Processor) approveSetEACL(e container.SetEACL) {
|
func (cp *Processor) approveSetEACL(e containerEvent.SetEACL) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
prm := cntClient.PutEACLPrm{}
|
prm := cntClient.PutEACLPrm{}
|
||||||
|
|
|
@ -5,12 +5,16 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||||
|
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -21,13 +25,26 @@ type (
|
||||||
IsAlphabet() bool
|
IsAlphabet() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContClient interface {
|
||||||
|
ContractAddress() util.Uint160
|
||||||
|
Morph() *client.Client
|
||||||
|
Put(p cntClient.PutPrm) error
|
||||||
|
Get(cid []byte) (*containercore.Container, error)
|
||||||
|
Delete(p cntClient.DeletePrm) error
|
||||||
|
PutEACL(p cntClient.PutEACLPrm) error
|
||||||
|
}
|
||||||
|
|
||||||
|
IDClient interface {
|
||||||
|
AccountKeys(p frostfsid.AccountKeysPrm) (keys.PublicKeys, error)
|
||||||
|
}
|
||||||
|
|
||||||
// Processor of events produced by container contract in the sidechain.
|
// Processor of events produced by container contract in the sidechain.
|
||||||
Processor struct {
|
Processor struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
pool *ants.Pool
|
pool *ants.Pool
|
||||||
alphabetState AlphabetState
|
alphabetState AlphabetState
|
||||||
cnrClient *container.Client // notary must be enabled
|
cnrClient ContClient // notary must be enabled
|
||||||
idClient *frostfsid.Client
|
idClient IDClient
|
||||||
netState NetworkState
|
netState NetworkState
|
||||||
notaryDisabled bool
|
notaryDisabled bool
|
||||||
}
|
}
|
||||||
|
@ -37,8 +54,8 @@ type (
|
||||||
Log *logger.Logger
|
Log *logger.Logger
|
||||||
PoolSize int
|
PoolSize int
|
||||||
AlphabetState AlphabetState
|
AlphabetState AlphabetState
|
||||||
ContainerClient *container.Client
|
ContainerClient ContClient
|
||||||
FrostFSIDClient *frostfsid.Client
|
FrostFSIDClient IDClient
|
||||||
NetworkState NetworkState
|
NetworkState NetworkState
|
||||||
NotaryDisabled bool
|
NotaryDisabled bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ func (np *Processor) handleDeposit(ev event.Event) {
|
||||||
|
|
||||||
// send event to the worker pool
|
// send event to the worker pool
|
||||||
|
|
||||||
err := np.pool.Submit(func() { np.processDeposit(&deposit) })
|
err := np.pool.Submit(func() { np.processDeposit(deposit) })
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// there system can be moved into controlled degradation stage
|
// there system can be moved into controlled degradation stage
|
||||||
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
||||||
|
@ -34,7 +34,7 @@ func (np *Processor) handleWithdraw(ev event.Event) {
|
||||||
|
|
||||||
// send event to the worker pool
|
// send event to the worker pool
|
||||||
|
|
||||||
err := np.pool.Submit(func() { np.processWithdraw(&withdraw) })
|
err := np.pool.Submit(func() { np.processWithdraw(withdraw) })
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// there system can be moved into controlled degradation stage
|
// there system can be moved into controlled degradation stage
|
||||||
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
||||||
|
@ -50,7 +50,7 @@ func (np *Processor) handleCheque(ev event.Event) {
|
||||||
|
|
||||||
// send event to the worker pool
|
// send event to the worker pool
|
||||||
|
|
||||||
err := np.pool.Submit(func() { np.processCheque(&cheque) })
|
err := np.pool.Submit(func() { np.processCheque(cheque) })
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// there system can be moved into controlled degradation stage
|
// there system can be moved into controlled degradation stage
|
||||||
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
||||||
|
@ -67,7 +67,7 @@ func (np *Processor) handleConfig(ev event.Event) {
|
||||||
|
|
||||||
// send event to the worker pool
|
// send event to the worker pool
|
||||||
|
|
||||||
err := np.pool.Submit(func() { np.processConfig(&cfg) })
|
err := np.pool.Submit(func() { np.processConfig(cfg) })
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// there system can be moved into controlled degradation stage
|
// there system can be moved into controlled degradation stage
|
||||||
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
||||||
|
@ -83,7 +83,7 @@ func (np *Processor) handleBind(ev event.Event) {
|
||||||
|
|
||||||
// send event to the worker pool
|
// send event to the worker pool
|
||||||
|
|
||||||
err := np.pool.Submit(func() { np.processBind(e) })
|
err := np.pool.Submit(func() { np.processBind(e, true) })
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// there system can be moved into controlled degradation stage
|
// there system can be moved into controlled degradation stage
|
||||||
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
||||||
|
@ -99,7 +99,7 @@ func (np *Processor) handleUnbind(ev event.Event) {
|
||||||
|
|
||||||
// send event to the worker pool
|
// send event to the worker pool
|
||||||
|
|
||||||
err := np.pool.Submit(func() { np.processBind(e) })
|
err := np.pool.Submit(func() { np.processBind(e, false) })
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// there system can be moved into controlled degradation stage
|
// there system can be moved into controlled degradation stage
|
||||||
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
||||||
|
|
371
pkg/innerring/processors/frostfs/handlers_test.go
Normal file
371
pkg/innerring/processors/frostfs/handlers_test.go
Normal file
|
@ -0,0 +1,371 @@
|
||||||
|
package frostfs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/balance"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||||
|
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
|
frostfsEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/frostfs"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHandleDeposit(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
es := &testEpochState{
|
||||||
|
epochCounter: 100,
|
||||||
|
}
|
||||||
|
b := &testBalaceClient{}
|
||||||
|
m := &testMorphClient{
|
||||||
|
balance: 150,
|
||||||
|
}
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.EpochState = es
|
||||||
|
p.BalanceClient = b
|
||||||
|
p.MorphClient = m
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
ev := frostfsEvent.Deposit{
|
||||||
|
IDValue: []byte{1, 2, 3, 4, 5},
|
||||||
|
FromValue: util.Uint160{100},
|
||||||
|
ToValue: util.Uint160{200},
|
||||||
|
AmountValue: 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleDeposit(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
var expMint balance.MintPrm
|
||||||
|
expMint.SetAmount(ev.AmountValue)
|
||||||
|
expMint.SetID(ev.IDValue)
|
||||||
|
expMint.SetTo(ev.ToValue)
|
||||||
|
|
||||||
|
require.EqualValues(t, []balance.MintPrm{expMint}, b.mint, "invalid mint value")
|
||||||
|
require.EqualValues(t, []transferGas{
|
||||||
|
{
|
||||||
|
receiver: ev.ToValue,
|
||||||
|
amount: fixedn.Fixed8(50),
|
||||||
|
},
|
||||||
|
}, m.transferGas, "invalid transfer gas")
|
||||||
|
|
||||||
|
es.epochCounter = 109
|
||||||
|
|
||||||
|
proc.handleDeposit(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
expMint.SetAmount(ev.AmountValue)
|
||||||
|
expMint.SetID(ev.IDValue)
|
||||||
|
expMint.SetTo(ev.ToValue)
|
||||||
|
|
||||||
|
require.EqualValues(t, []balance.MintPrm{expMint, expMint}, b.mint, "invalid mint value")
|
||||||
|
require.EqualValues(t, []transferGas{
|
||||||
|
{
|
||||||
|
receiver: ev.ToValue,
|
||||||
|
amount: fixedn.Fixed8(50),
|
||||||
|
},
|
||||||
|
}, m.transferGas, "invalid transfer gas")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleWithdraw(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
es := &testEpochState{
|
||||||
|
epochCounter: 100,
|
||||||
|
}
|
||||||
|
b := &testBalaceClient{}
|
||||||
|
m := &testMorphClient{
|
||||||
|
balance: 150,
|
||||||
|
}
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.EpochState = es
|
||||||
|
p.BalanceClient = b
|
||||||
|
p.MorphClient = m
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
ev := frostfsEvent.Withdraw{
|
||||||
|
IDValue: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
|
||||||
|
UserValue: util.Uint160{100},
|
||||||
|
AmountValue: 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleWithdraw(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
lock, err := util.Uint160DecodeBytesBE(ev.ID()[:util.Uint160Size])
|
||||||
|
require.NoError(t, err, "failed to decode ID")
|
||||||
|
var expLock balance.LockPrm
|
||||||
|
expLock.SetAmount(ev.AmountValue)
|
||||||
|
expLock.SetID(ev.IDValue)
|
||||||
|
expLock.SetDueEpoch(int64(es.epochCounter) + int64(lockAccountLifetime))
|
||||||
|
expLock.SetLock(lock)
|
||||||
|
expLock.SetUser(ev.UserValue)
|
||||||
|
|
||||||
|
require.EqualValues(t, []balance.LockPrm{expLock}, b.lock, "invalid lock value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleCheque(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
es := &testEpochState{
|
||||||
|
epochCounter: 100,
|
||||||
|
}
|
||||||
|
b := &testBalaceClient{}
|
||||||
|
m := &testMorphClient{
|
||||||
|
balance: 150,
|
||||||
|
}
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.BalanceClient = b
|
||||||
|
p.MorphClient = m
|
||||||
|
p.EpochState = es
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
ev := frostfsEvent.Cheque{
|
||||||
|
IDValue: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
|
||||||
|
UserValue: util.Uint160{100},
|
||||||
|
AmountValue: 1000,
|
||||||
|
LockValue: util.Uint160{200},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleCheque(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
var expBurn balance.BurnPrm
|
||||||
|
expBurn.SetAmount(ev.AmountValue)
|
||||||
|
expBurn.SetID(ev.IDValue)
|
||||||
|
expBurn.SetTo(util.Uint160{200})
|
||||||
|
|
||||||
|
require.EqualValues(t, []balance.BurnPrm{expBurn}, b.burn, "invalid burn value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleConfig(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
es := &testEpochState{
|
||||||
|
epochCounter: 100,
|
||||||
|
}
|
||||||
|
nm := &testNetmapClient{}
|
||||||
|
m := &testMorphClient{
|
||||||
|
balance: 150,
|
||||||
|
}
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.NetmapClient = nm
|
||||||
|
p.MorphClient = m
|
||||||
|
p.EpochState = es
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
ev := frostfsEvent.Config{
|
||||||
|
IDValue: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
|
||||||
|
KeyValue: []byte{1, 2, 3, 4, 5},
|
||||||
|
ValueValue: []byte{6, 7, 8, 9, 0},
|
||||||
|
TxHashValue: util.Uint256{100},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleConfig(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
var expConfig nmClient.SetConfigPrm
|
||||||
|
expConfig.SetHash(ev.TxHashValue)
|
||||||
|
expConfig.SetID(ev.IDValue)
|
||||||
|
expConfig.SetKey(ev.KeyValue)
|
||||||
|
expConfig.SetValue(ev.ValueValue)
|
||||||
|
|
||||||
|
require.EqualValues(t, []nmClient.SetConfigPrm{expConfig}, nm.config, "invalid config value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleUnbind(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
es := &testEpochState{
|
||||||
|
epochCounter: 100,
|
||||||
|
}
|
||||||
|
m := &testMorphClient{
|
||||||
|
balance: 150,
|
||||||
|
}
|
||||||
|
id := &testIDClient{}
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.EpochState = es
|
||||||
|
p.MorphClient = m
|
||||||
|
p.FrostFSIDClient = id
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
p, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
evUnbind := frostfsEvent.Unbind{
|
||||||
|
BindCommon: frostfsEvent.BindCommon{
|
||||||
|
UserValue: util.Uint160{49}.BytesBE(),
|
||||||
|
KeysValue: [][]byte{
|
||||||
|
p.PublicKey().Bytes(),
|
||||||
|
},
|
||||||
|
TxHashValue: util.Uint256{100},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleUnbind(evUnbind)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
var userID user.ID
|
||||||
|
userID.SetScriptHash(util.Uint160{49})
|
||||||
|
|
||||||
|
var expBind frostfsid.CommonBindPrm
|
||||||
|
expBind.SetOwnerID(userID.WalletBytes())
|
||||||
|
expBind.SetKeys(evUnbind.BindCommon.KeysValue)
|
||||||
|
expBind.SetHash(evUnbind.BindCommon.TxHashValue)
|
||||||
|
|
||||||
|
var expNilSlice []frostfsid.CommonBindPrm
|
||||||
|
|
||||||
|
require.EqualValues(t, []frostfsid.CommonBindPrm{expBind}, id.remove, "invalid remove keys value")
|
||||||
|
require.EqualValues(t, expNilSlice, id.add, "invalid add keys value")
|
||||||
|
|
||||||
|
evBind := frostfsEvent.Bind{
|
||||||
|
BindCommon: frostfsEvent.BindCommon{
|
||||||
|
UserValue: util.Uint160{49}.BytesBE(),
|
||||||
|
KeysValue: [][]byte{
|
||||||
|
p.PublicKey().Bytes(),
|
||||||
|
},
|
||||||
|
TxHashValue: util.Uint256{100},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleBind(evBind)
|
||||||
|
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
|
||||||
|
require.EqualValues(t, []frostfsid.CommonBindPrm{expBind}, id.remove, "invalid remove keys value")
|
||||||
|
require.EqualValues(t, []frostfsid.CommonBindPrm{expBind}, id.add, "invalid add keys value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestProc(t *testing.T, nonDefault func(p *Params)) (*Processor, error) {
|
||||||
|
p := &Params{
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 1,
|
||||||
|
FrostFSContract: util.Uint160{0},
|
||||||
|
FrostFSIDClient: &testIDClient{},
|
||||||
|
BalanceClient: &testBalaceClient{},
|
||||||
|
NetmapClient: &testNetmapClient{},
|
||||||
|
MorphClient: &testMorphClient{},
|
||||||
|
EpochState: &testEpochState{},
|
||||||
|
AlphabetState: &testAlphabetState{isAlphabet: true},
|
||||||
|
Converter: &testPrecisionConverter{},
|
||||||
|
MintEmitCacheSize: 100,
|
||||||
|
MintEmitThreshold: 10,
|
||||||
|
MintEmitValue: fixedn.Fixed8(50),
|
||||||
|
GasBalanceThreshold: 50,
|
||||||
|
}
|
||||||
|
|
||||||
|
nonDefault(p)
|
||||||
|
|
||||||
|
return New(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
type testEpochState struct {
|
||||||
|
epochCounter uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testEpochState) EpochCounter() uint64 {
|
||||||
|
return s.epochCounter
|
||||||
|
}
|
||||||
|
|
||||||
|
type testAlphabetState struct {
|
||||||
|
isAlphabet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testAlphabetState) IsAlphabet() bool {
|
||||||
|
return s.isAlphabet
|
||||||
|
}
|
||||||
|
|
||||||
|
type testPrecisionConverter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testPrecisionConverter) ToBalancePrecision(v int64) int64 {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
type testBalaceClient struct {
|
||||||
|
mint []balance.MintPrm
|
||||||
|
lock []balance.LockPrm
|
||||||
|
burn []balance.BurnPrm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testBalaceClient) Mint(p balance.MintPrm) error {
|
||||||
|
c.mint = append(c.mint, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *testBalaceClient) Lock(p balance.LockPrm) error {
|
||||||
|
c.lock = append(c.lock, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *testBalaceClient) Burn(p balance.BurnPrm) error {
|
||||||
|
c.burn = append(c.burn, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testNetmapClient struct {
|
||||||
|
config []nmClient.SetConfigPrm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testNetmapClient) SetConfig(p nmClient.SetConfigPrm) error {
|
||||||
|
c.config = append(c.config, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type transferGas struct {
|
||||||
|
receiver util.Uint160
|
||||||
|
amount fixedn.Fixed8
|
||||||
|
}
|
||||||
|
|
||||||
|
type testMorphClient struct {
|
||||||
|
balance int64
|
||||||
|
transferGas []transferGas
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testMorphClient) GasBalance() (res int64, err error) {
|
||||||
|
return c.balance, nil
|
||||||
|
}
|
||||||
|
func (c *testMorphClient) TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error {
|
||||||
|
c.transferGas = append(c.transferGas, transferGas{
|
||||||
|
receiver: receiver,
|
||||||
|
amount: amount,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testIDClient struct {
|
||||||
|
add []frostfsid.CommonBindPrm
|
||||||
|
remove []frostfsid.CommonBindPrm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testIDClient) AddKeys(p frostfsid.CommonBindPrm) error {
|
||||||
|
c.add = append(c.add, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testIDClient) RemoveKeys(args frostfsid.CommonBindPrm) error {
|
||||||
|
c.remove = append(c.remove, args)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ const (
|
||||||
|
|
||||||
// Process deposit event by invoking a balance contract and sending native
|
// Process deposit event by invoking a balance contract and sending native
|
||||||
// gas in the sidechain.
|
// gas in the sidechain.
|
||||||
func (np *Processor) processDeposit(deposit *frostfsEvent.Deposit) {
|
func (np *Processor) processDeposit(deposit frostfsEvent.Deposit) {
|
||||||
if !np.alphabetState.IsAlphabet() {
|
if !np.alphabetState.IsAlphabet() {
|
||||||
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreDeposit)
|
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreDeposit)
|
||||||
return
|
return
|
||||||
|
@ -80,7 +80,7 @@ func (np *Processor) processDeposit(deposit *frostfsEvent.Deposit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process withdraw event by locking assets in the balance account.
|
// Process withdraw event by locking assets in the balance account.
|
||||||
func (np *Processor) processWithdraw(withdraw *frostfsEvent.Withdraw) {
|
func (np *Processor) processWithdraw(withdraw frostfsEvent.Withdraw) {
|
||||||
if !np.alphabetState.IsAlphabet() {
|
if !np.alphabetState.IsAlphabet() {
|
||||||
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreWithdraw)
|
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreWithdraw)
|
||||||
return
|
return
|
||||||
|
@ -111,7 +111,7 @@ func (np *Processor) processWithdraw(withdraw *frostfsEvent.Withdraw) {
|
||||||
|
|
||||||
// Process cheque event by transferring assets from the lock account back to
|
// Process cheque event by transferring assets from the lock account back to
|
||||||
// the reserve account.
|
// the reserve account.
|
||||||
func (np *Processor) processCheque(cheque *frostfsEvent.Cheque) {
|
func (np *Processor) processCheque(cheque frostfsEvent.Cheque) {
|
||||||
if !np.alphabetState.IsAlphabet() {
|
if !np.alphabetState.IsAlphabet() {
|
||||||
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreCheque)
|
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreCheque)
|
||||||
return
|
return
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/frostfs"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -19,7 +18,7 @@ type bindCommon interface {
|
||||||
TxHash() util.Uint256
|
TxHash() util.Uint256
|
||||||
}
|
}
|
||||||
|
|
||||||
func (np *Processor) processBind(e bindCommon) {
|
func (np *Processor) processBind(e bindCommon, bind bool) {
|
||||||
if !np.alphabetState.IsAlphabet() {
|
if !np.alphabetState.IsAlphabet() {
|
||||||
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreBind)
|
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreBind)
|
||||||
return
|
return
|
||||||
|
@ -27,10 +26,9 @@ func (np *Processor) processBind(e bindCommon) {
|
||||||
|
|
||||||
c := &bindCommonContext{
|
c := &bindCommonContext{
|
||||||
bindCommon: e,
|
bindCommon: e,
|
||||||
|
bind: bind,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, c.bind = e.(frostfs.Bind)
|
|
||||||
|
|
||||||
err := np.checkBindCommon(c)
|
err := np.checkBindCommon(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
np.log.Error(logs.FrostFSInvalidManageKeyEvent,
|
np.log.Error(logs.FrostFSInvalidManageKeyEvent,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
// Process config event by setting configuration value from the mainchain in
|
// Process config event by setting configuration value from the mainchain in
|
||||||
// the sidechain.
|
// the sidechain.
|
||||||
func (np *Processor) processConfig(config *frostfsEvent.Config) {
|
func (np *Processor) processConfig(config frostfsEvent.Config) {
|
||||||
if !np.alphabetState.IsAlphabet() {
|
if !np.alphabetState.IsAlphabet() {
|
||||||
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreConfig)
|
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreConfig)
|
||||||
return
|
return
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/balance"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/balance"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
|
@ -36,14 +35,34 @@ type (
|
||||||
ToBalancePrecision(int64) int64
|
ToBalancePrecision(int64) int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BalanceClient interface {
|
||||||
|
Mint(p balance.MintPrm) error
|
||||||
|
Lock(p balance.LockPrm) error
|
||||||
|
Burn(p balance.BurnPrm) error
|
||||||
|
}
|
||||||
|
|
||||||
|
NetmapClient interface {
|
||||||
|
SetConfig(p nmClient.SetConfigPrm) error
|
||||||
|
}
|
||||||
|
|
||||||
|
MorphClient interface {
|
||||||
|
GasBalance() (res int64, err error)
|
||||||
|
TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error
|
||||||
|
}
|
||||||
|
|
||||||
|
IDClient interface {
|
||||||
|
AddKeys(p frostfsid.CommonBindPrm) error
|
||||||
|
RemoveKeys(args frostfsid.CommonBindPrm) error
|
||||||
|
}
|
||||||
|
|
||||||
// Processor of events produced by frostfs contract in main net.
|
// Processor of events produced by frostfs contract in main net.
|
||||||
Processor struct {
|
Processor struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
pool *ants.Pool
|
pool *ants.Pool
|
||||||
frostfsContract util.Uint160
|
frostfsContract util.Uint160
|
||||||
balanceClient *balance.Client
|
balanceClient BalanceClient
|
||||||
netmapClient *nmClient.Client
|
netmapClient NetmapClient
|
||||||
morphClient *client.Client
|
morphClient MorphClient
|
||||||
epochState EpochState
|
epochState EpochState
|
||||||
alphabetState AlphabetState
|
alphabetState AlphabetState
|
||||||
converter PrecisionConverter
|
converter PrecisionConverter
|
||||||
|
@ -52,8 +71,7 @@ type (
|
||||||
mintEmitThreshold uint64
|
mintEmitThreshold uint64
|
||||||
mintEmitValue fixedn.Fixed8
|
mintEmitValue fixedn.Fixed8
|
||||||
gasBalanceThreshold int64
|
gasBalanceThreshold int64
|
||||||
|
frostfsIDClient IDClient
|
||||||
frostfsIDClient *frostfsid.Client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Params of the processor constructor.
|
// Params of the processor constructor.
|
||||||
|
@ -61,10 +79,10 @@ type (
|
||||||
Log *logger.Logger
|
Log *logger.Logger
|
||||||
PoolSize int
|
PoolSize int
|
||||||
FrostFSContract util.Uint160
|
FrostFSContract util.Uint160
|
||||||
FrostFSIDClient *frostfsid.Client
|
FrostFSIDClient IDClient
|
||||||
BalanceClient *balance.Client
|
BalanceClient BalanceClient
|
||||||
NetmapClient *nmClient.Client
|
NetmapClient NetmapClient
|
||||||
MorphClient *client.Client
|
MorphClient MorphClient
|
||||||
EpochState EpochState
|
EpochState EpochState
|
||||||
AlphabetState AlphabetState
|
AlphabetState AlphabetState
|
||||||
Converter PrecisionConverter
|
Converter PrecisionConverter
|
||||||
|
|
304
pkg/innerring/processors/governance/handlers_test.go
Normal file
304
pkg/innerring/processors/governance/handlers_test.go
Normal file
|
@ -0,0 +1,304 @@
|
||||||
|
package governance
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||||
|
frostfscontract "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfs"
|
||||||
|
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/rolemanagement"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHandleAlphabetSyncEvent(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testKeys := generateTestKeys(t)
|
||||||
|
|
||||||
|
es := &testEpochState{
|
||||||
|
epoch: 100,
|
||||||
|
}
|
||||||
|
as := &testAlphabetState{
|
||||||
|
isAlphabet: true,
|
||||||
|
}
|
||||||
|
v := &testVoter{}
|
||||||
|
irf := &testIRFetcher{
|
||||||
|
publicKeys: testKeys.sidechainKeys,
|
||||||
|
}
|
||||||
|
m := &testMorphClient{
|
||||||
|
commiteeKeys: testKeys.sidechainKeys,
|
||||||
|
}
|
||||||
|
mn := &testMainnetClient{
|
||||||
|
alphabetKeys: testKeys.mainnetKeys,
|
||||||
|
}
|
||||||
|
f := &testFrostFSClient{}
|
||||||
|
nm := &testNetmapClient{}
|
||||||
|
|
||||||
|
proc, err := New(
|
||||||
|
&Params{
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
EpochState: es,
|
||||||
|
AlphabetState: as,
|
||||||
|
Voter: v,
|
||||||
|
IRFetcher: irf,
|
||||||
|
NotaryDisabled: true,
|
||||||
|
MorphClient: m,
|
||||||
|
MainnetClient: mn,
|
||||||
|
FrostFSClient: f,
|
||||||
|
NetmapClient: nm,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
ev := Sync{
|
||||||
|
txHash: util.Uint256{100},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.HandleAlphabetSync(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.EqualValues(t, []VoteValidatorPrm{
|
||||||
|
{
|
||||||
|
Validators: testKeys.newAlphabetExp,
|
||||||
|
Hash: &ev.txHash,
|
||||||
|
},
|
||||||
|
}, v.votes, "invalid vote calls")
|
||||||
|
|
||||||
|
var irUpdateExp nmClient.UpdateIRPrm
|
||||||
|
irUpdateExp.SetKeys(testKeys.newInnerRingExp)
|
||||||
|
irUpdateExp.SetHash(ev.txHash)
|
||||||
|
|
||||||
|
require.EqualValues(t, []nmClient.UpdateIRPrm{irUpdateExp}, nm.updates, "invalid IR updates")
|
||||||
|
|
||||||
|
var expAlphabetUpdates []client.UpdateAlphabetListPrm
|
||||||
|
require.EqualValues(t, expAlphabetUpdates, m.alphabetUpdates, "invalid alphabet updates")
|
||||||
|
|
||||||
|
var expNotaryUpdates []client.UpdateNotaryListPrm
|
||||||
|
require.EqualValues(t, expNotaryUpdates, m.notaryUpdates, "invalid notary list updates")
|
||||||
|
|
||||||
|
buf := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(buf, es.epoch)
|
||||||
|
|
||||||
|
id := append([]byte(alphabetUpdateIDPrefix), buf...)
|
||||||
|
var expFrostFSAlphabetUpd frostfscontract.AlphabetUpdatePrm
|
||||||
|
expFrostFSAlphabetUpd.SetID(id)
|
||||||
|
expFrostFSAlphabetUpd.SetPubs(testKeys.newAlphabetExp)
|
||||||
|
|
||||||
|
require.EqualValues(t, []frostfscontract.AlphabetUpdatePrm{expFrostFSAlphabetUpd}, f.updates, "invalid FrostFS alphabet updates")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandleAlphabetDesignateEvent(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
testKeys := generateTestKeys(t)
|
||||||
|
|
||||||
|
es := &testEpochState{
|
||||||
|
epoch: 100,
|
||||||
|
}
|
||||||
|
as := &testAlphabetState{
|
||||||
|
isAlphabet: true,
|
||||||
|
}
|
||||||
|
v := &testVoter{}
|
||||||
|
irf := &testIRFetcher{
|
||||||
|
publicKeys: testKeys.sidechainKeys,
|
||||||
|
}
|
||||||
|
m := &testMorphClient{
|
||||||
|
commiteeKeys: testKeys.sidechainKeys,
|
||||||
|
}
|
||||||
|
mn := &testMainnetClient{
|
||||||
|
alphabetKeys: testKeys.mainnetKeys,
|
||||||
|
}
|
||||||
|
f := &testFrostFSClient{}
|
||||||
|
nm := &testNetmapClient{}
|
||||||
|
|
||||||
|
proc, err := New(
|
||||||
|
&Params{
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
EpochState: es,
|
||||||
|
AlphabetState: as,
|
||||||
|
Voter: v,
|
||||||
|
IRFetcher: irf,
|
||||||
|
NotaryDisabled: false,
|
||||||
|
MorphClient: m,
|
||||||
|
MainnetClient: mn,
|
||||||
|
FrostFSClient: f,
|
||||||
|
NetmapClient: nm,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
ev := rolemanagement.Designate{
|
||||||
|
TxHash: util.Uint256{100},
|
||||||
|
Role: noderoles.NeoFSAlphabet,
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.HandleAlphabetSync(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.EqualValues(t, []VoteValidatorPrm{
|
||||||
|
{
|
||||||
|
Validators: testKeys.newAlphabetExp,
|
||||||
|
Hash: &ev.TxHash,
|
||||||
|
},
|
||||||
|
}, v.votes, "invalid vote calls")
|
||||||
|
|
||||||
|
var irUpdatesExp []nmClient.UpdateIRPrm
|
||||||
|
require.EqualValues(t, irUpdatesExp, nm.updates, "invalid IR updates")
|
||||||
|
|
||||||
|
var alpabetUpdExp client.UpdateAlphabetListPrm
|
||||||
|
alpabetUpdExp.SetList(testKeys.newInnerRingExp)
|
||||||
|
alpabetUpdExp.SetHash(ev.TxHash)
|
||||||
|
require.EqualValues(t, []client.UpdateAlphabetListPrm{alpabetUpdExp}, m.alphabetUpdates, "invalid alphabet updates")
|
||||||
|
|
||||||
|
var expNotaryUpdate client.UpdateNotaryListPrm
|
||||||
|
expNotaryUpdate.SetList(testKeys.newAlphabetExp)
|
||||||
|
expNotaryUpdate.SetHash(ev.TxHash)
|
||||||
|
require.EqualValues(t, []client.UpdateNotaryListPrm{expNotaryUpdate}, m.notaryUpdates, "invalid notary list updates")
|
||||||
|
|
||||||
|
buf := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(buf, es.epoch)
|
||||||
|
|
||||||
|
id := append([]byte(alphabetUpdateIDPrefix), buf...)
|
||||||
|
var expFrostFSAlphabetUpd frostfscontract.AlphabetUpdatePrm
|
||||||
|
expFrostFSAlphabetUpd.SetID(id)
|
||||||
|
expFrostFSAlphabetUpd.SetPubs(testKeys.newAlphabetExp)
|
||||||
|
|
||||||
|
require.EqualValues(t, []frostfscontract.AlphabetUpdatePrm{expFrostFSAlphabetUpd}, f.updates, "invalid FrostFS alphabet updates")
|
||||||
|
}
|
||||||
|
|
||||||
|
type testKeys struct {
|
||||||
|
sidechainKeys keys.PublicKeys
|
||||||
|
mainnetKeys keys.PublicKeys
|
||||||
|
newAlphabetExp keys.PublicKeys
|
||||||
|
newInnerRingExp keys.PublicKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateTestKeys(t *testing.T) testKeys {
|
||||||
|
for {
|
||||||
|
var result testKeys
|
||||||
|
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
pk, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err, "failed to create private key")
|
||||||
|
result.sidechainKeys = append(result.sidechainKeys, pk.PublicKey())
|
||||||
|
}
|
||||||
|
|
||||||
|
result.mainnetKeys = append(result.mainnetKeys, result.sidechainKeys...)
|
||||||
|
pk, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err, "failed to create private key")
|
||||||
|
result.mainnetKeys = append(result.mainnetKeys, pk.PublicKey())
|
||||||
|
|
||||||
|
result.newAlphabetExp, err = newAlphabetList(result.sidechainKeys, result.mainnetKeys)
|
||||||
|
require.NoError(t, err, "failed to create expected new alphabet")
|
||||||
|
|
||||||
|
if len(result.newAlphabetExp) == 0 {
|
||||||
|
continue //can be happen because of random and sort
|
||||||
|
}
|
||||||
|
|
||||||
|
var irKeys keys.PublicKeys
|
||||||
|
irKeys = append(irKeys, result.sidechainKeys...)
|
||||||
|
result.newInnerRingExp, err = updateInnerRing(irKeys, result.sidechainKeys, result.newAlphabetExp)
|
||||||
|
require.NoError(t, err, "failed to create expected new IR")
|
||||||
|
sort.Sort(result.newInnerRingExp)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testEpochState struct {
|
||||||
|
epoch uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testEpochState) EpochCounter() uint64 {
|
||||||
|
return s.epoch
|
||||||
|
}
|
||||||
|
|
||||||
|
type testAlphabetState struct {
|
||||||
|
isAlphabet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testAlphabetState) IsAlphabet() bool {
|
||||||
|
return s.isAlphabet
|
||||||
|
}
|
||||||
|
|
||||||
|
type testVoter struct {
|
||||||
|
votes []VoteValidatorPrm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *testVoter) VoteForSidechainValidator(prm VoteValidatorPrm) error {
|
||||||
|
v.votes = append(v.votes, prm)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testIRFetcher struct {
|
||||||
|
publicKeys keys.PublicKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *testIRFetcher) InnerRingKeys() (keys.PublicKeys, error) {
|
||||||
|
return f.publicKeys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testMorphClient struct {
|
||||||
|
commiteeKeys keys.PublicKeys
|
||||||
|
|
||||||
|
alphabetUpdates []client.UpdateAlphabetListPrm
|
||||||
|
notaryUpdates []client.UpdateNotaryListPrm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testMorphClient) Committee() (res keys.PublicKeys, err error) {
|
||||||
|
return c.commiteeKeys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testMorphClient) UpdateNeoFSAlphabetList(prm client.UpdateAlphabetListPrm) error {
|
||||||
|
c.alphabetUpdates = append(c.alphabetUpdates, prm)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testMorphClient) UpdateNotaryList(prm client.UpdateNotaryListPrm) error {
|
||||||
|
c.notaryUpdates = append(c.notaryUpdates, prm)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testMainnetClient struct {
|
||||||
|
alphabetKeys keys.PublicKeys
|
||||||
|
designateHash util.Uint160
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testMainnetClient) NeoFSAlphabetList() (res keys.PublicKeys, err error) {
|
||||||
|
return c.alphabetKeys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testMainnetClient) GetDesignateHash() util.Uint160 {
|
||||||
|
return c.designateHash
|
||||||
|
}
|
||||||
|
|
||||||
|
type testFrostFSClient struct {
|
||||||
|
updates []frostfscontract.AlphabetUpdatePrm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testFrostFSClient) AlphabetUpdate(p frostfscontract.AlphabetUpdatePrm) error {
|
||||||
|
c.updates = append(c.updates, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testNetmapClient struct {
|
||||||
|
updates []nmClient.UpdateIRPrm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testNetmapClient) UpdateInnerRing(p nmClient.UpdateIRPrm) error {
|
||||||
|
c.updates = append(c.updates, p)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -53,20 +53,39 @@ type (
|
||||||
InnerRingKeys() (keys.PublicKeys, error)
|
InnerRingKeys() (keys.PublicKeys, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FrostFSClient interface {
|
||||||
|
AlphabetUpdate(p frostfscontract.AlphabetUpdatePrm) error
|
||||||
|
}
|
||||||
|
|
||||||
|
NetmapClient interface {
|
||||||
|
UpdateInnerRing(p nmClient.UpdateIRPrm) error
|
||||||
|
}
|
||||||
|
|
||||||
|
MainnetClient interface {
|
||||||
|
NeoFSAlphabetList() (res keys.PublicKeys, err error)
|
||||||
|
GetDesignateHash() util.Uint160
|
||||||
|
}
|
||||||
|
|
||||||
|
MorphClient interface {
|
||||||
|
Committee() (res keys.PublicKeys, err error)
|
||||||
|
UpdateNeoFSAlphabetList(prm client.UpdateAlphabetListPrm) error
|
||||||
|
UpdateNotaryList(prm client.UpdateNotaryListPrm) error
|
||||||
|
}
|
||||||
|
|
||||||
// Processor of events related to governance in the network.
|
// Processor of events related to governance in the network.
|
||||||
Processor struct {
|
Processor struct {
|
||||||
log *logger.Logger
|
log *logger.Logger
|
||||||
pool *ants.Pool
|
pool *ants.Pool
|
||||||
frostfsClient *frostfscontract.Client
|
frostfsClient FrostFSClient
|
||||||
netmapClient *nmClient.Client
|
netmapClient NetmapClient
|
||||||
|
|
||||||
alphabetState AlphabetState
|
alphabetState AlphabetState
|
||||||
epochState EpochState
|
epochState EpochState
|
||||||
voter Voter
|
voter Voter
|
||||||
irFetcher IRFetcher
|
irFetcher IRFetcher
|
||||||
|
|
||||||
mainnetClient *client.Client
|
mainnetClient MainnetClient
|
||||||
morphClient *client.Client
|
morphClient MorphClient
|
||||||
|
|
||||||
notaryDisabled bool
|
notaryDisabled bool
|
||||||
|
|
||||||
|
@ -82,10 +101,10 @@ type (
|
||||||
Voter Voter
|
Voter Voter
|
||||||
IRFetcher IRFetcher
|
IRFetcher IRFetcher
|
||||||
|
|
||||||
MorphClient *client.Client
|
MorphClient MorphClient
|
||||||
MainnetClient *client.Client
|
MainnetClient MainnetClient
|
||||||
FrostFSClient *frostfscontract.Client
|
FrostFSClient FrostFSClient
|
||||||
NetmapClient *nmClient.Client
|
NetmapClient NetmapClient
|
||||||
|
|
||||||
NotaryDisabled bool
|
NotaryDisabled bool
|
||||||
}
|
}
|
||||||
|
|
570
pkg/innerring/processors/netmap/handlers_test.go
Normal file
570
pkg/innerring/processors/netmap/handlers_test.go
Normal file
|
@ -0,0 +1,570 @@
|
||||||
|
package netmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
|
||||||
|
netmapContract "git.frostfs.info/TrueCloudLab/frostfs-contract/netmap"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/audit"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/governance"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement"
|
||||||
|
timerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/timers"
|
||||||
|
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||||
|
netmapclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
|
netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewEpochTick(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
es := &testEpochState{
|
||||||
|
counter: 100,
|
||||||
|
}
|
||||||
|
nc := &testNetmapClient{}
|
||||||
|
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.NotaryDisabled = true
|
||||||
|
p.CleanupEnabled = true
|
||||||
|
p.EpochState = es
|
||||||
|
p.NetmapClient = nc
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
ev := timerEvent.NewEpochTick{}
|
||||||
|
proc.HandleNewEpochTick(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.EqualValues(t, []uint64{101}, nc.newEpochs, "invalid epochs")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewEpoch(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
var node1 netmap.NodeInfo
|
||||||
|
key1, err := keys.NewPublicKeyFromString("038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35")
|
||||||
|
require.NoError(t, err, "failed to parse key1")
|
||||||
|
node1.SetPublicKey(key1.Bytes())
|
||||||
|
|
||||||
|
var node2 netmap.NodeInfo
|
||||||
|
key2, err := keys.NewPublicKeyFromString("02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3")
|
||||||
|
require.NoError(t, err, "failed to parse key2")
|
||||||
|
node2.SetPublicKey(key2.Bytes())
|
||||||
|
|
||||||
|
network := &netmap.NetMap{}
|
||||||
|
network.SetNodes([]netmap.NodeInfo{node1, node2})
|
||||||
|
|
||||||
|
es := &testEpochState{
|
||||||
|
counter: 100,
|
||||||
|
duration: 10,
|
||||||
|
}
|
||||||
|
r := &testEpochResetter{}
|
||||||
|
cc := &testContainerClient{}
|
||||||
|
nc := &testNetmapClient{
|
||||||
|
epochDuration: 20,
|
||||||
|
txHeights: map[util.Uint256]uint32{
|
||||||
|
{101}: 10_000,
|
||||||
|
},
|
||||||
|
netmap: network,
|
||||||
|
}
|
||||||
|
eh := &testEventHandler{}
|
||||||
|
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.NotaryDisabled = true
|
||||||
|
p.NotaryDepositHandler = eh.Handle
|
||||||
|
p.HandleAudit = eh.Handle
|
||||||
|
p.AuditSettlementsHandler = eh.Handle
|
||||||
|
p.AlphabetSyncHandler = eh.Handle
|
||||||
|
p.NetmapClient = nc
|
||||||
|
p.ContainerWrapper = cc
|
||||||
|
p.EpochTimer = r
|
||||||
|
p.EpochState = es
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
ev := netmapEvent.NewEpoch{
|
||||||
|
Num: 101,
|
||||||
|
Hash: util.Uint256{101},
|
||||||
|
}
|
||||||
|
proc.handleNewEpoch(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, nc.epochDuration, es.duration, "invalid epoch duration")
|
||||||
|
require.Equal(t, ev.Num, es.counter, "invalid epoch counter")
|
||||||
|
require.EqualValues(t, []uint32{nc.txHeights[ev.Hash]}, r.timers, "invalid epoch timer resets")
|
||||||
|
|
||||||
|
var expEstimation cntClient.StartEstimationPrm
|
||||||
|
expEstimation.SetEpoch(ev.Num - 1)
|
||||||
|
expEstimation.SetHash(ev.Hash)
|
||||||
|
require.EqualValues(t, []cntClient.StartEstimationPrm{expEstimation}, cc.estimations, "invalid estimations")
|
||||||
|
|
||||||
|
require.EqualValues(t, []event.Event{
|
||||||
|
audit.NewAuditStartEvent(ev.Num),
|
||||||
|
settlement.NewAuditEvent(ev.Num),
|
||||||
|
governance.NewSyncEvent(ev.TxHash()),
|
||||||
|
ev,
|
||||||
|
}, eh.handledEvents, "invalid handled events")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddPeer(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("with notary", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
nc := &testNetmapClient{
|
||||||
|
contractAddress: util.Uint160{47},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.NotaryDisabled = true
|
||||||
|
p.NetmapClient = nc
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
var node netmap.NodeInfo
|
||||||
|
key, err := keys.NewPublicKeyFromString("038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35")
|
||||||
|
require.NoError(t, err, "failed to parse key1")
|
||||||
|
node.SetPublicKey(key.Bytes())
|
||||||
|
|
||||||
|
ev := netmapEvent.AddPeer{
|
||||||
|
NodeBytes: node.Marshal(),
|
||||||
|
Request: &payload.P2PNotaryRequest{
|
||||||
|
MainTransaction: &transaction.Transaction{
|
||||||
|
Nonce: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
proc.handleAddPeer(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.EqualValues(t, []notaryInvoke{
|
||||||
|
{
|
||||||
|
contract: nc.contractAddress,
|
||||||
|
fee: 0,
|
||||||
|
nonce: ev.Request.MainTransaction.Nonce,
|
||||||
|
vub: nil,
|
||||||
|
method: "addPeerIR",
|
||||||
|
args: []any{ev.Node()},
|
||||||
|
},
|
||||||
|
}, nc.notaryInvokes, "invalid notary invokes")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("without notary", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
nc := &testNetmapClient{
|
||||||
|
contractAddress: util.Uint160{47},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.NotaryDisabled = true
|
||||||
|
p.NetmapClient = nc
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
var node netmap.NodeInfo
|
||||||
|
key, err := keys.NewPublicKeyFromString("038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35")
|
||||||
|
require.NoError(t, err, "failed to parse key")
|
||||||
|
node.SetPublicKey(key.Bytes())
|
||||||
|
|
||||||
|
ev := netmapEvent.AddPeer{
|
||||||
|
NodeBytes: node.Marshal(),
|
||||||
|
}
|
||||||
|
proc.handleAddPeer(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
var addPeerExp netmapclient.AddPeerPrm
|
||||||
|
addPeerExp.SetNodeInfo(node)
|
||||||
|
require.EqualValues(t, []netmapclient.AddPeerPrm{addPeerExp}, nc.addPeers, "invalid peers")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateState(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("with notary", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ns := &testNodeStateSettings{
|
||||||
|
maintAllowed: true,
|
||||||
|
}
|
||||||
|
nc := &testNetmapClient{}
|
||||||
|
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.NotaryDisabled = true
|
||||||
|
p.NodeStateSettings = ns
|
||||||
|
p.NetmapClient = nc
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
key, err := keys.NewPublicKeyFromString("038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35")
|
||||||
|
require.NoError(t, err, "failed to parse key")
|
||||||
|
|
||||||
|
ev := netmapEvent.UpdatePeer{
|
||||||
|
State: netmapContract.NodeStateOnline,
|
||||||
|
PubKey: key,
|
||||||
|
Request: &payload.P2PNotaryRequest{
|
||||||
|
MainTransaction: &transaction.Transaction{
|
||||||
|
Nonce: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
proc.handleUpdateState(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.EqualValues(t, []*transaction.Transaction{
|
||||||
|
ev.Request.MainTransaction,
|
||||||
|
}, nc.invokedTxs, "invalid invoked transactions")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("without notary", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ns := &testNodeStateSettings{
|
||||||
|
maintAllowed: true,
|
||||||
|
}
|
||||||
|
nc := &testNetmapClient{}
|
||||||
|
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.NetmapClient = nc
|
||||||
|
p.NodeStateSettings = ns
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
key, err := keys.NewPublicKeyFromString("038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35")
|
||||||
|
require.NoError(t, err, "failed to parse key")
|
||||||
|
|
||||||
|
ev := netmapEvent.UpdatePeer{
|
||||||
|
State: netmapContract.NodeStateOnline,
|
||||||
|
PubKey: key,
|
||||||
|
}
|
||||||
|
proc.handleUpdateState(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
var expUpdPeer netmapclient.UpdatePeerPrm
|
||||||
|
expUpdPeer.SetMaintenance()
|
||||||
|
expUpdPeer.SetOnline()
|
||||||
|
expUpdPeer.SetKey(ev.PubKey.Bytes())
|
||||||
|
|
||||||
|
require.EqualValues(t, []netmapclient.UpdatePeerPrm{expUpdPeer}, nc.peerStateUpdates, "invalid peer state updates")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCleanupTick(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("notary disabled", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
nc := &testNetmapClient{}
|
||||||
|
|
||||||
|
proc, err := newTestProc(t, func(p *Params) {
|
||||||
|
p.NetmapClient = nc
|
||||||
|
p.NotaryDisabled = true
|
||||||
|
p.CleanupEnabled = true
|
||||||
|
})
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
key1Str := "038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35"
|
||||||
|
proc.netmapSnapshot.lastAccess[key1Str] = epochStampWithNodeInfo{
|
||||||
|
epochStamp: epochStamp{
|
||||||
|
epoch: 95,
|
||||||
|
removeFlag: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
key2Str := "02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3"
|
||||||
|
proc.netmapSnapshot.lastAccess[key2Str] = epochStampWithNodeInfo{
|
||||||
|
epochStamp: epochStamp{
|
||||||
|
epoch: 98,
|
||||||
|
removeFlag: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ev := netmapCleanupTick{
|
||||||
|
epoch: 100,
|
||||||
|
txHash: util.Uint256{123},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleCleanupTick(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
keyExp, err := keys.NewPublicKeyFromString(key1Str)
|
||||||
|
require.NoError(t, err, "failed to parse expired key")
|
||||||
|
|
||||||
|
updExp := netmapclient.UpdatePeerPrm{}
|
||||||
|
updExp.SetKey(keyExp.Bytes())
|
||||||
|
updExp.SetHash(ev.TxHash())
|
||||||
|
|
||||||
|
require.EqualValues(t, []netmapclient.UpdatePeerPrm{updExp}, nc.peerStateUpdates, "invalid peer updates")
|
||||||
|
require.True(t, proc.netmapSnapshot.lastAccess[key1Str].removeFlag, "invalid expired removed flag")
|
||||||
|
require.False(t, proc.netmapSnapshot.lastAccess[key2Str].removeFlag, "invalid non expired removed flag")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("notary enabled", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
nc := &testNetmapClient{
|
||||||
|
contractAddress: util.Uint160{111},
|
||||||
|
}
|
||||||
|
proc, err := newTestProc(t,
|
||||||
|
func(p *Params) {
|
||||||
|
p.NetmapClient = nc
|
||||||
|
p.CleanupEnabled = true
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create processor")
|
||||||
|
|
||||||
|
key1Str := "038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35"
|
||||||
|
proc.netmapSnapshot.lastAccess[key1Str] = epochStampWithNodeInfo{
|
||||||
|
epochStamp: epochStamp{
|
||||||
|
epoch: 95,
|
||||||
|
removeFlag: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
key2Str := "02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3"
|
||||||
|
proc.netmapSnapshot.lastAccess[key2Str] = epochStampWithNodeInfo{
|
||||||
|
epochStamp: epochStamp{
|
||||||
|
epoch: 98,
|
||||||
|
removeFlag: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ev := netmapCleanupTick{
|
||||||
|
epoch: 100,
|
||||||
|
txHash: util.Uint256{123},
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.handleCleanupTick(ev)
|
||||||
|
|
||||||
|
for proc.pool.Running() > 0 {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
keyExp, err := keys.NewPublicKeyFromString(key1Str)
|
||||||
|
require.NoError(t, err, "failed to parse expired key")
|
||||||
|
|
||||||
|
updExp := netmapclient.UpdatePeerPrm{}
|
||||||
|
updExp.SetKey(keyExp.Bytes())
|
||||||
|
updExp.SetHash(ev.TxHash())
|
||||||
|
|
||||||
|
require.EqualValues(t, []notaryInvoke{
|
||||||
|
{
|
||||||
|
contract: nc.contractAddress,
|
||||||
|
fee: 0,
|
||||||
|
nonce: uint32(ev.epoch),
|
||||||
|
vub: nil,
|
||||||
|
method: "updateStateIR",
|
||||||
|
args: []any{int64(v2netmap.Offline), keyExp.Bytes()},
|
||||||
|
},
|
||||||
|
}, nc.notaryInvokes, "invalid notary invokes")
|
||||||
|
require.True(t, proc.netmapSnapshot.lastAccess[key1Str].removeFlag, "invalid expired removed flag")
|
||||||
|
require.False(t, proc.netmapSnapshot.lastAccess[key2Str].removeFlag, "invalid non expired removed flag")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestProc(t *testing.T, nonDefault func(p *Params)) (*Processor, error) {
|
||||||
|
ns := &testNodeStateSettings{}
|
||||||
|
es := &testEpochState{}
|
||||||
|
r := &testEpochResetter{}
|
||||||
|
as := &testAlphabetState{
|
||||||
|
isAlphabet: true,
|
||||||
|
}
|
||||||
|
cc := &testContainerClient{}
|
||||||
|
nc := &testNetmapClient{}
|
||||||
|
eh := &testEventHandler{}
|
||||||
|
|
||||||
|
p := &Params{
|
||||||
|
Log: test.NewLogger(t, true),
|
||||||
|
PoolSize: 1,
|
||||||
|
CleanupEnabled: false,
|
||||||
|
CleanupThreshold: 3,
|
||||||
|
NotaryDisabled: false,
|
||||||
|
NodeStateSettings: ns,
|
||||||
|
NodeValidator: &testValidator{},
|
||||||
|
EpochState: es,
|
||||||
|
EpochTimer: r,
|
||||||
|
AlphabetState: as,
|
||||||
|
ContainerWrapper: cc,
|
||||||
|
NetmapClient: nc,
|
||||||
|
NotaryDepositHandler: eh.Handle,
|
||||||
|
HandleAudit: eh.Handle,
|
||||||
|
AuditSettlementsHandler: eh.Handle,
|
||||||
|
AlphabetSyncHandler: eh.Handle,
|
||||||
|
}
|
||||||
|
|
||||||
|
nonDefault(p)
|
||||||
|
|
||||||
|
return New(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
type testNodeStateSettings struct {
|
||||||
|
maintAllowed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testNodeStateSettings) MaintenanceModeAllowed() error {
|
||||||
|
if s.maintAllowed {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("maintenance mode not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
type testValidator struct{}
|
||||||
|
|
||||||
|
func (v *testValidator) VerifyAndUpdate(*netmap.NodeInfo) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testEpochState struct {
|
||||||
|
counter uint64
|
||||||
|
duration uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testEpochState) SetEpochCounter(c uint64) {
|
||||||
|
s.counter = c
|
||||||
|
}
|
||||||
|
func (s *testEpochState) EpochCounter() uint64 {
|
||||||
|
return s.counter
|
||||||
|
}
|
||||||
|
func (s *testEpochState) SetEpochDuration(d uint64) {
|
||||||
|
s.duration = d
|
||||||
|
}
|
||||||
|
func (s *testEpochState) EpochDuration() uint64 {
|
||||||
|
return s.duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type testEpochResetter struct {
|
||||||
|
timers []uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *testEpochResetter) ResetEpochTimer(t uint32) error {
|
||||||
|
r.timers = append(r.timers, t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testAlphabetState struct {
|
||||||
|
isAlphabet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *testAlphabetState) IsAlphabet() bool {
|
||||||
|
return s.isAlphabet
|
||||||
|
}
|
||||||
|
|
||||||
|
type testContainerClient struct {
|
||||||
|
estimations []cntClient.StartEstimationPrm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContainerClient) StartEstimation(p cntClient.StartEstimationPrm) error {
|
||||||
|
c.estimations = append(c.estimations, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type notaryInvoke struct {
|
||||||
|
contract util.Uint160
|
||||||
|
fee fixedn.Fixed8
|
||||||
|
nonce uint32
|
||||||
|
vub *uint32
|
||||||
|
method string
|
||||||
|
args []any
|
||||||
|
}
|
||||||
|
|
||||||
|
type testNetmapClient struct {
|
||||||
|
contractAddress util.Uint160
|
||||||
|
epochDuration uint64
|
||||||
|
netmap *netmap.NetMap
|
||||||
|
txHeights map[util.Uint256]uint32
|
||||||
|
|
||||||
|
peerStateUpdates []netmapclient.UpdatePeerPrm
|
||||||
|
notaryInvokes []notaryInvoke
|
||||||
|
newEpochs []uint64
|
||||||
|
addPeers []netmapclient.AddPeerPrm
|
||||||
|
invokedTxs []*transaction.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testNetmapClient) UpdatePeerState(p netmapclient.UpdatePeerPrm) error {
|
||||||
|
c.peerStateUpdates = append(c.peerStateUpdates, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *testNetmapClient) MorphNotaryInvoke(contract util.Uint160, fee fixedn.Fixed8, nonce uint32, vub *uint32, method string, args ...any) error {
|
||||||
|
c.notaryInvokes = append(c.notaryInvokes, notaryInvoke{
|
||||||
|
contract: contract,
|
||||||
|
fee: fee,
|
||||||
|
nonce: nonce,
|
||||||
|
vub: vub,
|
||||||
|
method: method,
|
||||||
|
args: args,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *testNetmapClient) ContractAddress() util.Uint160 {
|
||||||
|
return c.contractAddress
|
||||||
|
}
|
||||||
|
func (c *testNetmapClient) EpochDuration() (uint64, error) {
|
||||||
|
return c.epochDuration, nil
|
||||||
|
}
|
||||||
|
func (c *testNetmapClient) MorphTxHeight(h util.Uint256) (uint32, error) {
|
||||||
|
if res, found := c.txHeights[h]; found {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("not found")
|
||||||
|
}
|
||||||
|
func (c *testNetmapClient) NetMap() (*netmap.NetMap, error) {
|
||||||
|
return c.netmap, nil
|
||||||
|
}
|
||||||
|
func (c *testNetmapClient) NewEpoch(epoch uint64, force bool) error {
|
||||||
|
c.newEpochs = append(c.newEpochs, epoch)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *testNetmapClient) MorphIsValidScript(script []byte, signers []transaction.Signer) (valid bool, err error) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
func (c *testNetmapClient) AddPeer(p netmapclient.AddPeerPrm) error {
|
||||||
|
c.addPeers = append(c.addPeers, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (c *testNetmapClient) MorphNotarySignAndInvokeTX(mainTx *transaction.Transaction) error {
|
||||||
|
c.invokedTxs = append(c.invokedTxs, mainTx)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type testEventHandler struct {
|
||||||
|
handledEvents []event.Event
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *testEventHandler) Handle(e event.Event) {
|
||||||
|
h.handledEvents = append(h.handledEvents, e)
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ func (np *Processor) processNetmapCleanupTick(ev netmapCleanupTick) {
|
||||||
|
|
||||||
err = np.netmapClient.UpdatePeerState(prm)
|
err = np.netmapClient.UpdatePeerState(prm)
|
||||||
} else {
|
} else {
|
||||||
err = np.netmapClient.Morph().NotaryInvoke(
|
err = np.netmapClient.MorphNotaryInvoke(
|
||||||
np.netmapClient.ContractAddress(),
|
np.netmapClient.ContractAddress(),
|
||||||
0,
|
0,
|
||||||
uint32(ev.epoch),
|
uint32(ev.epoch),
|
||||||
|
|
|
@ -25,7 +25,7 @@ func (np *Processor) processNewEpoch(ev netmapEvent.NewEpoch) {
|
||||||
|
|
||||||
np.epochState.SetEpochCounter(epoch)
|
np.epochState.SetEpochCounter(epoch)
|
||||||
|
|
||||||
h, err := np.netmapClient.Morph().TxHeight(ev.TxHash())
|
h, err := np.netmapClient.MorphTxHeight(ev.TxHash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
np.log.Warn(logs.NetmapCantGetTransactionHeight,
|
np.log.Warn(logs.NetmapCantGetTransactionHeight,
|
||||||
zap.String("hash", ev.TxHash().StringLE()),
|
zap.String("hash", ev.TxHash().StringLE()),
|
||||||
|
|
|
@ -21,7 +21,7 @@ func (np *Processor) processAddPeer(ev netmapEvent.AddPeer) {
|
||||||
// check if notary transaction is valid, see #976
|
// check if notary transaction is valid, see #976
|
||||||
if originalRequest := ev.NotaryRequest(); originalRequest != nil {
|
if originalRequest := ev.NotaryRequest(); originalRequest != nil {
|
||||||
tx := originalRequest.MainTransaction
|
tx := originalRequest.MainTransaction
|
||||||
ok, err := np.netmapClient.Morph().IsValidScript(tx.Script, tx.Signers)
|
ok, err := np.netmapClient.MorphIsValidScript(tx.Script, tx.Signers)
|
||||||
if err != nil || !ok {
|
if err != nil || !ok {
|
||||||
np.log.Warn(logs.NetmapNonhaltNotaryTransaction,
|
np.log.Warn(logs.NetmapNonhaltNotaryTransaction,
|
||||||
zap.String("method", "netmap.AddPeer"),
|
zap.String("method", "netmap.AddPeer"),
|
||||||
|
@ -73,7 +73,7 @@ func (np *Processor) processAddPeer(ev netmapEvent.AddPeer) {
|
||||||
|
|
||||||
if nr := ev.NotaryRequest(); nr != nil {
|
if nr := ev.NotaryRequest(); nr != nil {
|
||||||
// create new notary request with the original nonce
|
// create new notary request with the original nonce
|
||||||
err = np.netmapClient.Morph().NotaryInvoke(
|
err = np.netmapClient.MorphNotaryInvoke(
|
||||||
np.netmapClient.ContractAddress(),
|
np.netmapClient.ContractAddress(),
|
||||||
0,
|
0,
|
||||||
nr.MainTransaction.Nonce,
|
nr.MainTransaction.Nonce,
|
||||||
|
@ -117,7 +117,7 @@ func (np *Processor) processUpdatePeer(ev netmapEvent.UpdatePeer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if nr := ev.NotaryRequest(); nr != nil {
|
if nr := ev.NotaryRequest(); nr != nil {
|
||||||
err = np.netmapClient.Morph().NotarySignAndInvokeTX(nr.MainTransaction)
|
err = np.netmapClient.MorphNotarySignAndInvokeTX(nr.MainTransaction)
|
||||||
} else {
|
} else {
|
||||||
prm := netmapclient.UpdatePeerPrm{}
|
prm := netmapclient.UpdatePeerPrm{}
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,16 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/state"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/state"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
netmapclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -51,6 +54,23 @@ type (
|
||||||
VerifyAndUpdate(*netmap.NodeInfo) error
|
VerifyAndUpdate(*netmap.NodeInfo) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Client interface {
|
||||||
|
UpdatePeerState(p netmapclient.UpdatePeerPrm) error
|
||||||
|
MorphNotaryInvoke(contract util.Uint160, fee fixedn.Fixed8, nonce uint32, vub *uint32, method string, args ...any) error
|
||||||
|
ContractAddress() util.Uint160
|
||||||
|
EpochDuration() (uint64, error)
|
||||||
|
MorphTxHeight(h util.Uint256) (res uint32, err error)
|
||||||
|
NetMap() (*netmap.NetMap, error)
|
||||||
|
NewEpoch(epoch uint64, force bool) error
|
||||||
|
MorphIsValidScript(script []byte, signers []transaction.Signer) (valid bool, err error)
|
||||||
|
AddPeer(p netmapclient.AddPeerPrm) error
|
||||||
|
MorphNotarySignAndInvokeTX(mainTx *transaction.Transaction) error
|
||||||
|
}
|
||||||
|
|
||||||
|
ContainerClient interface {
|
||||||
|
StartEstimation(p cntClient.StartEstimationPrm) error
|
||||||
|
}
|
||||||
|
|
||||||
// Processor of events produced by network map contract
|
// Processor of events produced by network map contract
|
||||||
// and new epoch ticker, because it is related to contract.
|
// and new epoch ticker, because it is related to contract.
|
||||||
Processor struct {
|
Processor struct {
|
||||||
|
@ -60,8 +80,8 @@ type (
|
||||||
epochState EpochState
|
epochState EpochState
|
||||||
alphabetState AlphabetState
|
alphabetState AlphabetState
|
||||||
|
|
||||||
netmapClient *nmClient.Client
|
netmapClient Client
|
||||||
containerWrp *container.Client
|
containerWrp ContainerClient
|
||||||
|
|
||||||
netmapSnapshot cleanupTable
|
netmapSnapshot cleanupTable
|
||||||
|
|
||||||
|
@ -81,13 +101,13 @@ type (
|
||||||
Params struct {
|
Params struct {
|
||||||
Log *logger.Logger
|
Log *logger.Logger
|
||||||
PoolSize int
|
PoolSize int
|
||||||
NetmapClient *nmClient.Client
|
NetmapClient Client
|
||||||
EpochTimer EpochTimerReseter
|
EpochTimer EpochTimerReseter
|
||||||
EpochState EpochState
|
EpochState EpochState
|
||||||
AlphabetState AlphabetState
|
AlphabetState AlphabetState
|
||||||
CleanupEnabled bool
|
CleanupEnabled bool
|
||||||
CleanupThreshold uint64 // in epochs
|
CleanupThreshold uint64 // in epochs
|
||||||
ContainerWrapper *container.Client
|
ContainerWrapper ContainerClient
|
||||||
|
|
||||||
HandleAudit event.Handler
|
HandleAudit event.Handler
|
||||||
AuditSettlementsHandler event.Handler
|
AuditSettlementsHandler event.Handler
|
||||||
|
|
59
pkg/innerring/processors/netmap/wrappers.go
Normal file
59
pkg/innerring/processors/netmap/wrappers.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package netmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
netmapclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewNetmapClient(netmapClient *netmapclient.Client) Client {
|
||||||
|
return &netmapClientWrapper{
|
||||||
|
netmapClient: netmapClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type netmapClientWrapper struct {
|
||||||
|
netmapClient *netmapclient.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) UpdatePeerState(p netmapclient.UpdatePeerPrm) error {
|
||||||
|
return w.netmapClient.UpdatePeerState(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) MorphNotaryInvoke(contract util.Uint160, fee fixedn.Fixed8, nonce uint32, vub *uint32, method string, args ...any) error {
|
||||||
|
return w.netmapClient.Morph().NotaryInvoke(contract, fee, nonce, vub, method, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) ContractAddress() util.Uint160 {
|
||||||
|
return w.netmapClient.ContractAddress()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) EpochDuration() (uint64, error) {
|
||||||
|
return w.netmapClient.EpochDuration()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) MorphTxHeight(h util.Uint256) (res uint32, err error) {
|
||||||
|
return w.netmapClient.Morph().TxHeight(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) NetMap() (*netmap.NetMap, error) {
|
||||||
|
return w.netmapClient.NetMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) NewEpoch(epoch uint64, force bool) error {
|
||||||
|
return w.netmapClient.NewEpoch(epoch, force)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) MorphIsValidScript(script []byte, signers []transaction.Signer) (valid bool, err error) {
|
||||||
|
return w.netmapClient.Morph().IsValidScript(script, signers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) AddPeer(p netmapclient.AddPeerPrm) error {
|
||||||
|
return w.netmapClient.AddPeer(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *netmapClientWrapper) MorphNotarySignAndInvokeTX(mainTx *transaction.Transaction) error {
|
||||||
|
return w.netmapClient.Morph().NotarySignAndInvokeTX(mainTx)
|
||||||
|
}
|
53
pkg/innerring/state_test.go
Normal file
53
pkg/innerring/state_test.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package innerring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||||
|
control "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/ir"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServerState(t *testing.T) {
|
||||||
|
keyStr := "03ff65b6ae79134a4dce9d0d39d3851e9bab4ee97abf86e81e1c5bbc50cd2826ae"
|
||||||
|
commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{keyStr})
|
||||||
|
require.NoError(t, err, "convert string to commitee public keys failed")
|
||||||
|
cf := &testCommiteeFetcher{
|
||||||
|
keys: commiteeKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
irKeys, err := keys.NewPublicKeysFromStrings([]string{keyStr})
|
||||||
|
require.NoError(t, err, "convert string to IR public keys failed")
|
||||||
|
irf := &testIRFetcher{
|
||||||
|
keys: irKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := keys.NewPublicKeyFromString(keyStr)
|
||||||
|
require.NoError(t, err, "convert string to public key failed")
|
||||||
|
|
||||||
|
require.NoError(t, err, "failed to create morph client")
|
||||||
|
srv := &Server{
|
||||||
|
statusIndex: newInnerRingIndexer(cf, irf, key, time.Second),
|
||||||
|
morphClient: &client.Client{},
|
||||||
|
}
|
||||||
|
|
||||||
|
var epoch uint64 = 100
|
||||||
|
srv.SetEpochCounter(epoch)
|
||||||
|
require.Equal(t, epoch, srv.EpochCounter(), "invalid epoch counter")
|
||||||
|
|
||||||
|
var epochDuration uint64 = 15
|
||||||
|
srv.SetEpochDuration(epochDuration)
|
||||||
|
require.Equal(t, epochDuration, srv.EpochDuration(), "invalid epoch duration")
|
||||||
|
|
||||||
|
var healthStatus control.HealthStatus = control.HealthStatus_READY
|
||||||
|
srv.setHealthStatus(healthStatus)
|
||||||
|
require.Equal(t, healthStatus, srv.HealthStatus(), "invalid health status")
|
||||||
|
|
||||||
|
require.True(t, srv.IsActive(), "invalid IsActive result")
|
||||||
|
require.True(t, srv.IsAlphabet(), "invalid IsAlphabet result")
|
||||||
|
require.Equal(t, 0, srv.InnerRingIndex(), "invalid IR index")
|
||||||
|
require.Equal(t, 1, srv.InnerRingSize(), "invalid IR index")
|
||||||
|
require.Equal(t, 0, srv.AlphabetIndex(), "invalid alphabet index")
|
||||||
|
}
|
|
@ -26,8 +26,12 @@ func AsContainerSource(w *Client) containercore.Source {
|
||||||
return (*containerSource)(w)
|
return (*containerSource)(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type getContainer interface {
|
||||||
|
Get(cid []byte) (*containercore.Container, error)
|
||||||
|
}
|
||||||
|
|
||||||
// Get marshals container ID, and passes it to Wrapper's Get method.
|
// Get marshals container ID, and passes it to Wrapper's Get method.
|
||||||
func Get(c *Client, cnr cid.ID) (*containercore.Container, error) {
|
func Get(c getContainer, cnr cid.ID) (*containercore.Container, error) {
|
||||||
binCnr := make([]byte, sha256.Size)
|
binCnr := make([]byte, sha256.Size)
|
||||||
cnr.Encode(binCnr)
|
cnr.Encode(binCnr)
|
||||||
|
|
||||||
|
|
|
@ -12,34 +12,34 @@ import (
|
||||||
|
|
||||||
// Delete structure of container.Delete notification from morph chain.
|
// Delete structure of container.Delete notification from morph chain.
|
||||||
type Delete struct {
|
type Delete struct {
|
||||||
containerID []byte
|
ContainerIDValue []byte
|
||||||
signature []byte
|
SignatureValue []byte
|
||||||
token []byte
|
TokenValue []byte
|
||||||
|
|
||||||
// For notary notifications only.
|
// For notary notifications only.
|
||||||
// Contains raw transactions of notary request.
|
// Contains raw transactions of notary request.
|
||||||
notaryRequest *payload.P2PNotaryRequest
|
NotaryRequestValue *payload.P2PNotaryRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
func (Delete) MorphEvent() {}
|
func (Delete) MorphEvent() {}
|
||||||
|
|
||||||
// ContainerID is a marshalled container structure, defined in API.
|
// ContainerID is a marshalled container structure, defined in API.
|
||||||
func (d Delete) ContainerID() []byte { return d.containerID }
|
func (d Delete) ContainerID() []byte { return d.ContainerIDValue }
|
||||||
|
|
||||||
// Signature of marshalled container by container owner.
|
// Signature of marshalled container by container owner.
|
||||||
func (d Delete) Signature() []byte { return d.signature }
|
func (d Delete) Signature() []byte { return d.SignatureValue }
|
||||||
|
|
||||||
// SessionToken returns binary token of the session
|
// SessionToken returns binary token of the session
|
||||||
// within which the eACL was set.
|
// within which the eACL was set.
|
||||||
func (d Delete) SessionToken() []byte {
|
func (d Delete) SessionToken() []byte {
|
||||||
return d.token
|
return d.TokenValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotaryRequest returns raw notary request if notification
|
// NotaryRequest returns raw notary request if notification
|
||||||
// was received via notary service. Otherwise, returns nil.
|
// was received via notary service. Otherwise, returns nil.
|
||||||
func (d Delete) NotaryRequest() *payload.P2PNotaryRequest {
|
func (d Delete) NotaryRequest() *payload.P2PNotaryRequest {
|
||||||
return d.notaryRequest
|
return d.NotaryRequestValue
|
||||||
}
|
}
|
||||||
|
|
||||||
const expectedItemNumDelete = 3
|
const expectedItemNumDelete = 3
|
||||||
|
@ -63,19 +63,19 @@ func ParseDelete(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse container
|
// parse container
|
||||||
ev.containerID, err = client.BytesFromStackItem(params[0])
|
ev.ContainerIDValue, err = client.BytesFromStackItem(params[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get container: %w", err)
|
return nil, fmt.Errorf("could not get container: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse signature
|
// parse signature
|
||||||
ev.signature, err = client.BytesFromStackItem(params[1])
|
ev.SignatureValue, err = client.BytesFromStackItem(params[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get signature: %w", err)
|
return nil, fmt.Errorf("could not get signature: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse session token
|
// parse session token
|
||||||
ev.token, err = client.BytesFromStackItem(params[2])
|
ev.TokenValue, err = client.BytesFromStackItem(params[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get session token: %w", err)
|
return nil, fmt.Errorf("could not get session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,19 +7,19 @@ import (
|
||||||
|
|
||||||
func (d *Delete) setContainerID(v []byte) {
|
func (d *Delete) setContainerID(v []byte) {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
d.containerID = v
|
d.ContainerIDValue = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Delete) setSignature(v []byte) {
|
func (d *Delete) setSignature(v []byte) {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
d.signature = v
|
d.SignatureValue = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Delete) setToken(v []byte) {
|
func (d *Delete) setToken(v []byte) {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
d.token = v
|
d.TokenValue = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func ParseDeleteNotary(ne event.NotaryEvent) (event.Event, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.notaryRequest = ne.Raw()
|
ev.NotaryRequestValue = ne.Raw()
|
||||||
|
|
||||||
return ev, nil
|
return ev, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,9 +63,9 @@ func TestParseDelete(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, Delete{
|
require.Equal(t, Delete{
|
||||||
containerID: containerID,
|
ContainerIDValue: containerID,
|
||||||
signature: signature,
|
SignatureValue: signature,
|
||||||
token: token,
|
TokenValue: token,
|
||||||
}, ev)
|
}, ev)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,14 +12,14 @@ import (
|
||||||
// SetEACL represents structure of notification about
|
// SetEACL represents structure of notification about
|
||||||
// modified eACL table coming from FrostFS Container contract.
|
// modified eACL table coming from FrostFS Container contract.
|
||||||
type SetEACL struct {
|
type SetEACL struct {
|
||||||
table []byte
|
TableValue []byte
|
||||||
signature []byte
|
SignatureValue []byte
|
||||||
publicKey []byte
|
PublicKeyValue []byte
|
||||||
token []byte
|
TokenValue []byte
|
||||||
|
|
||||||
// For notary notifications only.
|
// For notary notifications only.
|
||||||
// Contains raw transactions of notary request.
|
// Contains raw transactions of notary request.
|
||||||
notaryRequest *payload.P2PNotaryRequest
|
NotaryRequestValue *payload.P2PNotaryRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
|
@ -27,30 +27,30 @@ func (SetEACL) MorphEvent() {}
|
||||||
|
|
||||||
// Table returns returns eACL table in a binary FrostFS API format.
|
// Table returns returns eACL table in a binary FrostFS API format.
|
||||||
func (x SetEACL) Table() []byte {
|
func (x SetEACL) Table() []byte {
|
||||||
return x.table
|
return x.TableValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signature returns signature of the binary table.
|
// Signature returns signature of the binary table.
|
||||||
func (x SetEACL) Signature() []byte {
|
func (x SetEACL) Signature() []byte {
|
||||||
return x.signature
|
return x.SignatureValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicKey returns public keys of container
|
// PublicKey returns public keys of container
|
||||||
// owner in a binary format.
|
// owner in a binary format.
|
||||||
func (x SetEACL) PublicKey() []byte {
|
func (x SetEACL) PublicKey() []byte {
|
||||||
return x.publicKey
|
return x.PublicKeyValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionToken returns binary token of the session
|
// SessionToken returns binary token of the session
|
||||||
// within which the eACL was set.
|
// within which the eACL was set.
|
||||||
func (x SetEACL) SessionToken() []byte {
|
func (x SetEACL) SessionToken() []byte {
|
||||||
return x.token
|
return x.TokenValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotaryRequest returns raw notary request if notification
|
// NotaryRequest returns raw notary request if notification
|
||||||
// was received via notary service. Otherwise, returns nil.
|
// was received via notary service. Otherwise, returns nil.
|
||||||
func (x SetEACL) NotaryRequest() *payload.P2PNotaryRequest {
|
func (x SetEACL) NotaryRequest() *payload.P2PNotaryRequest {
|
||||||
return x.notaryRequest
|
return x.NotaryRequestValue
|
||||||
}
|
}
|
||||||
|
|
||||||
const expectedItemNumEACL = 4
|
const expectedItemNumEACL = 4
|
||||||
|
@ -74,25 +74,25 @@ func ParseSetEACL(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse table
|
// parse table
|
||||||
ev.table, err = client.BytesFromStackItem(params[0])
|
ev.TableValue, err = client.BytesFromStackItem(params[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse binary table: %w", err)
|
return nil, fmt.Errorf("could not parse binary table: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse signature
|
// parse signature
|
||||||
ev.signature, err = client.BytesFromStackItem(params[1])
|
ev.SignatureValue, err = client.BytesFromStackItem(params[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse table signature: %w", err)
|
return nil, fmt.Errorf("could not parse table signature: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse public key
|
// parse public key
|
||||||
ev.publicKey, err = client.BytesFromStackItem(params[2])
|
ev.PublicKeyValue, err = client.BytesFromStackItem(params[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse binary public key: %w", err)
|
return nil, fmt.Errorf("could not parse binary public key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse session token
|
// parse session token
|
||||||
ev.token, err = client.BytesFromStackItem(params[3])
|
ev.TokenValue, err = client.BytesFromStackItem(params[3])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get session token: %w", err)
|
return nil, fmt.Errorf("could not get session token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,25 +7,25 @@ import (
|
||||||
|
|
||||||
func (x *SetEACL) setTable(v []byte) {
|
func (x *SetEACL) setTable(v []byte) {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
x.table = v
|
x.TableValue = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SetEACL) setSignature(v []byte) {
|
func (x *SetEACL) setSignature(v []byte) {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
x.signature = v
|
x.SignatureValue = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SetEACL) setPublicKey(v []byte) {
|
func (x *SetEACL) setPublicKey(v []byte) {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
x.publicKey = v
|
x.PublicKeyValue = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SetEACL) setToken(v []byte) {
|
func (x *SetEACL) setToken(v []byte) {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
x.token = v
|
x.TokenValue = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ func ParseSetEACLNotary(ne event.NotaryEvent) (event.Event, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.notaryRequest = ne.Raw()
|
ev.NotaryRequestValue = ne.Raw()
|
||||||
|
|
||||||
return ev, nil
|
return ev, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,31 +11,31 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Bind struct {
|
type Bind struct {
|
||||||
bindCommon
|
BindCommon
|
||||||
}
|
}
|
||||||
|
|
||||||
type bindCommon struct {
|
type BindCommon struct {
|
||||||
user []byte
|
UserValue []byte
|
||||||
keys [][]byte
|
KeysValue [][]byte
|
||||||
|
|
||||||
// txHash is used in notary environmental
|
// TxHashValue is used in notary environmental
|
||||||
// for calculating unique but same for
|
// for calculating unique but same for
|
||||||
// all notification receivers values.
|
// all notification receivers values.
|
||||||
txHash util.Uint256
|
TxHashValue util.Uint256
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxHash returns hash of the TX with new epoch
|
// TxHash returns hash of the TX with new epoch
|
||||||
// notification.
|
// notification.
|
||||||
func (b bindCommon) TxHash() util.Uint256 {
|
func (b BindCommon) TxHash() util.Uint256 {
|
||||||
return b.txHash
|
return b.TxHashValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
func (bindCommon) MorphEvent() {}
|
func (BindCommon) MorphEvent() {}
|
||||||
|
|
||||||
func (b bindCommon) Keys() [][]byte { return b.keys }
|
func (b BindCommon) Keys() [][]byte { return b.KeysValue }
|
||||||
|
|
||||||
func (b bindCommon) User() []byte { return b.user }
|
func (b BindCommon) User() []byte { return b.UserValue }
|
||||||
|
|
||||||
func ParseBind(e *state.ContainedNotificationEvent) (event.Event, error) {
|
func ParseBind(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
var (
|
var (
|
||||||
|
@ -48,17 +48,17 @@ func ParseBind(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
return nil, fmt.Errorf("could not parse stack items from notify event: %w", err)
|
return nil, fmt.Errorf("could not parse stack items from notify event: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = parseBind(&ev.bindCommon, params)
|
err = parseBind(&ev.BindCommon, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.txHash = e.Container
|
ev.TxHashValue = e.Container
|
||||||
|
|
||||||
return ev, nil
|
return ev, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseBind(dst *bindCommon, params []stackitem.Item) error {
|
func parseBind(dst *BindCommon, params []stackitem.Item) error {
|
||||||
if ln := len(params); ln != 2 {
|
if ln := len(params); ln != 2 {
|
||||||
return event.WrongNumberOfParameters(2, ln)
|
return event.WrongNumberOfParameters(2, ln)
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ func parseBind(dst *bindCommon, params []stackitem.Item) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// parse user
|
// parse user
|
||||||
dst.user, err = client.BytesFromStackItem(params[0])
|
dst.UserValue, err = client.BytesFromStackItem(params[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not get bind user: %w", err)
|
return fmt.Errorf("could not get bind user: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func parseBind(dst *bindCommon, params []stackitem.Item) error {
|
||||||
return fmt.Errorf("could not get bind keys: %w", err)
|
return fmt.Errorf("could not get bind keys: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dst.keys = make([][]byte, 0, len(bindKeys))
|
dst.KeysValue = make([][]byte, 0, len(bindKeys))
|
||||||
|
|
||||||
for i := range bindKeys {
|
for i := range bindKeys {
|
||||||
rawKey, err := client.BytesFromStackItem(bindKeys[i])
|
rawKey, err := client.BytesFromStackItem(bindKeys[i])
|
||||||
|
@ -85,7 +85,7 @@ func parseBind(dst *bindCommon, params []stackitem.Item) error {
|
||||||
return fmt.Errorf("could not get bind public key: %w", err)
|
return fmt.Errorf("could not get bind public key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dst.keys = append(dst.keys, rawKey)
|
dst.KeysValue = append(dst.KeysValue, rawKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -11,26 +11,26 @@ import (
|
||||||
|
|
||||||
// Cheque structure of frostfs.Cheque notification from mainnet chain.
|
// Cheque structure of frostfs.Cheque notification from mainnet chain.
|
||||||
type Cheque struct {
|
type Cheque struct {
|
||||||
id []byte
|
IDValue []byte
|
||||||
amount int64 // Fixed8
|
AmountValue int64 // Fixed8
|
||||||
user util.Uint160
|
UserValue util.Uint160
|
||||||
lock util.Uint160
|
LockValue util.Uint160
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
func (Cheque) MorphEvent() {}
|
func (Cheque) MorphEvent() {}
|
||||||
|
|
||||||
// ID is a withdraw transaction hash.
|
// ID is a withdraw transaction hash.
|
||||||
func (c Cheque) ID() []byte { return c.id }
|
func (c Cheque) ID() []byte { return c.IDValue }
|
||||||
|
|
||||||
// User returns withdraw receiver script hash from main net.
|
// User returns withdraw receiver script hash from main net.
|
||||||
func (c Cheque) User() util.Uint160 { return c.user }
|
func (c Cheque) User() util.Uint160 { return c.UserValue }
|
||||||
|
|
||||||
// Amount of the sent assets.
|
// Amount of the sent assets.
|
||||||
func (c Cheque) Amount() int64 { return c.amount }
|
func (c Cheque) Amount() int64 { return c.AmountValue }
|
||||||
|
|
||||||
// LockAccount return script hash for balance contract wallet.
|
// LockAccount return script hash for balance contract wallet.
|
||||||
func (c Cheque) LockAccount() util.Uint160 { return c.lock }
|
func (c Cheque) LockAccount() util.Uint160 { return c.LockValue }
|
||||||
|
|
||||||
// ParseCheque from notification into cheque structure.
|
// ParseCheque from notification into cheque structure.
|
||||||
func ParseCheque(e *state.ContainedNotificationEvent) (event.Event, error) {
|
func ParseCheque(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
|
@ -49,7 +49,7 @@ func ParseCheque(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse id
|
// parse id
|
||||||
ev.id, err = client.BytesFromStackItem(params[0])
|
ev.IDValue, err = client.BytesFromStackItem(params[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get cheque id: %w", err)
|
return nil, fmt.Errorf("could not get cheque id: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -60,13 +60,13 @@ func ParseCheque(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
return nil, fmt.Errorf("could not get cheque user: %w", err)
|
return nil, fmt.Errorf("could not get cheque user: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.user, err = util.Uint160DecodeBytesBE(user)
|
ev.UserValue, err = util.Uint160DecodeBytesBE(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not convert cheque user to uint160: %w", err)
|
return nil, fmt.Errorf("could not convert cheque user to uint160: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse amount
|
// parse amount
|
||||||
ev.amount, err = client.IntFromStackItem(params[2])
|
ev.AmountValue, err = client.IntFromStackItem(params[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get cheque amount: %w", err)
|
return nil, fmt.Errorf("could not get cheque amount: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func ParseCheque(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
return nil, fmt.Errorf("could not get cheque lock account: %w", err)
|
return nil, fmt.Errorf("could not get cheque lock account: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.lock, err = util.Uint160DecodeBytesBE(lock)
|
ev.LockValue, err = util.Uint160DecodeBytesBE(lock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not convert cheque lock account to uint160: %w", err)
|
return nil, fmt.Errorf("could not convert cheque lock account to uint160: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,10 +77,10 @@ func TestParseCheque(t *testing.T) {
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, Cheque{
|
require.Equal(t, Cheque{
|
||||||
id: id,
|
IDValue: id,
|
||||||
amount: amount,
|
AmountValue: amount,
|
||||||
user: user,
|
UserValue: user,
|
||||||
lock: lock,
|
LockValue: lock,
|
||||||
}, ev)
|
}, ev)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,30 +10,30 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
key []byte
|
KeyValue []byte
|
||||||
value []byte
|
ValueValue []byte
|
||||||
id []byte
|
IDValue []byte
|
||||||
|
|
||||||
// txHash is used in notary environmental
|
// TxHashValue is used in notary environmental
|
||||||
// for calculating unique but same for
|
// for calculating unique but same for
|
||||||
// all notification receivers values.
|
// all notification receivers values.
|
||||||
txHash util.Uint256
|
TxHashValue util.Uint256
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxHash returns hash of the TX with new epoch
|
// TxHash returns hash of the TX with new epoch
|
||||||
// notification.
|
// notification.
|
||||||
func (u Config) TxHash() util.Uint256 {
|
func (u Config) TxHash() util.Uint256 {
|
||||||
return u.txHash
|
return u.TxHashValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
func (Config) MorphEvent() {}
|
func (Config) MorphEvent() {}
|
||||||
|
|
||||||
func (u Config) ID() []byte { return u.id }
|
func (u Config) ID() []byte { return u.IDValue }
|
||||||
|
|
||||||
func (u Config) Key() []byte { return u.key }
|
func (u Config) Key() []byte { return u.KeyValue }
|
||||||
|
|
||||||
func (u Config) Value() []byte { return u.value }
|
func (u Config) Value() []byte { return u.ValueValue }
|
||||||
|
|
||||||
func ParseConfig(e *state.ContainedNotificationEvent) (event.Event, error) {
|
func ParseConfig(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
var (
|
var (
|
||||||
|
@ -51,24 +51,24 @@ func ParseConfig(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse id
|
// parse id
|
||||||
ev.id, err = client.BytesFromStackItem(params[0])
|
ev.IDValue, err = client.BytesFromStackItem(params[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get config update id: %w", err)
|
return nil, fmt.Errorf("could not get config update id: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse key
|
// parse key
|
||||||
ev.key, err = client.BytesFromStackItem(params[1])
|
ev.KeyValue, err = client.BytesFromStackItem(params[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get config key: %w", err)
|
return nil, fmt.Errorf("could not get config key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse value
|
// parse value
|
||||||
ev.value, err = client.BytesFromStackItem(params[2])
|
ev.ValueValue, err = client.BytesFromStackItem(params[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get config value: %w", err)
|
return nil, fmt.Errorf("could not get config value: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.txHash = e.Container
|
ev.TxHashValue = e.Container
|
||||||
|
|
||||||
return ev, nil
|
return ev, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,9 +60,9 @@ func TestParseConfig(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, Config{
|
require.Equal(t, Config{
|
||||||
id: id,
|
IDValue: id,
|
||||||
key: key,
|
KeyValue: key,
|
||||||
value: value,
|
ValueValue: value,
|
||||||
}, ev)
|
}, ev)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,26 +11,26 @@ import (
|
||||||
|
|
||||||
// Deposit structure of frostfs.Deposit notification from mainnet chain.
|
// Deposit structure of frostfs.Deposit notification from mainnet chain.
|
||||||
type Deposit struct {
|
type Deposit struct {
|
||||||
id []byte
|
IDValue []byte
|
||||||
amount int64 // Fixed8
|
AmountValue int64 // Fixed8
|
||||||
from util.Uint160
|
FromValue util.Uint160
|
||||||
to util.Uint160
|
ToValue util.Uint160
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
func (Deposit) MorphEvent() {}
|
func (Deposit) MorphEvent() {}
|
||||||
|
|
||||||
// ID is a deposit transaction hash.
|
// ID is a deposit transaction hash.
|
||||||
func (d Deposit) ID() []byte { return d.id }
|
func (d Deposit) ID() []byte { return d.IDValue }
|
||||||
|
|
||||||
// From is a script hash of asset sender in main net.
|
// From is a script hash of asset sender in main net.
|
||||||
func (d Deposit) From() util.Uint160 { return d.from }
|
func (d Deposit) From() util.Uint160 { return d.FromValue }
|
||||||
|
|
||||||
// To is a script hash of asset receiver in balance contract.
|
// To is a script hash of asset receiver in balance contract.
|
||||||
func (d Deposit) To() util.Uint160 { return d.to }
|
func (d Deposit) To() util.Uint160 { return d.ToValue }
|
||||||
|
|
||||||
// Amount of transferred assets.
|
// Amount of transferred assets.
|
||||||
func (d Deposit) Amount() int64 { return d.amount }
|
func (d Deposit) Amount() int64 { return d.AmountValue }
|
||||||
|
|
||||||
// ParseDeposit notification into deposit structure.
|
// ParseDeposit notification into deposit structure.
|
||||||
func ParseDeposit(e *state.ContainedNotificationEvent) (event.Event, error) {
|
func ParseDeposit(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
|
@ -51,13 +51,13 @@ func ParseDeposit(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
return nil, fmt.Errorf("could not get deposit sender: %w", err)
|
return nil, fmt.Errorf("could not get deposit sender: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.from, err = util.Uint160DecodeBytesBE(from)
|
ev.FromValue, err = util.Uint160DecodeBytesBE(from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not convert deposit sender to uint160: %w", err)
|
return nil, fmt.Errorf("could not convert deposit sender to uint160: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse amount
|
// parse amount
|
||||||
ev.amount, err = client.IntFromStackItem(params[1])
|
ev.AmountValue, err = client.IntFromStackItem(params[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get deposit amount: %w", err)
|
return nil, fmt.Errorf("could not get deposit amount: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -68,13 +68,13 @@ func ParseDeposit(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
return nil, fmt.Errorf("could not get deposit receiver: %w", err)
|
return nil, fmt.Errorf("could not get deposit receiver: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.to, err = util.Uint160DecodeBytesBE(to)
|
ev.ToValue, err = util.Uint160DecodeBytesBE(to)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not convert deposit receiver to uint160: %w", err)
|
return nil, fmt.Errorf("could not convert deposit receiver to uint160: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse id
|
// parse id
|
||||||
ev.id, err = client.BytesFromStackItem(params[3])
|
ev.IDValue, err = client.BytesFromStackItem(params[3])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get deposit id: %w", err)
|
return nil, fmt.Errorf("could not get deposit id: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,10 +77,10 @@ func TestParseDeposit(t *testing.T) {
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, Deposit{
|
require.Equal(t, Deposit{
|
||||||
id: id,
|
IDValue: id,
|
||||||
amount: amount,
|
AmountValue: amount,
|
||||||
from: from,
|
FromValue: from,
|
||||||
to: to,
|
ToValue: to,
|
||||||
}, ev)
|
}, ev)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Unbind struct {
|
type Unbind struct {
|
||||||
bindCommon
|
BindCommon
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseUnbind(e *state.ContainedNotificationEvent) (event.Event, error) {
|
func ParseUnbind(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
|
@ -22,12 +22,12 @@ func ParseUnbind(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
return nil, fmt.Errorf("could not parse stack items from notify event: %w", err)
|
return nil, fmt.Errorf("could not parse stack items from notify event: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = parseBind(&ev.bindCommon, params)
|
err = parseBind(&ev.BindCommon, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.txHash = e.Container
|
ev.TxHashValue = e.Container
|
||||||
|
|
||||||
return ev, nil
|
return ev, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,22 +11,22 @@ import (
|
||||||
|
|
||||||
// Withdraw structure of frostfs.Withdraw notification from mainnet chain.
|
// Withdraw structure of frostfs.Withdraw notification from mainnet chain.
|
||||||
type Withdraw struct {
|
type Withdraw struct {
|
||||||
id []byte
|
IDValue []byte
|
||||||
amount int64 // Fixed8
|
AmountValue int64 // Fixed8
|
||||||
user util.Uint160
|
UserValue util.Uint160
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
func (Withdraw) MorphEvent() {}
|
func (Withdraw) MorphEvent() {}
|
||||||
|
|
||||||
// ID is a withdraw transaction hash.
|
// ID is a withdraw transaction hash.
|
||||||
func (w Withdraw) ID() []byte { return w.id }
|
func (w Withdraw) ID() []byte { return w.IDValue }
|
||||||
|
|
||||||
// User returns withdraw receiver script hash from main net.
|
// User returns withdraw receiver script hash from main net.
|
||||||
func (w Withdraw) User() util.Uint160 { return w.user }
|
func (w Withdraw) User() util.Uint160 { return w.UserValue }
|
||||||
|
|
||||||
// Amount of the withdraw assets.
|
// Amount of the withdraw assets.
|
||||||
func (w Withdraw) Amount() int64 { return w.amount }
|
func (w Withdraw) Amount() int64 { return w.AmountValue }
|
||||||
|
|
||||||
// ParseWithdraw notification into withdraw structure.
|
// ParseWithdraw notification into withdraw structure.
|
||||||
func ParseWithdraw(e *state.ContainedNotificationEvent) (event.Event, error) {
|
func ParseWithdraw(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
|
@ -47,19 +47,19 @@ func ParseWithdraw(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
return nil, fmt.Errorf("could not get withdraw user: %w", err)
|
return nil, fmt.Errorf("could not get withdraw user: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.user, err = util.Uint160DecodeBytesBE(user)
|
ev.UserValue, err = util.Uint160DecodeBytesBE(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not convert withdraw user to uint160: %w", err)
|
return nil, fmt.Errorf("could not convert withdraw user to uint160: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse amount
|
// parse amount
|
||||||
ev.amount, err = client.IntFromStackItem(params[1])
|
ev.AmountValue, err = client.IntFromStackItem(params[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get withdraw amount: %w", err)
|
return nil, fmt.Errorf("could not get withdraw amount: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse id
|
// parse id
|
||||||
ev.id, err = client.BytesFromStackItem(params[2])
|
ev.IDValue, err = client.BytesFromStackItem(params[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get withdraw id: %w", err)
|
return nil, fmt.Errorf("could not get withdraw id: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,9 @@ func TestParseWithdraw(t *testing.T) {
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, Withdraw{
|
require.Equal(t, Withdraw{
|
||||||
id: id,
|
IDValue: id,
|
||||||
amount: amount,
|
AmountValue: amount,
|
||||||
user: user,
|
UserValue: user,
|
||||||
}, ev)
|
}, ev)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,24 +10,24 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type AddPeer struct {
|
type AddPeer struct {
|
||||||
node []byte
|
NodeBytes []byte
|
||||||
|
|
||||||
// For notary notifications only.
|
// For notary notifications only.
|
||||||
// Contains raw transactions of notary request.
|
// Contains raw transactions of notary request.
|
||||||
notaryRequest *payload.P2PNotaryRequest
|
Request *payload.P2PNotaryRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
func (AddPeer) MorphEvent() {}
|
func (AddPeer) MorphEvent() {}
|
||||||
|
|
||||||
func (s AddPeer) Node() []byte {
|
func (s AddPeer) Node() []byte {
|
||||||
return s.node
|
return s.NodeBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotaryRequest returns raw notary request if notification
|
// NotaryRequest returns raw notary request if notification
|
||||||
// was received via notary service. Otherwise, returns nil.
|
// was received via notary service. Otherwise, returns nil.
|
||||||
func (s AddPeer) NotaryRequest() *payload.P2PNotaryRequest {
|
func (s AddPeer) NotaryRequest() *payload.P2PNotaryRequest {
|
||||||
return s.notaryRequest
|
return s.Request
|
||||||
}
|
}
|
||||||
|
|
||||||
const expectedItemNumAddPeer = 1
|
const expectedItemNumAddPeer = 1
|
||||||
|
@ -47,7 +47,7 @@ func ParseAddPeer(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
return nil, event.WrongNumberOfParameters(expectedItemNumAddPeer, ln)
|
return nil, event.WrongNumberOfParameters(expectedItemNumAddPeer, ln)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.node, err = client.BytesFromStackItem(params[0])
|
ev.NodeBytes, err = client.BytesFromStackItem(params[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get raw nodeinfo: %w", err)
|
return nil, fmt.Errorf("could not get raw nodeinfo: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
func (s *AddPeer) setNode(v []byte) {
|
func (s *AddPeer) setNode(v []byte) {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
s.node = v
|
s.NodeBytes = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ func ParseAddPeerNotary(ne event.NotaryEvent) (event.Event, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.notaryRequest = ne.Raw()
|
ev.Request = ne.Raw()
|
||||||
|
|
||||||
return ev, nil
|
return ev, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ func TestParseAddPeer(t *testing.T) {
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, AddPeer{
|
require.Equal(t, AddPeer{
|
||||||
node: info,
|
NodeBytes: info,
|
||||||
}, ev)
|
}, ev)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,12 @@ import (
|
||||||
|
|
||||||
// NewEpoch is a new epoch Neo:Morph event.
|
// NewEpoch is a new epoch Neo:Morph event.
|
||||||
type NewEpoch struct {
|
type NewEpoch struct {
|
||||||
num uint64
|
Num uint64
|
||||||
|
|
||||||
// txHash is used in notary environmental
|
// Hash is used in notary environmental
|
||||||
// for calculating unique but same for
|
// for calculating unique but same for
|
||||||
// all notification receivers values.
|
// all notification receivers values.
|
||||||
txHash util.Uint256
|
Hash util.Uint256
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
|
@ -24,13 +24,13 @@ func (NewEpoch) MorphEvent() {}
|
||||||
|
|
||||||
// EpochNumber returns new epoch number.
|
// EpochNumber returns new epoch number.
|
||||||
func (s NewEpoch) EpochNumber() uint64 {
|
func (s NewEpoch) EpochNumber() uint64 {
|
||||||
return s.num
|
return s.Num
|
||||||
}
|
}
|
||||||
|
|
||||||
// TxHash returns hash of the TX with new epoch
|
// TxHash returns hash of the TX with new epoch
|
||||||
// notification.
|
// notification.
|
||||||
func (s NewEpoch) TxHash() util.Uint256 {
|
func (s NewEpoch) TxHash() util.Uint256 {
|
||||||
return s.txHash
|
return s.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseNewEpoch is a parser of new epoch notification event.
|
// ParseNewEpoch is a parser of new epoch notification event.
|
||||||
|
@ -52,7 +52,7 @@ func ParseNewEpoch(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewEpoch{
|
return NewEpoch{
|
||||||
num: uint64(prmEpochNum),
|
Num: uint64(prmEpochNum),
|
||||||
txHash: e.Container,
|
Hash: e.Container,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ func TestParseNewEpoch(t *testing.T) {
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, NewEpoch{
|
require.Equal(t, NewEpoch{
|
||||||
num: epochNum,
|
Num: epochNum,
|
||||||
}, ev)
|
}, ev)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type UpdatePeer struct {
|
type UpdatePeer struct {
|
||||||
publicKey *keys.PublicKey
|
PubKey *keys.PublicKey
|
||||||
|
|
||||||
state netmap.NodeState
|
State netmap.NodeState
|
||||||
|
|
||||||
// For notary notifications only.
|
// For notary notifications only.
|
||||||
// Contains raw transactions of notary request.
|
// Contains raw transactions of notary request.
|
||||||
notaryRequest *payload.P2PNotaryRequest
|
Request *payload.P2PNotaryRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// MorphEvent implements Neo:Morph Event interface.
|
// MorphEvent implements Neo:Morph Event interface.
|
||||||
|
@ -28,27 +28,27 @@ func (UpdatePeer) MorphEvent() {}
|
||||||
// Online returns true if node's state is requested to be switched
|
// Online returns true if node's state is requested to be switched
|
||||||
// to "online".
|
// to "online".
|
||||||
func (s UpdatePeer) Online() bool {
|
func (s UpdatePeer) Online() bool {
|
||||||
return s.state == netmap.NodeStateOnline
|
return s.State == netmap.NodeStateOnline
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maintenance returns true if node's state is requested to be switched
|
// Maintenance returns true if node's state is requested to be switched
|
||||||
// to "maintenance".
|
// to "maintenance".
|
||||||
func (s UpdatePeer) Maintenance() bool {
|
func (s UpdatePeer) Maintenance() bool {
|
||||||
return s.state == netmap.NodeStateMaintenance
|
return s.State == netmap.NodeStateMaintenance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s UpdatePeer) PublicKey() *keys.PublicKey {
|
func (s UpdatePeer) PublicKey() *keys.PublicKey {
|
||||||
return s.publicKey
|
return s.PubKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotaryRequest returns raw notary request if notification
|
// NotaryRequest returns raw notary request if notification
|
||||||
// was received via notary service. Otherwise, returns nil.
|
// was received via notary service. Otherwise, returns nil.
|
||||||
func (s UpdatePeer) NotaryRequest() *payload.P2PNotaryRequest {
|
func (s UpdatePeer) NotaryRequest() *payload.P2PNotaryRequest {
|
||||||
return s.notaryRequest
|
return s.Request
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *UpdatePeer) decodeState(state int64) error {
|
func (s *UpdatePeer) decodeState(state int64) error {
|
||||||
switch s.state = netmap.NodeState(state); s.state {
|
switch s.State = netmap.NodeState(state); s.State {
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported node state %d", state)
|
return fmt.Errorf("unsupported node state %d", state)
|
||||||
case
|
case
|
||||||
|
@ -82,7 +82,7 @@ func ParseUpdatePeer(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||||
return nil, fmt.Errorf("could not get public key: %w", err)
|
return nil, fmt.Errorf("could not get public key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.publicKey, err = keys.NewPublicKeyFromBytes(key, elliptic.P256())
|
ev.PubKey, err = keys.NewPublicKeyFromBytes(key, elliptic.P256())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse public key: %w", err)
|
return nil, fmt.Errorf("could not parse public key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ func (s *UpdatePeer) setPublicKey(v []byte) (err error) {
|
||||||
return errNilPubKey
|
return errNilPubKey
|
||||||
}
|
}
|
||||||
|
|
||||||
s.publicKey, err = keys.NewPublicKeyFromBytes(v, elliptic.P256())
|
s.PubKey, err = keys.NewPublicKeyFromBytes(v, elliptic.P256())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not parse public key: %w", err)
|
return fmt.Errorf("could not parse public key: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ func ParseUpdatePeerNotary(ne event.NotaryEvent) (event.Event, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.notaryRequest = ne.Raw()
|
ev.Request = ne.Raw()
|
||||||
|
|
||||||
return ev, nil
|
return ev, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,8 @@ func TestParseUpdatePeer(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, UpdatePeer{
|
require.Equal(t, UpdatePeer{
|
||||||
publicKey: publicKey,
|
PubKey: publicKey,
|
||||||
state: state,
|
State: state,
|
||||||
}, ev)
|
}, ev)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue