Compare commits

..

2 commits

Author SHA1 Message Date
7ffc82a066 [#1452] container: Add ListStream method
* Added new method for listing containers to container service.
  It opens stream and sends containers in batches.

* Added TransportSplitter wrapper around ExecutionService to
  split container ID list read from contract in parts that are
  smaller than grpc max message size. Batch size can be changed
  in node configuration file (as in example config file).

* Changed `container list` implementaion in cli: now ListStream
  is called by default. Old List is called only if ListStream
  is not implemented.

Signed-off-by: Ekaterina Lebedeva <ekaterina.lebedeva@yadro.com>
2024-12-13 16:08:48 +03:00
bfa35cba26 [#1453] container: Replace sort.Slice with slices.SortFunc
* Replaced `sort.Slice` with `slices.SortFunc` in
  `ListContainersRes.SortedIDList()` as it is a bit faster,
  according to 15102e6dfd.

Signed-off-by: Ekaterina Lebedeva <ekaterina.lebedeva@yadro.com>
2024-12-12 18:06:08 +03:00
24 changed files with 131 additions and 83 deletions

View file

@ -29,7 +29,7 @@ func (c *Client) BalanceOf(id user.ID) (*big.Int, error) {
amount, err := client.BigIntFromStackItem(prms[0]) amount, err := client.BigIntFromStackItem(prms[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("get integer stack item from stack item (%s): %w", balanceOfMethod, err) return nil, fmt.Errorf("could not get integer stack item from stack item (%s): %w", balanceOfMethod, err)
} }
return amount, nil return amount, nil
} }

View file

@ -21,7 +21,7 @@ func (c *Client) Decimals() (uint32, error) {
decimals, err := client.IntFromStackItem(prms[0]) decimals, err := client.IntFromStackItem(prms[0])
if err != nil { if err != nil {
return 0, fmt.Errorf("get integer stack item from stack item (%s): %w", decimalsMethod, err) return 0, fmt.Errorf("could not get integer stack item from stack item (%s): %w", decimalsMethod, err)
} }
return uint32(decimals), nil return uint32(decimals), nil
} }

View file

@ -39,7 +39,7 @@ func (c *Client) TransferX(ctx context.Context, p TransferPrm) error {
_, err = c.client.Invoke(ctx, prm) _, err = c.client.Invoke(ctx, prm)
if err != nil { if err != nil {
return fmt.Errorf("invoke method (%s): %w", transferXMethod, err) return fmt.Errorf("could not invoke method (%s): %w", transferXMethod, err)
} }
return nil return nil
} }

View file

@ -196,7 +196,7 @@ func (c *Client) Invoke(ctx context.Context, contract util.Uint160, fee fixedn.F
txHash, vub, err := c.rpcActor.SendTunedCall(contract, method, nil, addFeeCheckerModifier(int64(fee)), args...) txHash, vub, err := c.rpcActor.SendTunedCall(contract, method, nil, addFeeCheckerModifier(int64(fee)), args...)
if err != nil { if err != nil {
return InvokeRes{}, fmt.Errorf("invoke %s: %w", method, err) return InvokeRes{}, fmt.Errorf("could not invoke %s: %w", method, err)
} }
c.logger.Debug(ctx, logs.ClientNeoClientInvoke, c.logger.Debug(ctx, logs.ClientNeoClientInvoke,
@ -509,7 +509,7 @@ func (c *Client) NeoFSAlphabetList() (res keys.PublicKeys, err error) {
list, err := c.roleList(noderoles.NeoFSAlphabet) list, err := c.roleList(noderoles.NeoFSAlphabet)
if err != nil { if err != nil {
return nil, fmt.Errorf("get alphabet nodes role list: %w", err) return nil, fmt.Errorf("can't get alphabet nodes role list: %w", err)
} }
return list, nil return list, nil
@ -523,7 +523,7 @@ func (c *Client) GetDesignateHash() util.Uint160 {
func (c *Client) roleList(r noderoles.Role) (keys.PublicKeys, error) { func (c *Client) roleList(r noderoles.Role) (keys.PublicKeys, error) {
height, err := c.rpcActor.GetBlockCount() height, err := c.rpcActor.GetBlockCount()
if err != nil { if err != nil {
return nil, fmt.Errorf("get chain height: %w", err) return nil, fmt.Errorf("can't get chain height: %w", err)
} }
return c.rolemgmt.GetDesignatedByRole(r, height) return c.rolemgmt.GetDesignatedByRole(r, height)

View file

@ -26,7 +26,7 @@ func (c *Client) ContainersOf(idUser *user.ID) ([]cid.ID, error) {
cb := func(item stackitem.Item) error { cb := func(item stackitem.Item) error {
rawID, err := client.BytesFromStackItem(item) rawID, err := client.BytesFromStackItem(item)
if err != nil { if err != nil {
return fmt.Errorf("get byte array from stack item (%s): %w", containersOfMethod, err) return fmt.Errorf("could not get byte array from stack item (%s): %w", containersOfMethod, err)
} }
var id cid.ID var id cid.ID

View file

@ -78,7 +78,7 @@ func (c *Client) Delete(ctx context.Context, p DeletePrm) (uint32, error) {
res, err := c.client.Invoke(ctx, prm) res, err := c.client.Invoke(ctx, prm)
if err != nil { if err != nil {
return 0, fmt.Errorf("invoke method (%s): %w", deleteMethod, err) return 0, fmt.Errorf("could not invoke method (%s): %w", deleteMethod, err)
} }
return res.VUB, nil return res.VUB, nil
} }

View file

@ -46,7 +46,7 @@ func (c *Client) DeletionInfo(cid []byte) (*containercore.DelInfo, error) {
arr, err := client.ArrayFromStackItem(res[0]) arr, err := client.ArrayFromStackItem(res[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("get item array of container (%s): %w", deletionInfoMethod, err) return nil, fmt.Errorf("could not get item array of container (%s): %w", deletionInfoMethod, err)
} }
if len(arr) != 2 { if len(arr) != 2 {
@ -55,17 +55,17 @@ func (c *Client) DeletionInfo(cid []byte) (*containercore.DelInfo, error) {
rawOwner, err := client.BytesFromStackItem(arr[0]) rawOwner, err := client.BytesFromStackItem(arr[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("get byte array of container (%s): %w", deletionInfoMethod, err) return nil, fmt.Errorf("could not get byte array of container (%s): %w", deletionInfoMethod, err)
} }
var owner user.ID var owner user.ID
if err := owner.DecodeString(base58.Encode(rawOwner)); err != nil { if err := owner.DecodeString(base58.Encode(rawOwner)); err != nil {
return nil, fmt.Errorf("decode container owner id (%s): %w", deletionInfoMethod, err) return nil, fmt.Errorf("could not decode container owner id (%s): %w", deletionInfoMethod, err)
} }
epoch, err := client.BigIntFromStackItem(arr[1]) epoch, err := client.BigIntFromStackItem(arr[1])
if err != nil { if err != nil {
return nil, fmt.Errorf("get byte array of container signature (%s): %w", deletionInfoMethod, err) return nil, fmt.Errorf("could not get byte array of container signature (%s): %w", deletionInfoMethod, err)
} }
return &containercore.DelInfo{ return &containercore.DelInfo{

View file

@ -60,7 +60,7 @@ func (c *Client) Get(cid []byte) (*containercore.Container, error) {
arr, err := client.ArrayFromStackItem(res[0]) arr, err := client.ArrayFromStackItem(res[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("get item array of container (%s): %w", getMethod, err) return nil, fmt.Errorf("could not get item array of container (%s): %w", getMethod, err)
} }
if len(arr) != 4 { if len(arr) != 4 {
@ -69,29 +69,29 @@ func (c *Client) Get(cid []byte) (*containercore.Container, error) {
cnrBytes, err := client.BytesFromStackItem(arr[0]) cnrBytes, err := client.BytesFromStackItem(arr[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("get byte array of container (%s): %w", getMethod, err) return nil, fmt.Errorf("could not get byte array of container (%s): %w", getMethod, err)
} }
sigBytes, err := client.BytesFromStackItem(arr[1]) sigBytes, err := client.BytesFromStackItem(arr[1])
if err != nil { if err != nil {
return nil, fmt.Errorf("get byte array of container signature (%s): %w", getMethod, err) return nil, fmt.Errorf("could not get byte array of container signature (%s): %w", getMethod, err)
} }
pub, err := client.BytesFromStackItem(arr[2]) pub, err := client.BytesFromStackItem(arr[2])
if err != nil { if err != nil {
return nil, fmt.Errorf("get byte array of public key (%s): %w", getMethod, err) return nil, fmt.Errorf("could not get byte array of public key (%s): %w", getMethod, err)
} }
tokBytes, err := client.BytesFromStackItem(arr[3]) tokBytes, err := client.BytesFromStackItem(arr[3])
if err != nil { if err != nil {
return nil, fmt.Errorf("get byte array of session token (%s): %w", getMethod, err) return nil, fmt.Errorf("could not get byte array of session token (%s): %w", getMethod, err)
} }
var cnr containercore.Container var cnr containercore.Container
if err := cnr.Value.Unmarshal(cnrBytes); err != nil { if err := cnr.Value.Unmarshal(cnrBytes); err != nil {
// use other major version if there any // use other major version if there any
return nil, fmt.Errorf("unmarshal container: %w", err) return nil, fmt.Errorf("can't unmarshal container: %w", err)
} }
if len(tokBytes) > 0 { if len(tokBytes) > 0 {
@ -99,7 +99,7 @@ func (c *Client) Get(cid []byte) (*containercore.Container, error) {
err = cnr.Session.Unmarshal(tokBytes) err = cnr.Session.Unmarshal(tokBytes)
if err != nil { if err != nil {
return nil, fmt.Errorf("unmarshal session token: %w", err) return nil, fmt.Errorf("could not unmarshal session token: %w", err)
} }
} }

View file

@ -34,14 +34,14 @@ func (c *Client) list(idUser *user.ID) ([]cid.ID, error) {
res, err = client.ArrayFromStackItem(res[0]) res, err = client.ArrayFromStackItem(res[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("get stack item array from stack item (%s): %w", listMethod, err) return nil, fmt.Errorf("could not get stack item array from stack item (%s): %w", listMethod, err)
} }
cidList := make([]cid.ID, 0, len(res)) cidList := make([]cid.ID, 0, len(res))
for i := range res { for i := range res {
rawID, err := client.BytesFromStackItem(res[i]) rawID, err := client.BytesFromStackItem(res[i])
if err != nil { if err != nil {
return nil, fmt.Errorf("get byte array from stack item (%s): %w", listMethod, err) return nil, fmt.Errorf("could not get byte array from stack item (%s): %w", listMethod, err)
} }
var id cid.ID var id cid.ID

View file

@ -117,7 +117,7 @@ func (c *Client) Put(ctx context.Context, p PutPrm) error {
_, err := c.client.Invoke(ctx, prm) _, err := c.client.Invoke(ctx, prm)
if err != nil { if err != nil {
return fmt.Errorf("invoke method (%s): %w", method, err) return fmt.Errorf("could not invoke method (%s): %w", method, err)
} }
return nil return nil
} }

View file

@ -31,7 +31,7 @@ func (c *Client) GetSubject(addr util.Uint160) (*frostfsidclient.Subject, error)
subj, err := frostfsidclient.ParseSubject(structArr) subj, err := frostfsidclient.ParseSubject(structArr)
if err != nil { if err != nil {
return nil, fmt.Errorf("parse test invocation result (%s): %w", methodGetSubject, err) return nil, fmt.Errorf("could not parse test invocation result (%s): %w", methodGetSubject, err)
} }
return subj, nil return subj, nil
@ -54,7 +54,7 @@ func (c *Client) GetSubjectExtended(addr util.Uint160) (*frostfsidclient.Subject
subj, err := frostfsidclient.ParseSubjectExtended(structArr) subj, err := frostfsidclient.ParseSubjectExtended(structArr)
if err != nil { if err != nil {
return nil, fmt.Errorf("parse test invocation result (%s): %w", methodGetSubject, err) return nil, fmt.Errorf("could not parse test invocation result (%s): %w", methodGetSubject, err)
} }
return subj, nil return subj, nil
@ -67,7 +67,7 @@ func checkStackItem(res []stackitem.Item) (structArr []stackitem.Item, err error
structArr, err = client.ArrayFromStackItem(res[0]) structArr, err = client.ArrayFromStackItem(res[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("get item array of container (%s): %w", methodGetSubject, err) return nil, fmt.Errorf("could not get item array of container (%s): %w", methodGetSubject, err)
} }
return return
} }

View file

@ -25,7 +25,7 @@ func (c *Client) Epoch() (uint64, error) {
num, err := client.IntFromStackItem(items[0]) num, err := client.IntFromStackItem(items[0])
if err != nil { if err != nil {
return 0, fmt.Errorf("get number from stack item (%s): %w", epochMethod, err) return 0, fmt.Errorf("could not get number from stack item (%s): %w", epochMethod, err)
} }
return uint64(num), nil return uint64(num), nil
} }
@ -49,7 +49,7 @@ func (c *Client) LastEpochBlock() (uint32, error) {
block, err := client.IntFromStackItem(items[0]) block, err := client.IntFromStackItem(items[0])
if err != nil { if err != nil {
return 0, fmt.Errorf("get number from stack item (%s): %w", return 0, fmt.Errorf("could not get number from stack item (%s): %w",
lastEpochBlockMethod, err) lastEpochBlockMethod, err)
} }
return uint32(block), nil return uint32(block), nil

View file

@ -59,7 +59,7 @@ func irKeysFromStackItem(stack []stackitem.Item, method string) (keys.PublicKeys
irs, err := client.ArrayFromStackItem(stack[0]) irs, err := client.ArrayFromStackItem(stack[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("get stack item array from stack item (%s): %w", method, err) return nil, fmt.Errorf("could not get stack item array from stack item (%s): %w", method, err)
} }
irKeys := make(keys.PublicKeys, len(irs)) irKeys := make(keys.PublicKeys, len(irs))
@ -79,7 +79,7 @@ const irNodeFixedPrmNumber = 1
func irKeyFromStackItem(prm stackitem.Item) (*keys.PublicKey, error) { func irKeyFromStackItem(prm stackitem.Item) (*keys.PublicKey, error) {
prms, err := client.ArrayFromStackItem(prm) prms, err := client.ArrayFromStackItem(prm)
if err != nil { if err != nil {
return nil, fmt.Errorf("get stack item array (IRNode): %w", err) return nil, fmt.Errorf("could not get stack item array (IRNode): %w", err)
} else if ln := len(prms); ln != irNodeFixedPrmNumber { } else if ln := len(prms); ln != irNodeFixedPrmNumber {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"unexpected stack item count (IRNode): expected %d, has %d", "unexpected stack item count (IRNode): expected %d, has %d",
@ -90,7 +90,7 @@ func irKeyFromStackItem(prm stackitem.Item) (*keys.PublicKey, error) {
byteKey, err := client.BytesFromStackItem(prms[0]) byteKey, err := client.BytesFromStackItem(prms[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("parse bytes from stack item (IRNode): %w", err) return nil, fmt.Errorf("could not parse bytes from stack item (IRNode): %w", err)
} }
return keys.NewPublicKeyFromBytes(byteKey, elliptic.P256()) return keys.NewPublicKeyFromBytes(byteKey, elliptic.P256())

View file

@ -16,7 +16,7 @@ func (c *Client) NewEpoch(ctx context.Context, epoch uint64) error {
_, err := c.client.Invoke(ctx, prm) _, err := c.client.Invoke(ctx, prm)
if err != nil { if err != nil {
return fmt.Errorf("invoke method (%s): %w", newEpochMethod, err) return fmt.Errorf("could not invoke method (%s): %w", newEpochMethod, err)
} }
return nil return nil
} }
@ -34,7 +34,7 @@ func (c *Client) NewEpochControl(ctx context.Context, epoch uint64, vub uint32)
res, err := c.client.Invoke(ctx, prm) res, err := c.client.Invoke(ctx, prm)
if err != nil { if err != nil {
return 0, fmt.Errorf("invoke method (%s): %w", newEpochMethod, err) return 0, fmt.Errorf("could not invoke method (%s): %w", newEpochMethod, err)
} }
return res.VUB, nil return res.VUB, nil
} }

View file

@ -41,7 +41,7 @@ func (c *Client) AddPeer(ctx context.Context, p AddPeerPrm) error {
prm.InvokePrmOptional = p.InvokePrmOptional prm.InvokePrmOptional = p.InvokePrmOptional
if _, err := c.client.Invoke(ctx, prm); err != nil { if _, err := c.client.Invoke(ctx, prm); err != nil {
return fmt.Errorf("invoke method (%s): %w", method, err) return fmt.Errorf("could not invoke method (%s): %w", method, err)
} }
return nil return nil
} }

View file

@ -107,7 +107,7 @@ func (c *Client) NNSHash() (util.Uint160, error) {
func nnsResolveItem(c *rpcclient.WSClient, nnsHash util.Uint160, domain string) (stackitem.Item, error) { func nnsResolveItem(c *rpcclient.WSClient, nnsHash util.Uint160, domain string) (stackitem.Item, error) {
found, err := exists(c, nnsHash, domain) found, err := exists(c, nnsHash, domain)
if err != nil { if err != nil {
return nil, fmt.Errorf("check presence in NNS contract for %s: %w", domain, err) return nil, fmt.Errorf("could not check presence in NNS contract for %s: %w", domain, err)
} }
if !found { if !found {

View file

@ -58,11 +58,16 @@ const (
defaultNotaryValidTime = 50 defaultNotaryValidTime = 50
defaultNotaryRoundTime = 100 defaultNotaryRoundTime = 100
setDesignateMethod = "designateAsRole" notaryBalanceOfMethod = "balanceOf"
notaryExpirationOfMethod = "expirationOf"
setDesignateMethod = "designateAsRole"
notaryBalanceErrMsg = "can't fetch notary balance"
notaryNotEnabledPanicMsg = "notary support was not enabled on this client" notaryNotEnabledPanicMsg = "notary support was not enabled on this client"
) )
var errUnexpectedItems = errors.New("invalid number of NEO VM arguments on stack")
func defaultNotaryConfig(c *Client) *notaryCfg { func defaultNotaryConfig(c *Client) *notaryCfg {
return &notaryCfg{ return &notaryCfg{
txValidTime: defaultNotaryValidTime, txValidTime: defaultNotaryValidTime,
@ -150,16 +155,15 @@ func (c *Client) DepositNotary(ctx context.Context, amount fixedn.Fixed8, delta
bc, err := c.rpcActor.GetBlockCount() bc, err := c.rpcActor.GetBlockCount()
if err != nil { if err != nil {
return util.Uint256{}, fmt.Errorf("get blockchain height: %w", err) return util.Uint256{}, fmt.Errorf("can't get blockchain height: %w", err)
} }
r := notary.NewReader(c.rpcActor) currentTill, err := c.depositExpirationOf()
currentTill, err := r.ExpirationOf(c.acc.PrivateKey().GetScriptHash())
if err != nil { if err != nil {
return util.Uint256{}, fmt.Errorf("get previous expiration value: %w", err) return util.Uint256{}, fmt.Errorf("can't get previous expiration value: %w", err)
} }
till := max(int64(bc+delta), int64(currentTill)) till := max(int64(bc+delta), currentTill)
res, _, err := c.depositNotary(ctx, amount, till) res, _, err := c.depositNotary(ctx, amount, till)
return res, err return res, err
} }
@ -193,7 +197,7 @@ func (c *Client) depositNotary(ctx context.Context, amount fixedn.Fixed8, till i
[]any{c.acc.PrivateKey().GetScriptHash(), till}) []any{c.acc.PrivateKey().GetScriptHash(), till})
if err != nil { if err != nil {
if !errors.Is(err, neorpc.ErrAlreadyExists) { if !errors.Is(err, neorpc.ErrAlreadyExists) {
return util.Uint256{}, 0, fmt.Errorf("make notary deposit: %w", err) return util.Uint256{}, 0, fmt.Errorf("can't make notary deposit: %w", err)
} }
// Transaction is already in mempool waiting to be processed. // Transaction is already in mempool waiting to be processed.
@ -233,10 +237,18 @@ func (c *Client) GetNotaryDeposit() (res int64, err error) {
sh := c.acc.PrivateKey().PublicKey().GetScriptHash() sh := c.acc.PrivateKey().PublicKey().GetScriptHash()
r := notary.NewReader(c.rpcActor) items, err := c.TestInvoke(c.notary.notary, notaryBalanceOfMethod, sh)
bigIntDeposit, err := r.BalanceOf(sh)
if err != nil { if err != nil {
return 0, fmt.Errorf("get notary deposit: %w", err) return 0, fmt.Errorf("test invoke (%s): %w", notaryBalanceOfMethod, err)
}
if len(items) != 1 {
return 0, wrapFrostFSError(fmt.Errorf("%v: %w", notaryBalanceErrMsg, errUnexpectedItems))
}
bigIntDeposit, err := items[0].TryInteger()
if err != nil {
return 0, wrapFrostFSError(fmt.Errorf("%v: %w", notaryBalanceErrMsg, err))
} }
return bigIntDeposit.Int64(), nil return bigIntDeposit.Int64(), nil
@ -277,7 +289,7 @@ func (c *Client) UpdateNotaryList(ctx context.Context, prm UpdateNotaryListPrm)
nonce, vub, err := c.CalculateNonceAndVUB(&prm.hash) nonce, vub, err := c.CalculateNonceAndVUB(&prm.hash)
if err != nil { if err != nil {
return fmt.Errorf("calculate nonce and `valicUntilBlock` values: %w", err) return fmt.Errorf("could not calculate nonce and `valicUntilBlock` values: %w", err)
} }
return c.notaryInvokeAsCommittee( return c.notaryInvokeAsCommittee(
@ -326,7 +338,7 @@ func (c *Client) UpdateNeoFSAlphabetList(ctx context.Context, prm UpdateAlphabet
nonce, vub, err := c.CalculateNonceAndVUB(&prm.hash) nonce, vub, err := c.CalculateNonceAndVUB(&prm.hash)
if err != nil { if err != nil {
return fmt.Errorf("calculate nonce and `valicUntilBlock` values: %w", err) return fmt.Errorf("could not calculate nonce and `valicUntilBlock` values: %w", err)
} }
return c.notaryInvokeAsCommittee( return c.notaryInvokeAsCommittee(
@ -395,7 +407,7 @@ func (c *Client) NotarySignAndInvokeTX(mainTx *transaction.Transaction) error {
alphabetList, err := c.notary.alphabetSource() alphabetList, err := c.notary.alphabetSource()
if err != nil { if err != nil {
return fmt.Errorf("fetch current alphabet keys: %w", err) return fmt.Errorf("could not fetch current alphabet keys: %w", err)
} }
cosigners, err := c.notaryCosignersFromTx(mainTx, alphabetList) cosigners, err := c.notaryCosignersFromTx(mainTx, alphabetList)
@ -517,24 +529,24 @@ func (c *Client) notaryCosignersFromTx(mainTx *transaction.Transaction, alphabet
if ok { if ok {
pub, err := keys.NewPublicKeyFromBytes(pubBytes, elliptic.P256()) pub, err := keys.NewPublicKeyFromBytes(pubBytes, elliptic.P256())
if err != nil { if err != nil {
return nil, fmt.Errorf("parse verification script of signer #2: invalid public key: %w", err) return nil, fmt.Errorf("failed to parse verification script of signer #2: invalid public key: %w", err)
} }
acc = notary.FakeSimpleAccount(pub) acc = notary.FakeSimpleAccount(pub)
} else { } else {
m, pubsBytes, ok := vm.ParseMultiSigContract(script) m, pubsBytes, ok := vm.ParseMultiSigContract(script)
if !ok { if !ok {
return nil, errors.New("parse verification script of signer #2: unknown witness type") return nil, errors.New("failed to parse verification script of signer #2: unknown witness type")
} }
pubs := make(keys.PublicKeys, len(pubsBytes)) pubs := make(keys.PublicKeys, len(pubsBytes))
for i := range pubs { for i := range pubs {
pubs[i], err = keys.NewPublicKeyFromBytes(pubsBytes[i], elliptic.P256()) pubs[i], err = keys.NewPublicKeyFromBytes(pubsBytes[i], elliptic.P256())
if err != nil { if err != nil {
return nil, fmt.Errorf("parse verification script of signer #2: invalid public key #%d: %w", i, err) return nil, fmt.Errorf("failed to parse verification script of signer #2: invalid public key #%d: %w", i, err)
} }
} }
acc, err = notary.FakeMultisigAccount(m, pubs) acc, err = notary.FakeMultisigAccount(m, pubs)
if err != nil { if err != nil {
return nil, fmt.Errorf("create fake account for signer #2: %w", err) return nil, fmt.Errorf("failed to create fake account for signer #2: %w", err)
} }
} }
} }
@ -611,7 +623,7 @@ func (c *Client) notaryMultisigAccount(ir []*keys.PublicKey, committee, invokedB
err := multisigAccount.ConvertMultisig(m, ir) err := multisigAccount.ConvertMultisig(m, ir)
if err != nil { if err != nil {
// wrap error as FrostFS-specific since the call is not related to any client // wrap error as FrostFS-specific since the call is not related to any client
return nil, wrapFrostFSError(fmt.Errorf("convert account to inner ring multisig wallet: %w", err)) return nil, wrapFrostFSError(fmt.Errorf("can't convert account to inner ring multisig wallet: %w", err))
} }
} else { } else {
// alphabet multisig redeem script is // alphabet multisig redeem script is
@ -620,7 +632,7 @@ func (c *Client) notaryMultisigAccount(ir []*keys.PublicKey, committee, invokedB
multisigAccount, err = notary.FakeMultisigAccount(m, ir) multisigAccount, err = notary.FakeMultisigAccount(m, ir)
if err != nil { if err != nil {
// wrap error as FrostFS-specific since the call is not related to any client // wrap error as FrostFS-specific since the call is not related to any client
return nil, wrapFrostFSError(fmt.Errorf("make inner ring multisig wallet: %w", err)) return nil, wrapFrostFSError(fmt.Errorf("can't make inner ring multisig wallet: %w", err))
} }
} }
@ -630,7 +642,7 @@ func (c *Client) notaryMultisigAccount(ir []*keys.PublicKey, committee, invokedB
func (c *Client) notaryTxValidationLimit() (uint32, error) { func (c *Client) notaryTxValidationLimit() (uint32, error) {
bc, err := c.rpcActor.GetBlockCount() bc, err := c.rpcActor.GetBlockCount()
if err != nil { if err != nil {
return 0, fmt.Errorf("get current blockchain height: %w", err) return 0, fmt.Errorf("can't get current blockchain height: %w", err)
} }
minTime := bc + c.notary.txValidTime minTime := bc + c.notary.txValidTime
@ -639,6 +651,24 @@ func (c *Client) notaryTxValidationLimit() (uint32, error) {
return rounded, nil return rounded, nil
} }
func (c *Client) depositExpirationOf() (int64, error) {
expirationRes, err := c.TestInvoke(c.notary.notary, notaryExpirationOfMethod, c.acc.PrivateKey().GetScriptHash())
if err != nil {
return 0, fmt.Errorf("test invoke (%s): %w", notaryExpirationOfMethod, err)
}
if len(expirationRes) != 1 {
return 0, fmt.Errorf("method returned unexpected item count: %d", len(expirationRes))
}
currentTillBig, err := expirationRes[0].TryInteger()
if err != nil {
return 0, fmt.Errorf("can't parse deposit till value: %w", err)
}
return currentTillBig.Int64(), nil
}
// sigCount returns the number of required signature. // sigCount returns the number of required signature.
// For FrostFS Alphabet M is a 2/3+1 of it (like in dBFT). // For FrostFS Alphabet M is a 2/3+1 of it (like in dBFT).
// If committee is true, returns M as N/2+1. // If committee is true, returns M as N/2+1.
@ -712,12 +742,12 @@ func alreadyOnChainError(err error) bool {
func CalculateNotaryDepositAmount(c *Client, gasMul, gasDiv int64) (fixedn.Fixed8, error) { func CalculateNotaryDepositAmount(c *Client, gasMul, gasDiv int64) (fixedn.Fixed8, error) {
notaryBalance, err := c.GetNotaryDeposit() notaryBalance, err := c.GetNotaryDeposit()
if err != nil { if err != nil {
return 0, fmt.Errorf("get notary balance: %w", err) return 0, fmt.Errorf("could not get notary balance: %w", err)
} }
gasBalance, err := c.GasBalance() gasBalance, err := c.GasBalance()
if err != nil { if err != nil {
return 0, fmt.Errorf("get GAS balance: %w", err) return 0, fmt.Errorf("could not get GAS balance: %w", err)
} }
if gasBalance == 0 { if gasBalance == 0 {
@ -766,12 +796,12 @@ func (c *Client) calculateNonceAndVUB(hash *util.Uint256, roundBlockHeight bool)
if hash != nil { if hash != nil {
height, err = c.getTransactionHeight(*hash) height, err = c.getTransactionHeight(*hash)
if err != nil { if err != nil {
return 0, 0, fmt.Errorf("get transaction height: %w", err) return 0, 0, fmt.Errorf("could not get transaction height: %w", err)
} }
} else { } else {
height, err = c.rpcActor.GetBlockCount() height, err = c.rpcActor.GetBlockCount()
if err != nil { if err != nil {
return 0, 0, fmt.Errorf("get chain height: %w", err) return 0, 0, fmt.Errorf("could not get chain height: %w", err)
} }
} }

View file

@ -159,7 +159,7 @@ func (s StaticClient) Invoke(ctx context.Context, prm InvokePrm) (InvokeRes, err
nonce, vub, err = s.client.CalculateNonceAndVUB(prm.hash) nonce, vub, err = s.client.CalculateNonceAndVUB(prm.hash)
} }
if err != nil { if err != nil {
return InvokeRes{}, fmt.Errorf("calculate nonce and VUB for notary alphabet invoke: %w", err) return InvokeRes{}, fmt.Errorf("could not calculate nonce and VUB for notary alphabet invoke: %w", err)
} }
vubP = &vub vubP = &vub

View file

@ -53,7 +53,7 @@ func BytesFromStackItem(param stackitem.Item) ([]byte, error) {
case stackitem.IntegerT: case stackitem.IntegerT:
n, err := param.TryInteger() n, err := param.TryInteger()
if err != nil { if err != nil {
return nil, fmt.Errorf("parse integer bytes: %w", err) return nil, fmt.Errorf("can't parse integer bytes: %w", err)
} }
return n.Bytes(), nil return n.Bytes(), nil

View file

@ -111,7 +111,7 @@ type listener struct {
pool *ants.Pool pool *ants.Pool
} }
const newListenerFailMsg = "instantiate Listener" const newListenerFailMsg = "could not instantiate Listener"
var ( var (
errNilLogger = errors.New("nil logger") errNilLogger = errors.New("nil logger")
@ -180,7 +180,7 @@ func (l *listener) subscribe(errCh chan error) {
// fill the list with the contracts with set event parsers. // fill the list with the contracts with set event parsers.
l.mtx.RLock() l.mtx.RLock()
for hashType := range l.notificationParsers { for hashType := range l.notificationParsers {
scHash := hashType.Hash scHash := hashType.ScriptHash()
// prevent repetitions // prevent repetitions
for _, hash := range hashes { for _, hash := range hashes {
@ -189,26 +189,26 @@ func (l *listener) subscribe(errCh chan error) {
} }
} }
hashes = append(hashes, hashType.Hash) hashes = append(hashes, hashType.ScriptHash())
} }
l.mtx.RUnlock() l.mtx.RUnlock()
err := l.subscriber.SubscribeForNotification(hashes...) err := l.subscriber.SubscribeForNotification(hashes...)
if err != nil { if err != nil {
errCh <- fmt.Errorf("subscribe for notifications: %w", err) errCh <- fmt.Errorf("could not subscribe for notifications: %w", err)
return return
} }
if len(l.blockHandlers) > 0 { if len(l.blockHandlers) > 0 {
if err = l.subscriber.BlockNotifications(); err != nil { if err = l.subscriber.BlockNotifications(); err != nil {
errCh <- fmt.Errorf("subscribe for blocks: %w", err) errCh <- fmt.Errorf("could not subscribe for blocks: %w", err)
return return
} }
} }
if l.listenNotary { if l.listenNotary {
if err = l.subscriber.SubscribeForNotaryRequests(l.notaryMainTXSigner); err != nil { if err = l.subscriber.SubscribeForNotaryRequests(l.notaryMainTXSigner); err != nil {
errCh <- fmt.Errorf("subscribe for notary requests: %w", err) errCh <- fmt.Errorf("could not subscribe for notary requests: %w", err)
return return
} }
} }
@ -326,7 +326,9 @@ func (l *listener) parseAndHandleNotification(ctx context.Context, notifyEvent *
) )
// get the event parser // get the event parser
keyEvent := scriptHashWithType{Hash: notifyEvent.ScriptHash, Type: typEvent} keyEvent := scriptHashWithType{}
keyEvent.SetScriptHash(notifyEvent.ScriptHash)
keyEvent.SetType(typEvent)
l.mtx.RLock() l.mtx.RLock()
parser, ok := l.notificationParsers[keyEvent] parser, ok := l.notificationParsers[keyEvent]
@ -449,7 +451,9 @@ func (l *listener) RegisterNotificationHandler(hi NotificationHandlerInfo) {
l.mtx.Lock() l.mtx.Lock()
defer l.mtx.Unlock() defer l.mtx.Unlock()
k := scriptHashWithType{Hash: hi.Contract, Type: hi.Type} var k scriptHashWithType
k.hash = hi.Contract
k.typ = hi.Type
l.notificationParsers[k] = hi.Parser l.notificationParsers[k] = hi.Parser
l.notificationHandlers[k] = append( l.notificationHandlers[k] = append(
@ -566,7 +570,7 @@ func NewListener(p ListenerParams) (Listener, error) {
// The default capacity is 0, which means "infinite". // The default capacity is 0, which means "infinite".
pool, err := ants.NewPool(p.WorkerPoolCapacity) pool, err := ants.NewPool(p.WorkerPoolCapacity)
if err != nil { if err != nil {
return nil, fmt.Errorf("init worker pool: %w", err) return nil, fmt.Errorf("could not init worker pool: %w", err)
} }
return &listener{ return &listener{

View file

@ -10,7 +10,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
) )
var errNilPubKey = errors.New("public key is nil") var errNilPubKey = errors.New("could not parse public key: public key is nil")
func (s *UpdatePeer) setPublicKey(v []byte) (err error) { func (s *UpdatePeer) setPublicKey(v []byte) (err error) {
if v == nil { if v == nil {
@ -19,7 +19,7 @@ func (s *UpdatePeer) setPublicKey(v []byte) (err error) {
s.PubKey, err = keys.NewPublicKeyFromBytes(v, elliptic.P256()) s.PubKey, err = keys.NewPublicKeyFromBytes(v, elliptic.P256())
if err != nil { if err != nil {
return fmt.Errorf("parse public key: %w", err) return fmt.Errorf("could not parse public key: %w", err)
} }
return return

View file

@ -127,7 +127,7 @@ func (p Preparator) Prepare(nr *payload.P2PNotaryRequest) (NotaryEvent, error) {
for { for {
opCode, param, err = ctx.Next() opCode, param, err = ctx.Next()
if err != nil { if err != nil {
return nil, fmt.Errorf("get next opcode in script: %w", err) return nil, fmt.Errorf("could not get next opcode in script: %w", err)
} }
if opCode == opcode.RET { if opCode == opcode.RET {
@ -147,7 +147,7 @@ func (p Preparator) Prepare(nr *payload.P2PNotaryRequest) (NotaryEvent, error) {
// retrieve contract's script hash // retrieve contract's script hash
contractHash, err := util.Uint160DecodeBytesBE(ops[opsLen-2].param) contractHash, err := util.Uint160DecodeBytesBE(ops[opsLen-2].param)
if err != nil { if err != nil {
return nil, fmt.Errorf("decode contract hash: %w", err) return nil, fmt.Errorf("could not decode contract hash: %w", err)
} }
// retrieve contract's method // retrieve contract's method
@ -164,7 +164,7 @@ func (p Preparator) Prepare(nr *payload.P2PNotaryRequest) (NotaryEvent, error) {
if len(args) != 0 { if len(args) != 0 {
err = p.validateParameterOpcodes(args) err = p.validateParameterOpcodes(args)
if err != nil { if err != nil {
return nil, fmt.Errorf("validate arguments: %w", err) return nil, fmt.Errorf("could not validate arguments: %w", err)
} }
// without args packing opcodes // without args packing opcodes
@ -206,7 +206,7 @@ func (p Preparator) validateNotaryRequest(nr *payload.P2PNotaryRequest) error {
currentAlphabet, err := p.alphaKeys() currentAlphabet, err := p.alphaKeys()
if err != nil { if err != nil {
return fmt.Errorf("fetch Alphabet public keys: %w", err) return fmt.Errorf("could not fetch Alphabet public keys: %w", err)
} }
err = p.validateCosigners(ln, nr.MainTransaction.Signers, currentAlphabet) err = p.validateCosigners(ln, nr.MainTransaction.Signers, currentAlphabet)
@ -239,7 +239,7 @@ func (p Preparator) validateParameterOpcodes(ops []Op) error {
argsLen, err := IntFromOpcode(ops[l-2]) argsLen, err := IntFromOpcode(ops[l-2])
if err != nil { if err != nil {
return fmt.Errorf("parse argument len: %w", err) return fmt.Errorf("could not parse argument len: %w", err)
} }
err = validateNestedArgs(argsLen, ops[:l-2]) err = validateNestedArgs(argsLen, ops[:l-2])
@ -273,7 +273,7 @@ func validateNestedArgs(expArgLen int64, ops []Op) error {
argsLen, err := IntFromOpcode(ops[i-1]) argsLen, err := IntFromOpcode(ops[i-1])
if err != nil { if err != nil {
return fmt.Errorf("parse argument len: %w", err) return fmt.Errorf("could not parse argument len: %w", err)
} }
expArgLen += argsLen + 1 expArgLen += argsLen + 1
@ -307,7 +307,7 @@ func (p Preparator) validateExpiration(fbTX *transaction.Transaction) error {
currBlock, err := p.blockCounter.BlockCount() currBlock, err := p.blockCounter.BlockCount()
if err != nil { if err != nil {
return fmt.Errorf("fetch current chain height: %w", err) return fmt.Errorf("could not fetch current chain height: %w", err)
} }
if currBlock >= nvb.Height { if currBlock >= nvb.Height {
@ -327,7 +327,7 @@ func (p Preparator) validateCosigners(expected int, s []transaction.Signer, alph
alphaVerificationScript, err := smartcontract.CreateMultiSigRedeemScript(len(alphaKeys)*2/3+1, alphaKeys) alphaVerificationScript, err := smartcontract.CreateMultiSigRedeemScript(len(alphaKeys)*2/3+1, alphaKeys)
if err != nil { if err != nil {
return fmt.Errorf("get Alphabet verification script: %w", err) return fmt.Errorf("could not get Alphabet verification script: %w", err)
} }
if !s[1].Account.Equals(hash.Hash160(alphaVerificationScript)) { if !s[1].Account.Equals(hash.Hash160(alphaVerificationScript)) {
@ -346,7 +346,7 @@ func (p Preparator) validateWitnesses(w []transaction.Witness, alphaKeys keys.Pu
alphaVerificationScript, err := smartcontract.CreateMultiSigRedeemScript(len(alphaKeys)*2/3+1, alphaKeys) alphaVerificationScript, err := smartcontract.CreateMultiSigRedeemScript(len(alphaKeys)*2/3+1, alphaKeys)
if err != nil { if err != nil {
return fmt.Errorf("get Alphabet verification script: %w", err) return fmt.Errorf("could not get Alphabet verification script: %w", err)
} }
// the second one must be witness of the current // the second one must be witness of the current

View file

@ -26,7 +26,7 @@ func (Designate) MorphEvent() {}
func ParseDesignate(e *state.ContainedNotificationEvent) (event.Event, error) { func ParseDesignate(e *state.ContainedNotificationEvent) (event.Event, error) {
params, err := event.ParseStackArray(e) params, err := event.ParseStackArray(e)
if err != nil { if err != nil {
return nil, fmt.Errorf("parse stack items from notify event: %w", err) return nil, fmt.Errorf("could not parse stack items from notify event: %w", err)
} }
if len(params) != 2 { if len(params) != 2 {

View file

@ -20,9 +20,13 @@ type scriptHashValue struct {
hash util.Uint160 hash util.Uint160
} }
type typeValue struct {
typ Type
}
type scriptHashWithType struct { type scriptHashWithType struct {
Hash util.Uint160 scriptHashValue
Type Type typeValue
} }
type notaryRequestTypes struct { type notaryRequestTypes struct {
@ -69,6 +73,16 @@ func (s scriptHashValue) ScriptHash() util.Uint160 {
return s.hash return s.hash
} }
// SetType is an event type setter.
func (s *typeValue) SetType(v Type) {
s.typ = v
}
// GetType is an event type getter.
func (s typeValue) GetType() Type {
return s.typ
}
// WorkerPoolHandler sets closure over worker pool w with passed handler h. // WorkerPoolHandler sets closure over worker pool w with passed handler h.
func WorkerPoolHandler(w util2.WorkerPool, h Handler, log *logger.Logger) Handler { func WorkerPoolHandler(w util2.WorkerPool, h Handler, log *logger.Logger) Handler {
return func(ctx context.Context, e Event) { return func(ctx context.Context, e Event) {