rpcclient: drop deprecated Client APIs
Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
parent
cef70091f6
commit
413caac941
14 changed files with 36 additions and 1831 deletions
14
ROADMAP.md
14
ROADMAP.md
|
@ -26,20 +26,6 @@ APIs/commands/configurations will be removed and here is a list of scheduled
|
|||
breaking changes. Consider changing your code/scripts/configurations if you're
|
||||
using anything mentioned here.
|
||||
|
||||
## Old RPC client APIs
|
||||
|
||||
A huge set of RPC client APIs was deprecated in versions 0.99.2 and 0.99.3
|
||||
(August-September 2022), including very frequently used ones like
|
||||
SignAndPushInvocationTx, AddNetworkFee, TransferNEP17. A new set of
|
||||
invoker/actor/unwrap/nep17/etc packages was introduced decoupling these
|
||||
functions from RPC client and simplifying typical backend code. Please refer
|
||||
to rpcclient package documentation for specific replacements for each of these
|
||||
APIs and convert your code to using them.
|
||||
|
||||
While a lot of the code is already converted to new APIs, old ones still can
|
||||
be used in some code not known to us. Therefore we will remove old APIs not
|
||||
earlier than May 2023, with 0.103.0 release.
|
||||
|
||||
## WSClient Notifications channel and SubscribeFor* APIs
|
||||
|
||||
Version 0.99.5 of NeoGo introduces a new set of subscription APIs that gives
|
||||
|
|
|
@ -30,6 +30,14 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// transferTarget represents target address, token amount and data for transfer.
|
||||
type transferTarget struct {
|
||||
Token util.Uint160
|
||||
Address util.Uint160
|
||||
Amount int64
|
||||
Data any
|
||||
}
|
||||
|
||||
var (
|
||||
tokenFlag = cli.StringFlag{
|
||||
Name: "token",
|
||||
|
@ -531,7 +539,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
|||
return cli.NewExitError("empty recipients list", 1)
|
||||
}
|
||||
var (
|
||||
recipients []rpcclient.TransferTarget
|
||||
recipients []transferTarget
|
||||
cosignersOffset = ctx.NArg()
|
||||
)
|
||||
cache := make(map[string]*wallet.Token)
|
||||
|
@ -564,7 +572,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
|||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
|
||||
}
|
||||
recipients = append(recipients, rpcclient.TransferTarget{
|
||||
recipients = append(recipients, transferTarget{
|
||||
Token: token.Hash,
|
||||
Address: addr,
|
||||
Amount: amount.Int64(),
|
||||
|
@ -690,7 +698,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
|||
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||
}
|
||||
|
||||
func makeMultiTransferNEP17(act *actor.Actor, recipients []rpcclient.TransferTarget) (*transaction.Transaction, error) {
|
||||
func makeMultiTransferNEP17(act *actor.Actor, recipients []transferTarget) (*transaction.Transaction, error) {
|
||||
scr := smartcontract.NewBuilder()
|
||||
for i := range recipients {
|
||||
scr.InvokeWithAssert(recipients[i].Token, "transfer", act.Sender(),
|
||||
|
|
|
@ -392,34 +392,17 @@ subpackage with an example written in Go doc.
|
|||
that includes simple-signature accounts and multisignature accounts where
|
||||
the client has one of the keys (in which case an invocation script is
|
||||
created that pushes just one signature onto the stack).
|
||||
10. Define lifetime for the fallback transaction. Let the `fallbackValidFor` be
|
||||
the lifetime. Let `N` be the current chain's height and `VUB` be
|
||||
`ValidUntilBlock` value estimated at step 3. Then, the notary node is trying to
|
||||
collect signatures for the main transaction from `N` up to
|
||||
`VUB-fallbackValidFor`. In case of failure after `VUB-fallbackValidFor`-th
|
||||
block is accepted, the notary node abandons attempts to complete the main transaction and
|
||||
tries to push all associated fallbacks. Use the following rules to define
|
||||
`fallbackValidFor`:
|
||||
- `fallbackValidFor` shouldn't be more than `MaxNotValidBeforeDelta` value.
|
||||
- Use notary package's GetMaxNotValidBeforeDelta to check `MaxNotValidBefore` value.
|
||||
11. Construct a script for the fallback transaction. The script may do something useful,
|
||||
i.g. invoke method of a contract. However, if you don't need to perform anything
|
||||
special on fallback invocation, you can use simple `opcode.RET` script.
|
||||
12. Sign and submit P2P notary request. Use
|
||||
[func (*Client) SignAndPushP2PNotaryRequest](https://pkg.go.dev/github.com/nspcc-dev/neo-go@v0.97.2/pkg/rpcclient#Client.SignAndPushP2PNotaryRequest) for it.
|
||||
10. Sign and submit P2P notary request. Use
|
||||
[func (*Actor) Notarize](https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/rpcclient/notary#Actor.Notarize) for it.
|
||||
- Use the signed main transaction from step 9 as `mainTx` argument.
|
||||
- Use the fallback script from step 10 as `fallbackScript` argument.
|
||||
- Use `-1` as `fallbackSysFee` argument to define system fee by test
|
||||
invocation or provide any custom value.
|
||||
- Use `0` as `fallbackNetFee` argument not to add extra network fee to the
|
||||
fallback.
|
||||
- Use the `fallbackValidFor` estimated at step 9 as `fallbackValidFor` argument.
|
||||
- Use your account you'd like to send request (and fallback transaction) from
|
||||
to sign the request (and fallback transaction).
|
||||
|
||||
`SignAndPushP2PNotaryRequest` will construct and sign a fallback transaction,
|
||||
construct and sign a P2PNotaryRequest and submit it to the RPC node. The
|
||||
resulting notary request and an error are returned.
|
||||
`Notarize` will construct and sign a fallback transaction using `Actor`
|
||||
configuration (just a simple `RET` script by default), pack both transactions
|
||||
into a P2PNotaryRequest and submit it to the RPC node. It returns hashes of
|
||||
the main and fallback transactions as well as their `ValidUntilBlock` value.
|
||||
If you need more control over fallback transction use `Actor` options or
|
||||
[func (*Actor) SendRequest](https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/rpcclient/notary#Actor.SendRequest)
|
||||
API.
|
||||
|
||||
After P2PNotaryRequests are sent, participants should wait for one of their
|
||||
transactions (main or fallback) to get accepted into one of subsequent blocks.
|
||||
|
|
|
@ -22,8 +22,6 @@ import (
|
|||
const (
|
||||
defaultDialTimeout = 4 * time.Second
|
||||
defaultRequestTimeout = 4 * time.Second
|
||||
// Number of blocks after which cache is expired.
|
||||
cacheTimeout = 100
|
||||
)
|
||||
|
||||
// Client represents the middleman for executing JSON RPC calls
|
||||
|
@ -77,17 +75,9 @@ type cache struct {
|
|||
initDone bool
|
||||
network netmode.Magic
|
||||
stateRootInHeader bool
|
||||
calculateValidUntilBlock calculateValidUntilBlockCache
|
||||
nativeHashes map[string]util.Uint160
|
||||
}
|
||||
|
||||
// calculateValidUntilBlockCache stores a cached number of validators and
|
||||
// cache expiration value in blocks.
|
||||
type calculateValidUntilBlockCache struct {
|
||||
validatorsCount uint32
|
||||
expiresAt uint32
|
||||
}
|
||||
|
||||
// New returns a new Client ready to use. You should call Init method to
|
||||
// initialize stateroot setting for the network the client is operating on if
|
||||
// you plan using GetBlock*.
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// InvokeAndPackIteratorResults creates a script containing System.Contract.Call
|
||||
// of the specified contract with the specified arguments. It assumes that the
|
||||
// specified operation will return iterator. The script traverses the resulting
|
||||
// iterator, packs all its values into array and pushes the resulting array on
|
||||
// stack. Constructed script is invoked via `invokescript` JSON-RPC API using
|
||||
// the provided signers. The result of the script invocation contains single array
|
||||
// stackitem on stack if invocation HALTed. InvokeAndPackIteratorResults can be
|
||||
// used to interact with JSON-RPC server where iterator sessions are disabled to
|
||||
// retrieve iterator values via single `invokescript` JSON-RPC call. It returns
|
||||
// maxIteratorResultItems items at max which is set to
|
||||
// config.DefaultMaxIteratorResultItems by default.
|
||||
//
|
||||
// Deprecated: please use more convenient and powerful invoker.Invoker interface with
|
||||
// CallAndExpandIterator method. This method will be removed in future versions.
|
||||
func (c *Client) InvokeAndPackIteratorResults(contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer, maxIteratorResultItems ...int) (*result.Invoke, error) {
|
||||
max := config.DefaultMaxIteratorResultItems
|
||||
if len(maxIteratorResultItems) != 0 {
|
||||
max = maxIteratorResultItems[0]
|
||||
}
|
||||
values, err := smartcontract.ExpandParameterToEmitable(smartcontract.Parameter{
|
||||
Type: smartcontract.ArrayType,
|
||||
Value: params,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("expanding params to emitable: %w", err)
|
||||
}
|
||||
bytes, err := smartcontract.CreateCallAndUnwrapIteratorScript(contract, operation, max, values.([]any)...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create iterator unwrapper script: %w", err)
|
||||
}
|
||||
return c.InvokeScript(bytes, signers)
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
// Various non-policy things from native contracts.
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"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/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nns"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// GetOraclePrice invokes `getPrice` method on a native Oracle contract.
|
||||
//
|
||||
// Deprecated: please use oracle subpackage.
|
||||
func (c *Client) GetOraclePrice() (int64, error) {
|
||||
oracleHash, err := c.GetNativeContractHash(nativenames.Oracle)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native Oracle hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(oracleHash, "getPrice")
|
||||
}
|
||||
|
||||
// GetNNSPrice invokes `getPrice` method on a NeoNameService contract with the specified hash.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) GetNNSPrice(nnsHash util.Uint160) (int64, error) {
|
||||
return c.invokeNativeGetMethod(nnsHash, "getPrice")
|
||||
}
|
||||
|
||||
// GetGasPerBlock invokes `getGasPerBlock` method on a native NEO contract.
|
||||
//
|
||||
// Deprecated: please use neo subpackage. This method will be removed in future releases.
|
||||
func (c *Client) GetGasPerBlock() (int64, error) {
|
||||
return c.getFromNEO("getGasPerBlock")
|
||||
}
|
||||
|
||||
// GetCandidateRegisterPrice invokes `getRegisterPrice` method on native NEO contract.
|
||||
//
|
||||
// Deprecated: please use neo subpackage. This method will be removed in future releases.
|
||||
func (c *Client) GetCandidateRegisterPrice() (int64, error) {
|
||||
return c.getFromNEO("getRegisterPrice")
|
||||
}
|
||||
|
||||
func (c *Client) getFromNEO(meth string) (int64, error) {
|
||||
neoHash, err := c.GetNativeContractHash(nativenames.Neo)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native NEO hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(neoHash, meth)
|
||||
}
|
||||
|
||||
// GetDesignatedByRole invokes `getDesignatedByRole` method on a native RoleManagement contract.
|
||||
//
|
||||
// Deprecated: please use rolemgmt package.
|
||||
func (c *Client) GetDesignatedByRole(role noderoles.Role, index uint32) (keys.PublicKeys, error) {
|
||||
rmHash, err := c.GetNativeContractHash(nativenames.Designation)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get native RoleManagement hash: %w", err)
|
||||
}
|
||||
arr, err := unwrap.Array(c.reader.Call(rmHash, "getDesignatedByRole", int64(role), index))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pks := make(keys.PublicKeys, len(arr))
|
||||
for i, item := range arr {
|
||||
val, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid array element #%d: %s", i, item.Type())
|
||||
}
|
||||
pks[i], err = keys.NewPublicKeyFromBytes(val, elliptic.P256())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return pks, nil
|
||||
}
|
||||
|
||||
// NNSResolve invokes `resolve` method on a NameService contract with the specified hash.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) NNSResolve(nnsHash util.Uint160, name string, typ nns.RecordType) (string, error) {
|
||||
if typ == nns.CNAME {
|
||||
return "", errors.New("can't resolve CNAME record type")
|
||||
}
|
||||
return unwrap.UTF8String(c.reader.Call(nnsHash, "resolve", name, int64(typ)))
|
||||
}
|
||||
|
||||
// NNSIsAvailable invokes `isAvailable` method on a NeoNameService contract with the specified hash.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) NNSIsAvailable(nnsHash util.Uint160, name string) (bool, error) {
|
||||
return unwrap.Bool(c.reader.Call(nnsHash, "isAvailable", name))
|
||||
}
|
||||
|
||||
// NNSGetAllRecords returns iterator over records for a given name from NNS service.
|
||||
// First return value is the session ID, the second one is Iterator itself, the
|
||||
// third one is an error. Use TraverseIterator method to traverse iterator values or
|
||||
// TerminateSession to terminate opened iterator session. See TraverseIterator and
|
||||
// TerminateSession documentation for more details.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) NNSGetAllRecords(nnsHash util.Uint160, name string) (uuid.UUID, result.Iterator, error) {
|
||||
return unwrap.SessionIterator(c.reader.Call(nnsHash, "getAllRecords", name))
|
||||
}
|
||||
|
||||
// NNSUnpackedGetAllRecords returns a set of records for a given name from NNS service
|
||||
// (config.DefaultMaxIteratorResultItems at max). It differs from NNSGetAllRecords in
|
||||
// that no iterator session is used to retrieve values from iterator. Instead, unpacking
|
||||
// VM script is created and invoked via `invokescript` JSON-RPC call.
|
||||
//
|
||||
// Deprecated: please use nns subpackage. This method will be removed in future versions.
|
||||
func (c *Client) NNSUnpackedGetAllRecords(nnsHash util.Uint160, name string) ([]nns.RecordState, error) {
|
||||
arr, err := unwrap.Array(c.reader.CallAndExpandIterator(nnsHash, "getAllRecords", config.DefaultMaxIteratorResultItems, name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := make([]nns.RecordState, len(arr))
|
||||
for i := range arr {
|
||||
rs, ok := arr[i].Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: not a struct", i)
|
||||
}
|
||||
if len(rs) != 3 {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: wrong number of elements", i)
|
||||
}
|
||||
name, err := rs[0].TryBytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: %w", i, err)
|
||||
}
|
||||
typ, err := rs[1].TryInteger()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: %w", i, err)
|
||||
}
|
||||
data, err := rs[2].TryBytes()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: %w", i, err)
|
||||
}
|
||||
u64Typ := typ.Uint64()
|
||||
if !typ.IsUint64() || u64Typ > 255 {
|
||||
return nil, fmt.Errorf("failed to decode RecordState from stackitem #%d: bad type", i)
|
||||
}
|
||||
res[i] = nns.RecordState{
|
||||
Name: string(name),
|
||||
Type: nns.RecordType(u64Typ),
|
||||
Data: string(data),
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetNotaryServiceFeePerKey returns a reward per notary request key for the designated
|
||||
// notary nodes. It doesn't cache the result.
|
||||
//
|
||||
// Deprecated: please use the Notary contract wrapper from the notary subpackage. This
|
||||
// method will be removed in future versions.
|
||||
func (c *Client) GetNotaryServiceFeePerKey() (int64, error) {
|
||||
notaryHash, err := c.GetNativeContractHash(nativenames.Notary)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native Notary hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(notaryHash, "getNotaryServiceFeePerKey")
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
// nepDecimals invokes `decimals` NEP* method on the specified contract.
|
||||
func (c *Client) nepDecimals(tokenHash util.Uint160) (int64, error) {
|
||||
return unwrap.Int64(c.reader.Call(tokenHash, "decimals"))
|
||||
}
|
||||
|
||||
// nepSymbol invokes `symbol` NEP* method on the specified contract.
|
||||
func (c *Client) nepSymbol(tokenHash util.Uint160) (string, error) {
|
||||
return unwrap.PrintableASCIIString(c.reader.Call(tokenHash, "symbol"))
|
||||
}
|
||||
|
||||
// nepTotalSupply invokes `totalSupply` NEP* method on the specified contract.
|
||||
func (c *Client) nepTotalSupply(tokenHash util.Uint160) (int64, error) {
|
||||
return unwrap.Int64(c.reader.Call(tokenHash, "totalSupply"))
|
||||
}
|
||||
|
||||
// nepBalanceOf invokes `balanceOf` NEP* method on the specified contract.
|
||||
func (c *Client) nepBalanceOf(tokenHash, acc util.Uint160, tokenID []byte) (int64, error) {
|
||||
params := []any{acc}
|
||||
if tokenID != nil {
|
||||
params = append(params, tokenID)
|
||||
}
|
||||
return unwrap.Int64(c.reader.Call(tokenHash, "balanceOf", params...))
|
||||
}
|
||||
|
||||
// nepTokenInfo returns full NEP* token info.
|
||||
func (c *Client) nepTokenInfo(tokenHash util.Uint160, standard string) (*wallet.Token, error) {
|
||||
cs, err := c.GetContractStateByHash(tokenHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var isStandardOK bool
|
||||
for _, st := range cs.Manifest.SupportedStandards {
|
||||
if st == standard {
|
||||
isStandardOK = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isStandardOK {
|
||||
return nil, fmt.Errorf("token %s does not support %s standard", tokenHash.StringLE(), standard)
|
||||
}
|
||||
symbol, err := c.nepSymbol(tokenHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decimals, err := c.nepDecimals(tokenHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wallet.NewToken(tokenHash, cs.Manifest.Name, symbol, decimals, standard), nil
|
||||
}
|
|
@ -1,232 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
// NEP11Decimals invokes `decimals` NEP-11 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11Decimals(tokenHash util.Uint160) (int64, error) {
|
||||
return c.nepDecimals(tokenHash)
|
||||
}
|
||||
|
||||
// NEP11Symbol invokes `symbol` NEP-11 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11Symbol(tokenHash util.Uint160) (string, error) {
|
||||
return c.nepSymbol(tokenHash)
|
||||
}
|
||||
|
||||
// NEP11TotalSupply invokes `totalSupply` NEP-11 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11TotalSupply(tokenHash util.Uint160) (int64, error) {
|
||||
return c.nepTotalSupply(tokenHash)
|
||||
}
|
||||
|
||||
// NEP11BalanceOf invokes `balanceOf` NEP-11 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11BalanceOf(tokenHash, owner util.Uint160) (int64, error) {
|
||||
return c.nepBalanceOf(tokenHash, owner, nil)
|
||||
}
|
||||
|
||||
// NEP11TokenInfo returns full NEP-11 token info.
|
||||
//
|
||||
// Deprecated: please use Info method from the neptoken subpackage. This method
|
||||
// will be removed in future versions.
|
||||
func (c *Client) NEP11TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) {
|
||||
return c.nepTokenInfo(tokenHash, manifest.NEP11StandardName)
|
||||
}
|
||||
|
||||
// TransferNEP11 creates an invocation transaction that invokes 'transfer' method
|
||||
// on the given token to move the whole NEP-11 token with the specified token ID to
|
||||
// the given account and sends it to the network returning just a hash of it.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) TransferNEP11(acc *wallet.Account, to util.Uint160,
|
||||
tokenHash util.Uint160, tokenID string, data any, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, to, tokenID, data)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
||||
|
||||
// CreateNEP11TransferTx creates an invocation transaction for the 'transfer'
|
||||
// method of the given contract (token) to move the whole (or the specified amount
|
||||
// of) NEP-11 token with the specified token ID to the given account and returns it.
|
||||
// The returned transaction is not signed. CreateNEP11TransferTx is also a
|
||||
// helper for TransferNEP11 and TransferNEP11D.
|
||||
// `args` for TransferNEP11: to util.Uint160, tokenID string, data interface{};
|
||||
// `args` for TransferNEP11D: from, to util.Uint160, amount int64, tokenID string, data interface{}.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) CreateNEP11TransferTx(acc *wallet.Account, tokenHash util.Uint160,
|
||||
gas int64, cosigners []SignerAccount, args ...any) (*transaction.Transaction, error) {
|
||||
script, err := smartcontract.CreateCallWithAssertScript(tokenHash, "transfer", args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create NEP-11 transfer script: %w", err)
|
||||
}
|
||||
return c.CreateTxFromScript(script, acc, -1, gas, append([]SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: acc.ScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc,
|
||||
}}, cosigners...))
|
||||
}
|
||||
|
||||
// NEP11TokensOf returns iterator over token IDs for the specified owner of the
|
||||
// specified NFT token. First return value is the session ID, the second one is
|
||||
// Iterator itself, the third one is an error. Use TraverseIterator method to
|
||||
// traverse iterator values or TerminateSession to terminate opened iterator
|
||||
// session. See TraverseIterator and TerminateSession documentation for more details.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11TokensOf(tokenHash util.Uint160, owner util.Uint160) (uuid.UUID, result.Iterator, error) {
|
||||
return unwrap.SessionIterator(c.reader.Call(tokenHash, "tokensOf", owner))
|
||||
}
|
||||
|
||||
// NEP11UnpackedTokensOf returns an array of token IDs for the specified owner of the specified NFT token
|
||||
// (config.DefaultMaxIteratorResultItems at max). It differs from NEP11TokensOf in that no iterator session
|
||||
// is used to retrieve values from iterator. Instead, unpacking VM script is created and invoked via
|
||||
// `invokescript` JSON-RPC call.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11UnpackedTokensOf(tokenHash util.Uint160, owner util.Uint160) ([][]byte, error) {
|
||||
return unwrap.ArrayOfBytes(c.reader.CallAndExpandIterator(tokenHash, "tokensOf", config.DefaultMaxIteratorResultItems, owner))
|
||||
}
|
||||
|
||||
// Non-divisible NFT methods section start.
|
||||
|
||||
// NEP11NDOwnerOf invokes `ownerOf` non-divisible NEP-11 method with the
|
||||
// specified token ID on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11NDOwnerOf(tokenHash util.Uint160, tokenID []byte) (util.Uint160, error) {
|
||||
return unwrap.Uint160(c.reader.Call(tokenHash, "ownerOf", tokenID))
|
||||
}
|
||||
|
||||
// Non-divisible NFT methods section end.
|
||||
|
||||
// Divisible NFT methods section start.
|
||||
|
||||
// TransferNEP11D creates an invocation transaction that invokes 'transfer'
|
||||
// method on the given token to move the specified amount of divisible NEP-11 assets
|
||||
// (in FixedN format using contract's number of decimals) to the given account and
|
||||
// sends it to the network returning just a hash of it.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) TransferNEP11D(acc *wallet.Account, to util.Uint160,
|
||||
tokenHash util.Uint160, amount int64, tokenID []byte, data any, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, acc.ScriptHash(), to, amount, tokenID, data)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
||||
|
||||
// NEP11DBalanceOf invokes `balanceOf` divisible NEP-11 method on a
|
||||
// specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11DBalanceOf(tokenHash, owner util.Uint160, tokenID []byte) (int64, error) {
|
||||
return c.nepBalanceOf(tokenHash, owner, tokenID)
|
||||
}
|
||||
|
||||
// NEP11DOwnerOf returns iterator over the specified NEP-11 divisible token owners. First return value
|
||||
// is the session ID, the second one is Iterator itself, the third one is an error. Use TraverseIterator
|
||||
// method to traverse iterator values or TerminateSession to terminate opened iterator session. See
|
||||
// TraverseIterator and TerminateSession documentation for more details.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11DOwnerOf(tokenHash util.Uint160, tokenID []byte) (uuid.UUID, result.Iterator, error) {
|
||||
return unwrap.SessionIterator(c.reader.Call(tokenHash, "ownerOf", tokenID))
|
||||
}
|
||||
|
||||
// NEP11DUnpackedOwnerOf returns list of the specified NEP-11 divisible token owners
|
||||
// (config.DefaultMaxIteratorResultItems at max). It differs from NEP11DOwnerOf in that no
|
||||
// iterator session is used to retrieve values from iterator. Instead, unpacking VM
|
||||
// script is created and invoked via `invokescript` JSON-RPC call.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11DUnpackedOwnerOf(tokenHash util.Uint160, tokenID []byte) ([]util.Uint160, error) {
|
||||
arr, err := unwrap.ArrayOfBytes(c.reader.CallAndExpandIterator(tokenHash, "ownerOf", config.DefaultMaxIteratorResultItems, tokenID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
owners := make([]util.Uint160, len(arr))
|
||||
for i := range arr {
|
||||
owners[i], err = util.Uint160DecodeBytesBE(arr[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("not a Uint160 at %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
return owners, nil
|
||||
}
|
||||
|
||||
// Divisible NFT methods section end.
|
||||
|
||||
// Optional NFT methods section start.
|
||||
|
||||
// NEP11Properties invokes `properties` optional NEP-11 method on the
|
||||
// specified contract.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11Properties(tokenHash util.Uint160, tokenID []byte) (*stackitem.Map, error) {
|
||||
return unwrap.Map(c.reader.Call(tokenHash, "properties", tokenID))
|
||||
}
|
||||
|
||||
// NEP11Tokens returns iterator over the tokens minted by the contract. First return
|
||||
// value is the session ID, the second one is Iterator itself, the third one is an
|
||||
// error. Use TraverseIterator method to traverse iterator values or
|
||||
// TerminateSession to terminate opened iterator session. See TraverseIterator and
|
||||
// TerminateSession documentation for more details.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11Tokens(tokenHash util.Uint160) (uuid.UUID, result.Iterator, error) {
|
||||
return unwrap.SessionIterator(c.reader.Call(tokenHash, "tokens"))
|
||||
}
|
||||
|
||||
// NEP11UnpackedTokens returns list of the tokens minted by the contract
|
||||
// (config.DefaultMaxIteratorResultItems at max). It differs from NEP11Tokens in that no
|
||||
// iterator session is used to retrieve values from iterator. Instead, unpacking
|
||||
// VM script is created and invoked via `invokescript` JSON-RPC call.
|
||||
//
|
||||
// Deprecated: please use nep11 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP11UnpackedTokens(tokenHash util.Uint160) ([][]byte, error) {
|
||||
return unwrap.ArrayOfBytes(c.reader.CallAndExpandIterator(tokenHash, "tokens", config.DefaultMaxIteratorResultItems))
|
||||
}
|
||||
|
||||
// Optional NFT methods section end.
|
|
@ -1,188 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
// TransferTarget represents target address, token amount and data for transfer.
|
||||
type TransferTarget struct {
|
||||
Token util.Uint160
|
||||
Address util.Uint160
|
||||
Amount int64
|
||||
Data any
|
||||
}
|
||||
|
||||
// SignerAccount represents combination of the transaction.Signer and the
|
||||
// corresponding wallet.Account.
|
||||
type SignerAccount struct {
|
||||
Signer transaction.Signer
|
||||
Account *wallet.Account
|
||||
}
|
||||
|
||||
// NEP17Decimals invokes `decimals` NEP-17 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP17Decimals(tokenHash util.Uint160) (int64, error) {
|
||||
return c.nepDecimals(tokenHash)
|
||||
}
|
||||
|
||||
// NEP17Symbol invokes `symbol` NEP-17 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) NEP17Symbol(tokenHash util.Uint160) (string, error) {
|
||||
return c.nepSymbol(tokenHash)
|
||||
}
|
||||
|
||||
// NEP17TotalSupply invokes `totalSupply` NEP-17 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions. This method is also wrong since tokens can return values overflowing
|
||||
// int64.
|
||||
func (c *Client) NEP17TotalSupply(tokenHash util.Uint160) (int64, error) {
|
||||
return c.nepTotalSupply(tokenHash)
|
||||
}
|
||||
|
||||
// NEP17BalanceOf invokes `balanceOf` NEP-17 method on the specified contract.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions. This method is also wrong since tokens can return values overflowing
|
||||
// int64.
|
||||
func (c *Client) NEP17BalanceOf(tokenHash, acc util.Uint160) (int64, error) {
|
||||
return c.nepBalanceOf(tokenHash, acc, nil)
|
||||
}
|
||||
|
||||
// NEP17TokenInfo returns full NEP-17 token info.
|
||||
//
|
||||
// Deprecated: please use Info method from the neptoken subpackage. This method
|
||||
// will be removed in future versions.
|
||||
func (c *Client) NEP17TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) {
|
||||
return c.nepTokenInfo(tokenHash, manifest.NEP17StandardName)
|
||||
}
|
||||
|
||||
// CreateNEP17TransferTx creates an invocation transaction for the 'transfer'
|
||||
// method of the given contract (token) to move the specified amount of NEP-17 assets
|
||||
// (in FixedN format using contract's number of decimals) to the given account and
|
||||
// returns it. The returned transaction is not signed.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) CreateNEP17TransferTx(acc *wallet.Account, to util.Uint160,
|
||||
token util.Uint160, amount int64, gas int64, data any, cosigners []SignerAccount) (*transaction.Transaction, error) {
|
||||
return c.CreateNEP17MultiTransferTx(acc, gas, []TransferTarget{
|
||||
{Token: token,
|
||||
Address: to,
|
||||
Amount: amount,
|
||||
Data: data,
|
||||
},
|
||||
}, cosigners)
|
||||
}
|
||||
|
||||
// CreateNEP17MultiTransferTx creates an invocation transaction for performing
|
||||
// NEP-17 transfers from a single sender to multiple recipients with the given
|
||||
// data and cosigners. The transaction sender is included with the CalledByEntry
|
||||
// scope by default.
|
||||
//
|
||||
// Deprecated: please use nep17 package (when transferring the same token) or
|
||||
// [smartcontract.Builder] (when transferring multiple tokens), this method will
|
||||
// be removed in future versions.
|
||||
func (c *Client) CreateNEP17MultiTransferTx(acc *wallet.Account, gas int64,
|
||||
recipients []TransferTarget, cosigners []SignerAccount) (*transaction.Transaction, error) {
|
||||
from := acc.ScriptHash()
|
||||
b := smartcontract.NewBuilder()
|
||||
for i := range recipients {
|
||||
b.InvokeWithAssert(recipients[i].Token, "transfer",
|
||||
from, recipients[i].Address, recipients[i].Amount, recipients[i].Data)
|
||||
}
|
||||
script, err := b.Script()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create transfer script: %w", err)
|
||||
}
|
||||
return c.CreateTxFromScript(script, acc, -1, gas, append([]SignerAccount{{
|
||||
Signer: transaction.Signer{
|
||||
Account: from,
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc,
|
||||
}}, cosigners...))
|
||||
}
|
||||
|
||||
// CreateTxFromScript creates transaction and properly sets cosigners and NetworkFee.
|
||||
// If sysFee <= 0, it is determined via result of `invokescript` RPC. You should
|
||||
// initialize network magic with Init before calling CreateTxFromScript.
|
||||
//
|
||||
// Deprecated: please use actor.Actor API, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) CreateTxFromScript(script []byte, acc *wallet.Account, sysFee, netFee int64,
|
||||
cosigners []SignerAccount) (*transaction.Transaction, error) {
|
||||
signers, accounts, err := getSigners(acc, cosigners)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to construct tx signers: %w", err)
|
||||
}
|
||||
if sysFee < 0 {
|
||||
result, err := c.InvokeScript(script, signers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't add system fee to transaction: %w", err)
|
||||
}
|
||||
if result.State != "HALT" {
|
||||
return nil, fmt.Errorf("can't add system fee to transaction: bad vm state: %s due to an error: %s", result.State, result.FaultException)
|
||||
}
|
||||
sysFee = result.GasConsumed
|
||||
}
|
||||
|
||||
tx := transaction.New(script, sysFee)
|
||||
tx.Signers = signers
|
||||
|
||||
tx.ValidUntilBlock, err = c.CalculateValidUntilBlock()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add validUntilBlock to transaction: %w", err)
|
||||
}
|
||||
|
||||
err = c.AddNetworkFee(tx, netFee, accounts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add network fee: %w", err)
|
||||
}
|
||||
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// TransferNEP17 creates an invocation transaction that invokes 'transfer' method
|
||||
// on the given token to move the specified amount of NEP-17 assets (in FixedN format
|
||||
// using contract's number of decimals) to the given account with the data specified and
|
||||
// sends it to the network returning just a hash of it. Cosigners argument
|
||||
// specifies a set of the transaction cosigners (may be nil or may include sender)
|
||||
// with a proper scope and the accounts to cosign the transaction. If cosigning is
|
||||
// impossible (e.g. due to locked cosigner's account) an error is returned.
|
||||
//
|
||||
// Deprecated: please use nep17 package, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) TransferNEP17(acc *wallet.Account, to util.Uint160, token util.Uint160,
|
||||
amount int64, gas int64, data any, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP17TransferTx(acc, to, token, amount, gas, data, cosigners)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
||||
|
||||
// MultiTransferNEP17 is similar to TransferNEP17, buf allows to have multiple recipients.
|
||||
//
|
||||
// Deprecated: please use nep17 package (when transferring the same token) or
|
||||
// [smartcontract.Builder] (when transferring multiple tokens), this method will
|
||||
// be removed in future versions.
|
||||
func (c *Client) MultiTransferNEP17(acc *wallet.Account, gas int64, recipients []TransferTarget, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateNEP17MultiTransferTx(acc, gas, recipients, cosigners)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package rpcclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// GetFeePerByte invokes `getFeePerByte` method on a native Policy contract.
|
||||
//
|
||||
// Deprecated: please use policy subpackage.
|
||||
func (c *Client) GetFeePerByte() (int64, error) {
|
||||
return c.invokeNativePolicyMethod("getFeePerByte")
|
||||
}
|
||||
|
||||
// GetExecFeeFactor invokes `getExecFeeFactor` method on a native Policy contract.
|
||||
//
|
||||
// Deprecated: please use policy subpackage.
|
||||
func (c *Client) GetExecFeeFactor() (int64, error) {
|
||||
return c.invokeNativePolicyMethod("getExecFeeFactor")
|
||||
}
|
||||
|
||||
// GetStoragePrice invokes `getStoragePrice` method on a native Policy contract.
|
||||
//
|
||||
// Deprecated: please use policy subpackage.
|
||||
func (c *Client) GetStoragePrice() (int64, error) {
|
||||
return c.invokeNativePolicyMethod("getStoragePrice")
|
||||
}
|
||||
|
||||
// GetMaxNotValidBeforeDelta invokes `getMaxNotValidBeforeDelta` method on a native Notary contract.
|
||||
//
|
||||
// Deprecated: please use notary subpackage. This method will be removed
|
||||
// in future versions.
|
||||
func (c *Client) GetMaxNotValidBeforeDelta() (int64, error) {
|
||||
notaryHash, err := c.GetNativeContractHash(nativenames.Notary)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native Notary hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(notaryHash, "getMaxNotValidBeforeDelta")
|
||||
}
|
||||
|
||||
// invokeNativePolicy method invokes Get* method on a native Policy contract.
|
||||
func (c *Client) invokeNativePolicyMethod(operation string) (int64, error) {
|
||||
policyHash, err := c.GetNativeContractHash(nativenames.Policy)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get native Policy hash: %w", err)
|
||||
}
|
||||
return c.invokeNativeGetMethod(policyHash, operation)
|
||||
}
|
||||
|
||||
func (c *Client) invokeNativeGetMethod(hash util.Uint160, operation string) (int64, error) {
|
||||
return unwrap.Int64(c.reader.Call(hash, operation))
|
||||
}
|
||||
|
||||
// IsBlocked invokes `isBlocked` method on native Policy contract.
|
||||
//
|
||||
// Deprecated: please use policy subpackage.
|
||||
func (c *Client) IsBlocked(hash util.Uint160) (bool, error) {
|
||||
policyHash, err := c.GetNativeContractHash(nativenames.Policy)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get native Policy hash: %w", err)
|
||||
}
|
||||
return unwrap.Bool(c.reader.Call(policyHash, "isBlocked", hash))
|
||||
}
|
|
@ -9,27 +9,19 @@ import (
|
|||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativeprices"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"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/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||
)
|
||||
|
||||
var errNetworkNotInitialized = errors.New("RPC client network is not initialized")
|
||||
|
@ -103,7 +95,7 @@ func (c *Client) getBlock(param any) (*block.Block, error) {
|
|||
return nil, err
|
||||
}
|
||||
r := io.NewBinReaderFromBuf(resp)
|
||||
sr, err := c.StateRootInHeader()
|
||||
sr, err := c.stateRootInHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -136,7 +128,7 @@ func (c *Client) getBlockVerbose(param any) (*result.Block, error) {
|
|||
resp = &result.Block{}
|
||||
err error
|
||||
)
|
||||
sr, err := c.StateRootInHeader()
|
||||
sr, err := c.stateRootInHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -171,7 +163,7 @@ func (c *Client) GetBlockHeader(hash util.Uint256) (*block.Header, error) {
|
|||
if err := c.performRequest("getblockheader", params, &resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sr, err := c.StateRootInHeader()
|
||||
sr, err := c.stateRootInHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -844,234 +836,6 @@ func (c *Client) SubmitRawOracleResponse(ps []any) error {
|
|||
return c.performRequest("submitoracleresponse", ps, new(result.RelayResult))
|
||||
}
|
||||
|
||||
// SignAndPushInvocationTx signs and pushes the given script as an invocation
|
||||
// transaction using the given wif to sign it and the given cosigners to cosign it if
|
||||
// possible. It spends the amount of gas specified. It returns a hash of the
|
||||
// invocation transaction and an error. If one of the cosigners accounts is
|
||||
// neither contract-based nor unlocked, an error is returned.
|
||||
//
|
||||
// Deprecated: please use actor.Actor API, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sysfee int64, netfee fixedn.Fixed8, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tx, err := c.CreateTxFromScript(script, acc, sysfee, int64(netfee), cosigners)
|
||||
if err != nil {
|
||||
return util.Uint256{}, fmt.Errorf("failed to create tx: %w", err)
|
||||
}
|
||||
return c.SignAndPushTx(tx, acc, cosigners)
|
||||
}
|
||||
|
||||
// SignAndPushTx signs the given transaction using the given wif and cosigners and pushes
|
||||
// it to the chain. It returns a hash of the transaction and an error. If one of
|
||||
// the cosigners accounts is neither contract-based nor unlocked, an error is
|
||||
// returned.
|
||||
//
|
||||
// Deprecated: please use actor.Actor API, this method will be removed in future
|
||||
// versions.
|
||||
func (c *Client) SignAndPushTx(tx *transaction.Transaction, acc *wallet.Account, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
var (
|
||||
txHash util.Uint256
|
||||
err error
|
||||
)
|
||||
m, err := c.GetNetwork()
|
||||
if err != nil {
|
||||
return txHash, fmt.Errorf("failed to sign tx: %w", err)
|
||||
}
|
||||
if err = acc.SignTx(m, tx); err != nil {
|
||||
return txHash, fmt.Errorf("failed to sign tx: %w", err)
|
||||
}
|
||||
// try to add witnesses for the rest of the signers
|
||||
for i, signer := range tx.Signers[1:] {
|
||||
var isOk bool
|
||||
for _, cosigner := range cosigners {
|
||||
if signer.Account == cosigner.Signer.Account {
|
||||
err = cosigner.Account.SignTx(m, tx)
|
||||
if err != nil { // then account is non-contract-based and locked, but let's provide more detailed error
|
||||
if paramNum := len(cosigner.Account.Contract.Parameters); paramNum != 0 && cosigner.Account.Contract.Deployed {
|
||||
return txHash, fmt.Errorf("failed to add contract-based witness for signer #%d (%s): "+
|
||||
"%d parameters must be provided to construct invocation script", i, address.Uint160ToString(signer.Account), paramNum)
|
||||
}
|
||||
return txHash, fmt.Errorf("failed to add witness for signer #%d (%s): account should be unlocked to add the signature. "+
|
||||
"Store partially-signed transaction and then use 'wallet sign' command to cosign it", i, address.Uint160ToString(signer.Account))
|
||||
}
|
||||
isOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isOk {
|
||||
return txHash, fmt.Errorf("failed to add witness for signer #%d (%s): account wasn't provided", i, address.Uint160ToString(signer.Account))
|
||||
}
|
||||
}
|
||||
txHash = tx.Hash()
|
||||
actualHash, err := c.SendRawTransaction(tx)
|
||||
if err != nil {
|
||||
return txHash, fmt.Errorf("failed to send tx: %w", err)
|
||||
}
|
||||
if !actualHash.Equals(txHash) {
|
||||
return actualHash, fmt.Errorf("sent and actual tx hashes mismatch:\n\tsent: %v\n\tactual: %v", txHash.StringLE(), actualHash.StringLE())
|
||||
}
|
||||
return txHash, nil
|
||||
}
|
||||
|
||||
// getSigners returns an array of transaction signers and corresponding accounts from
|
||||
// given sender and cosigners. If cosigners list already contains sender, the sender
|
||||
// will be placed at the start of the list.
|
||||
func getSigners(sender *wallet.Account, cosigners []SignerAccount) ([]transaction.Signer, []*wallet.Account, error) {
|
||||
var (
|
||||
signers []transaction.Signer
|
||||
accounts []*wallet.Account
|
||||
)
|
||||
from := sender.ScriptHash()
|
||||
s := transaction.Signer{
|
||||
Account: from,
|
||||
Scopes: transaction.None,
|
||||
}
|
||||
for _, c := range cosigners {
|
||||
if c.Signer.Account == from {
|
||||
s = c.Signer
|
||||
continue
|
||||
}
|
||||
signers = append(signers, c.Signer)
|
||||
accounts = append(accounts, c.Account)
|
||||
}
|
||||
signers = append([]transaction.Signer{s}, signers...)
|
||||
accounts = append([]*wallet.Account{sender}, accounts...)
|
||||
return signers, accounts, nil
|
||||
}
|
||||
|
||||
// SignAndPushP2PNotaryRequest creates and pushes a P2PNotary request constructed from the main
|
||||
// and fallback transactions using the given wif to sign it. It returns the request and an error.
|
||||
// Fallback transaction is constructed from the given script using the amount of gas specified.
|
||||
// For successful fallback transaction validation at least 2*transaction.NotaryServiceFeePerKey
|
||||
// GAS should be deposited to the Notary contract.
|
||||
// Main transaction should be constructed by the user. Several rules should be met for
|
||||
// successful main transaction acceptance:
|
||||
// 1. Native Notary contract should be a signer of the main transaction.
|
||||
// 2. Notary signer should have None scope.
|
||||
// 3. Main transaction should have dummy contract witness for Notary signer.
|
||||
// 4. Main transaction should have NotaryAssisted attribute with NKeys specified.
|
||||
// 5. NotaryAssisted attribute and dummy Notary witness (as long as the other incomplete witnesses)
|
||||
// should be paid for. Use CalculateNotaryWitness to calculate the amount of network fee to pay
|
||||
// for the attribute and Notary witness.
|
||||
// 6. Main transaction either shouldn't have all witnesses attached (in this case none of them
|
||||
// can be multisignature), or it only should have a partial multisignature.
|
||||
//
|
||||
// Note: client should be initialized before SignAndPushP2PNotaryRequest call.
|
||||
//
|
||||
// Deprecated: please use Actor from the notary subpackage. This method will be
|
||||
// deleted in future versions.
|
||||
func (c *Client) SignAndPushP2PNotaryRequest(mainTx *transaction.Transaction, fallbackScript []byte, fallbackSysFee int64, fallbackNetFee int64, fallbackValidFor uint32, acc *wallet.Account) (*payload.P2PNotaryRequest, error) {
|
||||
var err error
|
||||
notaryHash, err := c.GetNativeContractHash(nativenames.Notary)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get native Notary hash: %w", err)
|
||||
}
|
||||
from := acc.ScriptHash()
|
||||
signers := []transaction.Signer{{Account: notaryHash}, {Account: from}}
|
||||
if fallbackSysFee < 0 {
|
||||
result, err := c.InvokeScript(fallbackScript, signers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't add system fee to fallback transaction: %w", err)
|
||||
}
|
||||
if result.State != "HALT" {
|
||||
return nil, fmt.Errorf("can't add system fee to fallback transaction: bad vm state %s due to an error: %s", result.State, result.FaultException)
|
||||
}
|
||||
fallbackSysFee = result.GasConsumed
|
||||
}
|
||||
|
||||
maxNVBDelta, err := c.GetMaxNotValidBeforeDelta()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get MaxNotValidBeforeDelta")
|
||||
}
|
||||
if int64(fallbackValidFor) > maxNVBDelta {
|
||||
return nil, fmt.Errorf("fallback transaction should be valid for not more than %d blocks", maxNVBDelta)
|
||||
}
|
||||
fallbackTx := transaction.New(fallbackScript, fallbackSysFee)
|
||||
fallbackTx.Signers = signers
|
||||
fallbackTx.ValidUntilBlock = mainTx.ValidUntilBlock
|
||||
fallbackTx.Attributes = []transaction.Attribute{
|
||||
{
|
||||
Type: transaction.NotaryAssistedT,
|
||||
Value: &transaction.NotaryAssisted{NKeys: 0},
|
||||
},
|
||||
{
|
||||
Type: transaction.NotValidBeforeT,
|
||||
Value: &transaction.NotValidBefore{Height: fallbackTx.ValidUntilBlock - fallbackValidFor + 1},
|
||||
},
|
||||
{
|
||||
Type: transaction.ConflictsT,
|
||||
Value: &transaction.Conflicts{Hash: mainTx.Hash()},
|
||||
},
|
||||
}
|
||||
|
||||
fallbackTx.Scripts = []transaction.Witness{
|
||||
{
|
||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...),
|
||||
VerificationScript: []byte{},
|
||||
},
|
||||
{
|
||||
InvocationScript: []byte{},
|
||||
VerificationScript: acc.GetVerificationScript(),
|
||||
},
|
||||
}
|
||||
fallbackTx.NetworkFee, err = c.CalculateNetworkFee(fallbackTx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add network fee: %w", err)
|
||||
}
|
||||
fallbackTx.NetworkFee += fallbackNetFee
|
||||
m, err := c.GetNetwork()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to sign fallback tx: %w", err)
|
||||
}
|
||||
if err = acc.SignTx(m, fallbackTx); err != nil {
|
||||
return nil, fmt.Errorf("failed to sign fallback tx: %w", err)
|
||||
}
|
||||
fallbackHash := fallbackTx.Hash()
|
||||
req := &payload.P2PNotaryRequest{
|
||||
MainTransaction: mainTx,
|
||||
FallbackTransaction: fallbackTx,
|
||||
}
|
||||
req.Witness = transaction.Witness{
|
||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, acc.SignHashable(m, req)...),
|
||||
VerificationScript: acc.GetVerificationScript(),
|
||||
}
|
||||
actualHash, err := c.SubmitP2PNotaryRequest(req)
|
||||
if err != nil {
|
||||
return req, fmt.Errorf("failed to submit notary request: %w", err)
|
||||
}
|
||||
if !actualHash.Equals(fallbackHash) {
|
||||
return req, fmt.Errorf("sent and actual fallback tx hashes mismatch:\n\tsent: %v\n\tactual: %v", fallbackHash.StringLE(), actualHash.StringLE())
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// CalculateNotaryFee calculates network fee for one dummy Notary witness and NotaryAssisted attribute with NKeys specified.
|
||||
// The result should be added to the transaction's net fee for successful verification.
|
||||
//
|
||||
// Deprecated: NeoGo calculatenetworkfee method handles notary fees as well since 0.99.3, so
|
||||
// this method is just no longer needed and will be removed in future versions.
|
||||
func (c *Client) CalculateNotaryFee(nKeys uint8) (int64, error) {
|
||||
baseExecFee, err := c.GetExecFeeFactor()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get BaseExecFeeFactor: %w", err)
|
||||
}
|
||||
feePerByte, err := c.GetFeePerByte()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get FeePerByte: %w", err)
|
||||
}
|
||||
feePerKey, err := c.GetNotaryServiceFeePerKey()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get NotaryServiceFeePerKey: %w", err)
|
||||
}
|
||||
return int64((nKeys+1))*feePerKey + // fee for NotaryAssisted attribute
|
||||
fee.Opcode(baseExecFee, // Notary node witness
|
||||
opcode.PUSHDATA1, opcode.RET, // invocation script
|
||||
opcode.PUSH0, opcode.SYSCALL, opcode.RET) + // System.Contract.CallNative
|
||||
nativeprices.NotaryVerificationPrice*baseExecFee + // Notary witness verification price
|
||||
feePerByte*int64(io.GetVarSize(make([]byte, 66))) + // invocation script per-byte fee
|
||||
feePerByte*int64(io.GetVarSize([]byte{})), // verification script per-byte fee
|
||||
nil
|
||||
}
|
||||
|
||||
// SubmitP2PNotaryRequest submits given P2PNotaryRequest payload to the RPC node.
|
||||
func (c *Client) SubmitP2PNotaryRequest(req *payload.P2PNotaryRequest) (util.Uint256, error) {
|
||||
var resp = new(result.RelayResult)
|
||||
|
@ -1103,113 +867,9 @@ func (c *Client) ValidateAddress(address string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// CalculateValidUntilBlock calculates ValidUntilBlock field for tx as
|
||||
// current blockchain height + number of validators. Number of validators
|
||||
// is the length of blockchain validators list got from GetNextBlockValidators()
|
||||
// method. Validators count is being cached and updated every 100 blocks.
|
||||
//
|
||||
// Deprecated: please use (*Actor).CalculateValidUntilBlock. This method will be
|
||||
// removed in future versions.
|
||||
func (c *Client) CalculateValidUntilBlock() (uint32, error) {
|
||||
var (
|
||||
result uint32
|
||||
validatorsCount uint32
|
||||
)
|
||||
blockCount, err := c.GetBlockCount()
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("can't get block count: %w", err)
|
||||
}
|
||||
|
||||
c.cacheLock.RLock()
|
||||
if c.cache.calculateValidUntilBlock.expiresAt > blockCount {
|
||||
validatorsCount = c.cache.calculateValidUntilBlock.validatorsCount
|
||||
c.cacheLock.RUnlock()
|
||||
} else {
|
||||
c.cacheLock.RUnlock()
|
||||
validators, err := c.GetNextBlockValidators()
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("can't get validators: %w", err)
|
||||
}
|
||||
validatorsCount = uint32(len(validators))
|
||||
c.cacheLock.Lock()
|
||||
c.cache.calculateValidUntilBlock = calculateValidUntilBlockCache{
|
||||
validatorsCount: validatorsCount,
|
||||
expiresAt: blockCount + cacheTimeout,
|
||||
}
|
||||
c.cacheLock.Unlock()
|
||||
}
|
||||
return blockCount + validatorsCount + 1, nil
|
||||
}
|
||||
|
||||
// AddNetworkFee adds network fee for each witness script and optional extra
|
||||
// network fee to transaction. `accs` is an array signer's accounts.
|
||||
//
|
||||
// Deprecated: please use CalculateNetworkFee or actor.Actor. This method will
|
||||
// be removed in future versions.
|
||||
func (c *Client) AddNetworkFee(tx *transaction.Transaction, extraFee int64, accs ...*wallet.Account) error {
|
||||
if len(tx.Signers) != len(accs) {
|
||||
return errors.New("number of signers must match number of scripts")
|
||||
}
|
||||
size := io.GetVarSize(tx)
|
||||
var ef int64
|
||||
for i, cosigner := range tx.Signers {
|
||||
if accs[i].Contract.Deployed {
|
||||
res, err := c.InvokeContractVerify(cosigner.Account, []smartcontract.Parameter{}, tx.Signers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to invoke verify: %w", err)
|
||||
}
|
||||
r, err := unwrap.Bool(res, err)
|
||||
if err != nil {
|
||||
return fmt.Errorf("signer #%d: %w", i, err)
|
||||
}
|
||||
if !r {
|
||||
return fmt.Errorf("signer #%d: `verify` returned `false`", i)
|
||||
}
|
||||
tx.NetworkFee += res.GasConsumed
|
||||
size += io.GetVarSize([]byte{}) * 2 // both scripts are empty
|
||||
continue
|
||||
}
|
||||
|
||||
if ef == 0 {
|
||||
var err error
|
||||
ef, err = c.GetExecFeeFactor()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get `ExecFeeFactor`: %w", err)
|
||||
}
|
||||
}
|
||||
netFee, sizeDelta := fee.Calculate(ef, accs[i].Contract.Script)
|
||||
tx.NetworkFee += netFee
|
||||
size += sizeDelta
|
||||
}
|
||||
fee, err := c.GetFeePerByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tx.NetworkFee += int64(size)*fee + extraFee
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetNetwork returns the network magic of the RPC node the client connected to. It
|
||||
// requires Init to be done first, otherwise an error is returned.
|
||||
//
|
||||
// Deprecated: please use GetVersion (it has the same data in the Protocol section)
|
||||
// or actor subpackage. This method will be removed in future versions.
|
||||
func (c *Client) GetNetwork() (netmode.Magic, error) {
|
||||
c.cacheLock.RLock()
|
||||
defer c.cacheLock.RUnlock()
|
||||
|
||||
if !c.cache.initDone {
|
||||
return 0, errNetworkNotInitialized
|
||||
}
|
||||
return c.cache.network, nil
|
||||
}
|
||||
|
||||
// StateRootInHeader returns true if the state root is contained in the block header.
|
||||
// You should initialize Client cache with Init() before calling StateRootInHeader.
|
||||
//
|
||||
// Deprecated: please use GetVersion (it has the same data in the Protocol section).
|
||||
// This method will be removed in future versions.
|
||||
func (c *Client) StateRootInHeader() (bool, error) {
|
||||
// stateRootInHeader returns true if the state root is contained in the block header.
|
||||
// Requires Init() before use.
|
||||
func (c *Client) stateRootInHeader() (bool, error) {
|
||||
c.cacheLock.RLock()
|
||||
defer c.cacheLock.RUnlock()
|
||||
|
||||
|
@ -1219,29 +879,6 @@ func (c *Client) StateRootInHeader() (bool, error) {
|
|||
return c.cache.stateRootInHeader, nil
|
||||
}
|
||||
|
||||
// GetNativeContractHash returns native contract hash by its name.
|
||||
//
|
||||
// Deprecated: please use native contract subpackages that have hashes directly
|
||||
// (gas, management, neo, notary, oracle, policy, rolemgmt) or
|
||||
// GetContractStateByAddressOrName method that will return hash along with other
|
||||
// data.
|
||||
func (c *Client) GetNativeContractHash(name string) (util.Uint160, error) {
|
||||
c.cacheLock.RLock()
|
||||
hash, ok := c.cache.nativeHashes[name]
|
||||
c.cacheLock.RUnlock()
|
||||
if ok {
|
||||
return hash, nil
|
||||
}
|
||||
cs, err := c.GetContractStateByAddressOrName(name)
|
||||
if err != nil {
|
||||
return util.Uint160{}, err
|
||||
}
|
||||
c.cacheLock.Lock()
|
||||
c.cache.nativeHashes[name] = cs.Hash
|
||||
c.cacheLock.Unlock()
|
||||
return cs.Hash, nil
|
||||
}
|
||||
|
||||
// TraverseIterator returns a set of iterator values (maxItemsCount at max) for
|
||||
// the specified iterator and session. If result contains no elements, then either
|
||||
// Iterator has no elements or session was expired and terminated by the server.
|
||||
|
|
|
@ -2,7 +2,6 @@ package rpcclient
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/elliptic"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
|
@ -18,7 +17,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
|
@ -403,136 +401,6 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
},
|
||||
},
|
||||
},
|
||||
"getFeePerByte": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetFeePerByte()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"1000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(1000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getExecFeeFactor": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetExecFeeFactor()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"1000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(1000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getStoragePrice": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetStoragePrice()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"100000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(100000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getOraclePrice": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetOraclePrice()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"10000000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(10000000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getNNSPrice": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetNNSPrice(util.Uint160{1, 2, 3})
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"1000000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(1000000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getGasPerBlock": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetGasPerBlock()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"500000000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(500000000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getCandidateRegisterPrice": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetCandidateRegisterPrice()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"100000000000"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(100000000000)
|
||||
},
|
||||
},
|
||||
},
|
||||
"getDesignatedByRole": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetDesignatedByRole(noderoles.P2PNotary, 10)
|
||||
},
|
||||
serverResponse: `{"id" : 1,"result" : {"stack" : [{"value" : [{"type":"ByteString","value":"Aw0WkQoDc8WqpG18xPMTEgfHO6gRTVtMN0Mw6zw06fzl"},{"type":"ByteString","value":"A+bmJ9wIaj96Ygr+uQQvQ0AaUrQmj2b3AGnztAOkU3/L"}],"type" : "Array"}],"exception" : null,"script" : "ERQSwB8ME2dldERlc2lnbmF0ZWRCeVJvbGUMFOKV45FUTBeK2U8D7E3N/3hTTs9JQWJ9W1I=","gasconsumed" : "2028150","state" : "HALT"}, "jsonrpc" : "2.0"}`,
|
||||
result: func(c *Client) any {
|
||||
pk1Bytes, _ := base64.StdEncoding.DecodeString("Aw0WkQoDc8WqpG18xPMTEgfHO6gRTVtMN0Mw6zw06fzl")
|
||||
pk1, err := keys.NewPublicKeyFromBytes(pk1Bytes, elliptic.P256())
|
||||
if err != nil {
|
||||
panic("invalid pub key #1 bytes")
|
||||
}
|
||||
pk2Bytes, _ := base64.StdEncoding.DecodeString("A+bmJ9wIaj96Ygr+uQQvQ0AaUrQmj2b3AGnztAOkU3/L")
|
||||
pk2, err := keys.NewPublicKeyFromBytes(pk2Bytes, elliptic.P256())
|
||||
if err != nil {
|
||||
panic("invalid pub key #2 bytes")
|
||||
}
|
||||
return keys.PublicKeys{pk1, pk2}
|
||||
},
|
||||
},
|
||||
},
|
||||
"getMaxNotValidBeforeDelta": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.GetMaxNotValidBeforeDelta()
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMD2dldE1heEJsb2NrU2l6ZQwUmmGkbuyXuJMG186B8VtGIJHQCTJBYn1bUg==","stack":[{"type":"Integer","value":"262144"}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return int64(262144)
|
||||
},
|
||||
},
|
||||
},
|
||||
"isBlocked": {
|
||||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (any, error) {
|
||||
return c.IsBlocked(util.Uint160{1, 2, 3})
|
||||
},
|
||||
serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMEmdldEJsb2NrZWRBY2NvdW50cwwUmmGkbuyXuJMG186B8VtGIJHQCTJBYn1bUg==","stack":[{"type":"Boolean","value":false}],"tx":null}}`,
|
||||
result: func(c *Client) any {
|
||||
return false
|
||||
},
|
||||
},
|
||||
},
|
||||
"getnep11balances": {
|
||||
{
|
||||
name: "positive",
|
||||
|
@ -2138,92 +2006,6 @@ func wrapInitResponse(r *params.In, resp string) string {
|
|||
return response
|
||||
}
|
||||
|
||||
func TestCalculateValidUntilBlock(t *testing.T) {
|
||||
var (
|
||||
getBlockCountCalled int
|
||||
getValidatorsCalled int
|
||||
)
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
r := params.NewRequest()
|
||||
err := r.DecodeData(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot decode request body: %s", req.Body)
|
||||
}
|
||||
var response string
|
||||
switch r.In.Method {
|
||||
case "getblockcount":
|
||||
getBlockCountCalled++
|
||||
response = `{"jsonrpc":"2.0","id":1,"result":50}`
|
||||
case "getnextblockvalidators":
|
||||
getValidatorsCalled++
|
||||
response = `{"id":1,"jsonrpc":"2.0","result":[{"publickey":"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2","votes":"0","active":true},{"publickey":"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e","votes":"0","active":true},{"publickey":"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699","votes":"0","active":true},{"publickey":"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62","votes":"0","active":true}]}`
|
||||
}
|
||||
requestHandler(t, r.In, w, response)
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
endpoint := srv.URL
|
||||
opts := Options{}
|
||||
c, err := New(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.getNextRequestID = getTestRequestID
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
validUntilBlock, err := c.CalculateValidUntilBlock()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, uint32(55), validUntilBlock)
|
||||
assert.Equal(t, 1, getBlockCountCalled)
|
||||
assert.Equal(t, 1, getValidatorsCalled)
|
||||
|
||||
// check, whether caching is working
|
||||
validUntilBlock, err = c.CalculateValidUntilBlock()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, uint32(55), validUntilBlock)
|
||||
assert.Equal(t, 2, getBlockCountCalled)
|
||||
assert.Equal(t, 1, getValidatorsCalled)
|
||||
}
|
||||
|
||||
func TestGetNetwork(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
r := params.NewRequest()
|
||||
err := r.DecodeData(req.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot decode request body: %s", req.Body)
|
||||
}
|
||||
// request handler already have `getversion` response wrapper
|
||||
requestHandler(t, r.In, w, "")
|
||||
}))
|
||||
t.Cleanup(srv.Close)
|
||||
endpoint := srv.URL
|
||||
opts := Options{}
|
||||
|
||||
t.Run("bad", func(t *testing.T) {
|
||||
c, err := New(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.getNextRequestID = getTestRequestID
|
||||
// network was not initialised
|
||||
_, err = c.GetNetwork()
|
||||
require.ErrorIs(t, err, errNetworkNotInitialized)
|
||||
require.Equal(t, false, c.cache.initDone)
|
||||
})
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
c, err := New(context.TODO(), endpoint, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c.getNextRequestID = getTestRequestID
|
||||
require.NoError(t, c.Init())
|
||||
m, err := c.GetNetwork()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, netmode.UnitTestNet, m)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUninitedClient(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
r := params.NewRequest()
|
||||
|
@ -2250,10 +2032,6 @@ func TestUninitedClient(t *testing.T) {
|
|||
require.Error(t, err)
|
||||
_, err = c.GetRawTransactionVerbose(util.Uint256{})
|
||||
require.Error(t, err)
|
||||
_, err = c.IsBlocked(util.Uint160{})
|
||||
require.Error(t, err)
|
||||
_, err = c.GetFeePerByte()
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func newTestNEF(script []byte) nef.File {
|
||||
|
|
|
@ -566,7 +566,7 @@ readloop:
|
|||
ntf := Notification{Type: event}
|
||||
switch event {
|
||||
case neorpc.BlockEventID:
|
||||
sr, err := c.StateRootInHeader()
|
||||
sr, err := c.stateRootInHeader()
|
||||
if err != nil {
|
||||
// Client is not initialized.
|
||||
connCloseErr = fmt.Errorf("failed to fetch StateRootInHeader: %w", err)
|
||||
|
|
|
@ -31,7 +31,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc"
|
||||
|
@ -544,7 +543,7 @@ func TestClientNotary(t *testing.T) {
|
|||
require.Error(t, err) // Can't be withdrawn until 1111.
|
||||
}
|
||||
|
||||
func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
||||
func TestCalculateNetworkFee_Base(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
@ -555,27 +554,8 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
getAccounts := func(t *testing.T, n int) []*wallet.Account {
|
||||
accs := make([]*wallet.Account, n)
|
||||
var err error
|
||||
for i := range accs {
|
||||
accs[i], err = wallet.NewAccount()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
return accs
|
||||
}
|
||||
|
||||
feePerByte := chain.FeePerByte()
|
||||
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
tx := transaction.New([]byte{byte(opcode.PUSH1)}, 0)
|
||||
accs := getAccounts(t, 2)
|
||||
tx.Signers = []transaction.Signer{{
|
||||
Account: accs[0].PrivateKey().GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
}}
|
||||
require.Error(t, c.AddNetworkFee(tx, extraFee, accs[0], accs[1])) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
})
|
||||
t.Run("Simple", func(t *testing.T) {
|
||||
acc0 := wallet.NewAccountFromPrivateKey(testchain.PrivateKeyByID(0))
|
||||
check := func(t *testing.T, extraFee int64) {
|
||||
|
@ -593,16 +573,12 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
}
|
||||
actualCalculatedNetFee, err := c.CalculateNetworkFee(tx)
|
||||
require.NoError(t, err)
|
||||
|
||||
tx.Scripts = nil
|
||||
require.NoError(t, c.AddNetworkFee(tx, extraFee, acc0)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
actual := tx.NetworkFee
|
||||
tx.NetworkFee = actualCalculatedNetFee + extraFee
|
||||
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), tx))
|
||||
cFee, _ := fee.Calculate(chain.GetBaseExecFee(), acc0.Contract.Script)
|
||||
expected := int64(io.GetVarSize(tx))*feePerByte + cFee + extraFee
|
||||
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expected, actualCalculatedNetFee+extraFee)
|
||||
err = chain.VerifyTx(tx)
|
||||
if extraFee < 0 {
|
||||
|
@ -658,12 +634,9 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
}
|
||||
actualCalculatedNetFee, err := c.CalculateNetworkFee(tx)
|
||||
require.NoError(t, err)
|
||||
tx.NetworkFee = actualCalculatedNetFee + extraFee
|
||||
|
||||
tx.Scripts = nil
|
||||
|
||||
require.NoError(t, c.AddNetworkFee(tx, extraFee, acc0, acc1)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
actual := tx.NetworkFee
|
||||
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), tx))
|
||||
tx.Scripts = append(tx.Scripts, transaction.Witness{
|
||||
InvocationScript: testchain.Sign(tx),
|
||||
|
@ -673,7 +646,6 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
cFeeM, _ := fee.Calculate(chain.GetBaseExecFee(), acc1.Contract.Script)
|
||||
expected := int64(io.GetVarSize(tx))*feePerByte + cFee + cFeeM + extraFee
|
||||
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expected, actualCalculatedNetFee+extraFee)
|
||||
err = chain.VerifyTx(tx)
|
||||
if extraFee < 0 {
|
||||
|
@ -732,12 +704,11 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
}
|
||||
actual, err := c.CalculateNetworkFee(tx)
|
||||
require.NoError(t, err)
|
||||
tx.Scripts = nil
|
||||
tx.NetworkFee = actual + extraFee
|
||||
|
||||
require.NoError(t, c.AddNetworkFee(tx, extraFee, acc0, acc1)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
tx.Scripts = nil
|
||||
require.NoError(t, acc0.SignTx(testchain.Network(), tx))
|
||||
tx.Scripts = append(tx.Scripts, transaction.Witness{})
|
||||
require.Equal(t, tx.NetworkFee, actual+extraFee)
|
||||
err = chain.VerifyTx(tx)
|
||||
if extraFee < 0 {
|
||||
require.Error(t, err)
|
||||
|
@ -759,37 +730,6 @@ func TestAddNetworkFeeCalculateNetworkFee(t *testing.T) {
|
|||
check(t, -1)
|
||||
})
|
||||
})
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
tx := newTx(t)
|
||||
acc0, err := wallet.NewAccount()
|
||||
require.NoError(t, err)
|
||||
tx.Signers = []transaction.Signer{
|
||||
{
|
||||
Account: acc0.PrivateKey().GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
{
|
||||
Account: h,
|
||||
Scopes: transaction.Global,
|
||||
},
|
||||
}
|
||||
require.Error(t, c.AddNetworkFee(tx, 10, acc0, acc1)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
})
|
||||
t.Run("InvalidContract", func(t *testing.T) {
|
||||
tx := newTx(t)
|
||||
acc0 := wallet.NewAccountFromPrivateKey(priv)
|
||||
tx.Signers = []transaction.Signer{
|
||||
{
|
||||
Account: acc0.PrivateKey().GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
{
|
||||
Account: util.Uint160{},
|
||||
Scopes: transaction.Global,
|
||||
},
|
||||
}
|
||||
require.Error(t, c.AddNetworkFee(tx, 10, acc0, acc1)) //nolint:staticcheck // SA1019: c.AddNetworkFee is deprecated
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -863,160 +803,6 @@ func TestCalculateNetworkFee(t *testing.T) {
|
|||
})
|
||||
})
|
||||
}
|
||||
func TestSignAndPushInvocationTx(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
priv0 := testchain.PrivateKeyByID(0)
|
||||
acc0 := wallet.NewAccountFromPrivateKey(priv0)
|
||||
|
||||
verifyWithoutParamsCtr, err := util.Uint160DecodeStringLE(verifyContractHash)
|
||||
require.NoError(t, err)
|
||||
acc1 := &wallet.Account{
|
||||
Address: address.Uint160ToString(verifyWithoutParamsCtr),
|
||||
Contract: &wallet.Contract{
|
||||
Parameters: []wallet.ContractParam{},
|
||||
Deployed: true,
|
||||
},
|
||||
Default: false,
|
||||
}
|
||||
|
||||
verifyWithParamsCtr, err := util.Uint160DecodeStringLE(verifyWithArgsContractHash)
|
||||
require.NoError(t, err)
|
||||
acc2 := &wallet.Account{
|
||||
Address: address.Uint160ToString(verifyWithParamsCtr),
|
||||
Contract: &wallet.Contract{
|
||||
Parameters: []wallet.ContractParam{
|
||||
{Name: "argString", Type: smartcontract.StringType},
|
||||
{Name: "argInt", Type: smartcontract.IntegerType},
|
||||
{Name: "argBool", Type: smartcontract.BoolType},
|
||||
},
|
||||
Deployed: true,
|
||||
},
|
||||
Default: false,
|
||||
}
|
||||
|
||||
priv3 := testchain.PrivateKeyByID(3)
|
||||
acc3 := wallet.NewAccountFromPrivateKey(priv3)
|
||||
|
||||
check := func(t *testing.T, h util.Uint256) {
|
||||
mp := chain.GetMemPool()
|
||||
tx, ok := mp.TryGetValue(h)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, h, tx.Hash())
|
||||
require.EqualValues(t, 30, tx.SystemFee)
|
||||
}
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
t.Run("signer0: sig", func(t *testing.T) {
|
||||
h, err := c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
check(t, h)
|
||||
})
|
||||
t.Run("signer0: sig; signer1: sig", func(t *testing.T) {
|
||||
h, err := c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv3.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc3,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
check(t, h)
|
||||
})
|
||||
t.Run("signer0: sig; signer1: contract-based paramless", func(t *testing.T) {
|
||||
h, err := c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: verifyWithoutParamsCtr,
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc1,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
check(t, h)
|
||||
})
|
||||
})
|
||||
t.Run("error", func(t *testing.T) {
|
||||
t.Run("signer0: sig; signer1: contract-based with params", func(t *testing.T) {
|
||||
_, err := c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: verifyWithParamsCtr,
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc2,
|
||||
},
|
||||
})
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("signer0: sig; signer1: locked sig", func(t *testing.T) {
|
||||
pk, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
acc4 := &wallet.Account{
|
||||
Address: address.Uint160ToString(pk.GetScriptHash()),
|
||||
Contract: &wallet.Contract{
|
||||
Script: pk.PublicKey().GetVerificationScript(),
|
||||
Parameters: []wallet.ContractParam{{Name: "parameter0", Type: smartcontract.SignatureType}},
|
||||
},
|
||||
}
|
||||
_, err = c.SignAndPushInvocationTx([]byte{byte(opcode.PUSH1)}, acc0, 30, 0, []rpcclient.SignerAccount{ //nolint:staticcheck // SA1019: c.SignAndPushInvocationTx is deprecated
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: priv0.GetScriptHash(),
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc0,
|
||||
},
|
||||
{
|
||||
Signer: transaction.Signer{
|
||||
Account: util.Uint160{1, 2, 3},
|
||||
Scopes: transaction.CalledByEntry,
|
||||
},
|
||||
Account: acc4,
|
||||
},
|
||||
})
|
||||
require.Error(t, err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestNotaryActor(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChainAndServices(t, false, true, false)
|
||||
|
@ -1049,92 +835,6 @@ func TestNotaryActor(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestSignAndPushP2PNotaryRequest(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChainAndServices(t, false, true, false)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
acc, err := wallet.NewAccount()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("client wasn't initialized", func(t *testing.T) {
|
||||
_, err := c.SignAndPushP2PNotaryRequest(transaction.New([]byte{byte(opcode.RET)}, 123), []byte{byte(opcode.RET)}, -1, 0, 100, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
||||
require.NotNil(t, err)
|
||||
})
|
||||
|
||||
require.NoError(t, c.Init())
|
||||
t.Run("bad fallback script", func(t *testing.T) {
|
||||
_, err := c.SignAndPushP2PNotaryRequest(nil, []byte{byte(opcode.ASSERT)}, -1, 0, 0, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
||||
require.NotNil(t, err)
|
||||
})
|
||||
|
||||
t.Run("too large fallbackValidFor", func(t *testing.T) {
|
||||
_, err := c.SignAndPushP2PNotaryRequest(nil, []byte{byte(opcode.RET)}, -1, 0, 141, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
||||
require.NotNil(t, err)
|
||||
})
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
sender := testchain.PrivateKeyByID(0) // owner of the deposit in testchain
|
||||
acc := wallet.NewAccountFromPrivateKey(sender)
|
||||
expected := transaction.Transaction{
|
||||
Attributes: []transaction.Attribute{{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 1}}},
|
||||
Script: []byte{byte(opcode.RET)},
|
||||
ValidUntilBlock: chain.BlockHeight() + 5,
|
||||
Signers: []transaction.Signer{{Account: util.Uint160{1, 5, 9}}},
|
||||
Scripts: []transaction.Witness{{
|
||||
InvocationScript: []byte{1, 4, 7},
|
||||
VerificationScript: []byte{3, 6, 9},
|
||||
}},
|
||||
}
|
||||
mainTx := expected
|
||||
_ = expected.Hash()
|
||||
req, err := c.SignAndPushP2PNotaryRequest(&mainTx, []byte{byte(opcode.RET)}, -1, 0, 6, acc) //nolint:staticcheck // SA1019: c.SignAndPushP2PNotaryRequest is deprecated
|
||||
require.NoError(t, err)
|
||||
|
||||
// check that request was correctly completed
|
||||
require.Equal(t, expected, *req.MainTransaction) // main tx should be the same
|
||||
require.ElementsMatch(t, []transaction.Attribute{
|
||||
{
|
||||
Type: transaction.NotaryAssistedT,
|
||||
Value: &transaction.NotaryAssisted{NKeys: 0},
|
||||
},
|
||||
{
|
||||
Type: transaction.NotValidBeforeT,
|
||||
Value: &transaction.NotValidBefore{Height: chain.BlockHeight()},
|
||||
},
|
||||
{
|
||||
Type: transaction.ConflictsT,
|
||||
Value: &transaction.Conflicts{Hash: mainTx.Hash()},
|
||||
},
|
||||
}, req.FallbackTransaction.Attributes)
|
||||
require.Equal(t, []transaction.Signer{
|
||||
{Account: chain.GetNotaryContractScriptHash()},
|
||||
{Account: acc.PrivateKey().GetScriptHash()},
|
||||
}, req.FallbackTransaction.Signers)
|
||||
|
||||
// it shouldn't be an error to add completed fallback to the chain
|
||||
w, err := wallet.NewWalletFromFile(notaryPath)
|
||||
require.NoError(t, err)
|
||||
ntr := w.Accounts[0]
|
||||
err = ntr.Decrypt(notaryPass, w.Scrypt)
|
||||
require.NoError(t, err)
|
||||
req.FallbackTransaction.Scripts[0] = transaction.Witness{
|
||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, ntr.PrivateKey().SignHashable(uint32(testchain.Network()), req.FallbackTransaction)...),
|
||||
VerificationScript: []byte{},
|
||||
}
|
||||
b := testchain.NewBlock(t, chain, 1, 0, req.FallbackTransaction)
|
||||
require.NoError(t, chain.AddBlock(b))
|
||||
appLogs, err := chain.GetAppExecResults(req.FallbackTransaction.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(appLogs))
|
||||
appLog := appLogs[0]
|
||||
require.Equal(t, vmstate.Halt, appLog.VMState)
|
||||
require.Equal(t, appLog.GasConsumed, req.FallbackTransaction.SystemFee)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetRawNotaryPoolAndTransaction(t *testing.T) {
|
||||
var (
|
||||
mainHash1, fallbackHash1, mainHash2, fallbackHash2 util.Uint256
|
||||
|
@ -1266,20 +966,6 @@ func TestGetRawNotaryPoolAndTransaction(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestCalculateNotaryFee(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("client not initialized", func(t *testing.T) {
|
||||
_, err := c.CalculateNotaryFee(0) //nolint:staticcheck // SA1019: c.CalculateNotaryFee is deprecated
|
||||
require.NoError(t, err) // Do not require client initialisation for this.
|
||||
})
|
||||
}
|
||||
|
||||
func TestPing(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
@ -1294,35 +980,6 @@ func TestPing(t *testing.T) {
|
|||
require.Error(t, c.Ping())
|
||||
}
|
||||
|
||||
func TestCreateTxFromScript(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
priv := testchain.PrivateKey(0)
|
||||
acc := wallet.NewAccountFromPrivateKey(priv)
|
||||
t.Run("NoSystemFee", func(t *testing.T) {
|
||||
tx, err := c.CreateTxFromScript([]byte{byte(opcode.PUSH1)}, acc, -1, 10, nil) //nolint:staticcheck // SA1019: c.CreateTxFromScript is deprecated
|
||||
require.NoError(t, err)
|
||||
require.True(t, tx.ValidUntilBlock > chain.BlockHeight())
|
||||
require.EqualValues(t, 30, tx.SystemFee) // PUSH1
|
||||
require.True(t, len(tx.Signers) == 1)
|
||||
require.Equal(t, acc.PrivateKey().GetScriptHash(), tx.Signers[0].Account)
|
||||
})
|
||||
t.Run("ProvideSystemFee", func(t *testing.T) {
|
||||
tx, err := c.CreateTxFromScript([]byte{byte(opcode.PUSH1)}, acc, 123, 10, nil) //nolint:staticcheck // SA1019: c.CreateTxFromScript is deprecated
|
||||
require.NoError(t, err)
|
||||
require.True(t, tx.ValidUntilBlock > chain.BlockHeight())
|
||||
require.EqualValues(t, 123, tx.SystemFee)
|
||||
require.True(t, len(tx.Signers) == 1)
|
||||
require.Equal(t, acc.PrivateKey().GetScriptHash(), tx.Signers[0].Account)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateNEP17TransferTx(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
@ -1885,21 +1542,6 @@ func TestClient_IteratorSessions(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestClient_GetNotaryServiceFeePerKey(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
var defaultNotaryServiceFeePerKey int64 = 1000_0000
|
||||
actual, err := c.GetNotaryServiceFeePerKey() //nolint:staticcheck // SA1019: c.GetNotaryServiceFeePerKey is deprecated
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, defaultNotaryServiceFeePerKey, actual)
|
||||
}
|
||||
|
||||
func TestClient_States(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
|
@ -1973,63 +1615,6 @@ func TestClientOracle(t *testing.T) {
|
|||
require.Equal(t, newPrice, actual)
|
||||
}
|
||||
|
||||
func TestClient_InvokeAndPackIteratorResults(t *testing.T) {
|
||||
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
||||
defer chain.Close()
|
||||
defer rpcSrv.Shutdown()
|
||||
|
||||
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, c.Init())
|
||||
|
||||
// storageItemsCount is the amount of storage items stored in Storage contract, it's hard-coded in the contract code.
|
||||
const storageItemsCount = 255
|
||||
expected := make([][]byte, storageItemsCount)
|
||||
for i := 0; i < storageItemsCount; i++ {
|
||||
expected[i] = stackitem.NewBigInteger(big.NewInt(int64(i))).Bytes()
|
||||
}
|
||||
sort.Slice(expected, func(i, j int) bool {
|
||||
if len(expected[i]) != len(expected[j]) {
|
||||
return len(expected[i]) < len(expected[j])
|
||||
}
|
||||
return bytes.Compare(expected[i], expected[j]) < 0
|
||||
})
|
||||
storageHash, err := util.Uint160DecodeStringLE(storageContractHash)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("default max items constraint", func(t *testing.T) {
|
||||
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil) //nolint:staticcheck // SA1019: c.InvokeAndPackIteratorResults is deprecated
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, stackitem.ArrayT, res.Stack[0].Type())
|
||||
arr, ok := res.Stack[0].Value().([]stackitem.Item)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, config.DefaultMaxIteratorResultItems, len(arr))
|
||||
|
||||
for i := range arr {
|
||||
require.Equal(t, stackitem.ByteArrayT, arr[i].Type())
|
||||
require.Equal(t, expected[i], arr[i].Value().([]byte))
|
||||
}
|
||||
})
|
||||
t.Run("custom max items constraint", func(t *testing.T) {
|
||||
max := 123
|
||||
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil, max) //nolint:staticcheck // SA1019: c.InvokeAndPackIteratorResults is deprecated
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Equal(t, 1, len(res.Stack))
|
||||
require.Equal(t, stackitem.ArrayT, res.Stack[0].Type())
|
||||
arr, ok := res.Stack[0].Value().([]stackitem.Item)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, max, len(arr))
|
||||
|
||||
for i := range arr {
|
||||
require.Equal(t, stackitem.ByteArrayT, arr[i].Type())
|
||||
require.Equal(t, expected[i], arr[i].Value().([]byte))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_Iterator_SessionConfigVariations(t *testing.T) {
|
||||
var expected [][]byte
|
||||
storageHash, err := util.Uint160DecodeStringLE(storageContractHash)
|
||||
|
|
Loading…
Reference in a new issue