Merge pull request #1139 from nspcc-dev/fix-deployment-sysfee-and-invokes

Fix deployment sysfee and invokes
This commit is contained in:
Roman Khimov 2020-07-03 10:11:23 +03:00 committed by GitHub
commit 6cd166fb7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 50 deletions

View file

@ -399,8 +399,10 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
if !args.Present() { if !args.Present() {
return cli.NewExitError(errNoScriptHash, 1) return cli.NewExitError(errNoScriptHash, 1)
} }
script := args[0] script, err := util.Uint160DecodeStringLE(args[0])
if err != nil {
return cli.NewExitError(fmt.Errorf("incorrect script hash: %v", err), 1)
}
if len(args) <= 1 { if len(args) <= 1 {
return cli.NewExitError(errNoMethod, 1) return cli.NewExitError(errNoMethod, 1)
} }
@ -510,8 +512,7 @@ func testInvokeScript(ctx *cli.Context) error {
return err return err
} }
scriptHex := hex.EncodeToString(nefFile.Script) resp, err := c.InvokeScript(nefFile.Script, cosigners)
resp, err := c.InvokeScript(scriptHex, cosigners)
if err != nil { if err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -654,12 +655,17 @@ func contractDeploy(ctx *cli.Context) error {
return err return err
} }
txScript, sysfee, err := request.CreateDeploymentScript(nefFile.Script, m) txScript, err := request.CreateDeploymentScript(nefFile.Script, m)
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("failed to create deployment script: %v", err), 1) return cli.NewExitError(fmt.Errorf("failed to create deployment script: %v", err), 1)
} }
// It doesn't require any cosigners.
invRes, err := c.InvokeScript(txScript, nil)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to test-invoke deployment script: %v", err), 1)
}
txHash, err := c.SignAndPushInvocationTx(txScript, acc, sysfee, gas) txHash, err := c.SignAndPushInvocationTx(txScript, acc, invRes.GasConsumed, gas)
if err != nil { if err != nil {
return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %v", err), 1) return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %v", err), 1)
} }

View file

@ -1,7 +1,6 @@
package client package client
import ( import (
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
@ -25,7 +24,7 @@ var (
// NEP5Decimals invokes `decimals` NEP5 method on a specified contract. // NEP5Decimals invokes `decimals` NEP5 method on a specified contract.
func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) { func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) {
result, err := c.InvokeFunction(tokenHash.StringLE(), "decimals", []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(tokenHash, "decimals", []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return 0, err return 0, err
} else if result.State != "HALT" || len(result.Stack) == 0 { } else if result.State != "HALT" || len(result.Stack) == 0 {
@ -37,7 +36,7 @@ func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) {
// NEP5Name invokes `name` NEP5 method on a specified contract. // NEP5Name invokes `name` NEP5 method on a specified contract.
func (c *Client) NEP5Name(tokenHash util.Uint160) (string, error) { func (c *Client) NEP5Name(tokenHash util.Uint160) (string, error) {
result, err := c.InvokeFunction(tokenHash.StringLE(), "name", []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(tokenHash, "name", []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return "", err return "", err
} else if result.State != "HALT" || len(result.Stack) == 0 { } else if result.State != "HALT" || len(result.Stack) == 0 {
@ -49,7 +48,7 @@ func (c *Client) NEP5Name(tokenHash util.Uint160) (string, error) {
// NEP5Symbol invokes `symbol` NEP5 method on a specified contract. // NEP5Symbol invokes `symbol` NEP5 method on a specified contract.
func (c *Client) NEP5Symbol(tokenHash util.Uint160) (string, error) { func (c *Client) NEP5Symbol(tokenHash util.Uint160) (string, error) {
result, err := c.InvokeFunction(tokenHash.StringLE(), "symbol", []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(tokenHash, "symbol", []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return "", err return "", err
} else if result.State != "HALT" || len(result.Stack) == 0 { } else if result.State != "HALT" || len(result.Stack) == 0 {
@ -61,7 +60,7 @@ func (c *Client) NEP5Symbol(tokenHash util.Uint160) (string, error) {
// NEP5TotalSupply invokes `totalSupply` NEP5 method on a specified contract. // NEP5TotalSupply invokes `totalSupply` NEP5 method on a specified contract.
func (c *Client) NEP5TotalSupply(tokenHash util.Uint160) (int64, error) { func (c *Client) NEP5TotalSupply(tokenHash util.Uint160) (int64, error) {
result, err := c.InvokeFunction(tokenHash.StringLE(), "totalSupply", []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(tokenHash, "totalSupply", []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return 0, err return 0, err
} else if result.State != "HALT" || len(result.Stack) == 0 { } else if result.State != "HALT" || len(result.Stack) == 0 {
@ -73,7 +72,7 @@ func (c *Client) NEP5TotalSupply(tokenHash util.Uint160) (int64, error) {
// NEP5BalanceOf invokes `balanceOf` NEP5 method on a specified contract. // NEP5BalanceOf invokes `balanceOf` NEP5 method on a specified contract.
func (c *Client) NEP5BalanceOf(tokenHash util.Uint160) (int64, error) { func (c *Client) NEP5BalanceOf(tokenHash util.Uint160) (int64, error) {
result, err := c.InvokeFunction(tokenHash.StringLE(), "balanceOf", []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(tokenHash, "balanceOf", []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return 0, err return 0, err
} else if result.State != "HALT" || len(result.Stack) == 0 { } else if result.State != "HALT" || len(result.Stack) == 0 {
@ -127,7 +126,7 @@ func (c *Client) CreateNEP5TransferTx(acc *wallet.Account, to util.Uint160, toke
}, },
} }
result, err := c.InvokeScript(hex.EncodeToString(script), []transaction.Cosigner{ result, err := c.InvokeScript(script, []transaction.Cosigner{
{ {
Account: from, Account: from,
Scopes: transaction.Global, Scopes: transaction.Global,

View file

@ -29,7 +29,7 @@ func (c *Client) GetFeePerByte() (int64, error) {
} }
func (c *Client) invokeNativePolicyMethod(operation string) (int64, error) { func (c *Client) invokeNativePolicyMethod(operation string) (int64, error) {
result, err := c.InvokeFunction(PolicyContractHash.StringLE(), operation, []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(PolicyContractHash, operation, []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return 0, err return 0, err
} else if result.State != "HALT" || len(result.Stack) == 0 { } else if result.State != "HALT" || len(result.Stack) == 0 {
@ -41,7 +41,7 @@ func (c *Client) invokeNativePolicyMethod(operation string) (int64, error) {
// GetBlockedAccounts invokes `getBlockedAccounts` method on a native Policy contract. // GetBlockedAccounts invokes `getBlockedAccounts` method on a native Policy contract.
func (c *Client) GetBlockedAccounts() (native.BlockedAccounts, error) { func (c *Client) GetBlockedAccounts() (native.BlockedAccounts, error) {
result, err := c.InvokeFunction(PolicyContractHash.StringLE(), "getBlockedAccounts", []smartcontract.Parameter{}, nil) result, err := c.InvokeFunction(PolicyContractHash, "getBlockedAccounts", []smartcontract.Parameter{}, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} else if result.State != "HALT" || len(result.Stack) == 0 { } else if result.State != "HALT" || len(result.Stack) == 0 {

View file

@ -349,36 +349,38 @@ func (c *Client) GetVersion() (*result.Version, error) {
// InvokeScript returns the result of the given script after running it true the VM. // InvokeScript returns the result of the given script after running it true the VM.
// NOTE: This is a test invoke and will not affect the blockchain. // NOTE: This is a test invoke and will not affect the blockchain.
func (c *Client) InvokeScript(script string, cosigners []transaction.Cosigner) (*result.Invoke, error) { func (c *Client) InvokeScript(script []byte, cosigners []transaction.Cosigner) (*result.Invoke, error) {
var ( var p = request.NewRawParams(hex.EncodeToString(script))
params request.RawParams return c.invokeSomething("invokescript", p, cosigners)
resp = &result.Invoke{}
)
if cosigners != nil {
params = request.NewRawParams(script, cosigners)
} else {
params = request.NewRawParams(script)
}
if err := c.performRequest("invokescript", params, resp); err != nil {
return nil, err
}
return resp, nil
} }
// InvokeFunction returns the results after calling the smart contract scripthash // InvokeFunction returns the results after calling the smart contract scripthash
// with the given operation and parameters. // with the given operation and parameters.
// NOTE: this is test invoke and will not affect the blockchain. // NOTE: this is test invoke and will not affect the blockchain.
func (c *Client) InvokeFunction(script, operation string, params []smartcontract.Parameter, cosigners []transaction.Cosigner) (*result.Invoke, error) { func (c *Client) InvokeFunction(contract util.Uint160, operation string, params []smartcontract.Parameter, cosigners []transaction.Cosigner) (*result.Invoke, error) {
var ( var p = request.NewRawParams(contract.StringLE(), operation, params)
p request.RawParams return c.invokeSomething("invokefunction", p, cosigners)
resp = &result.Invoke{} }
)
// invokeSomething is an inner wrapper for Invoke* functions
func (c *Client) invokeSomething(method string, p request.RawParams, cosigners []transaction.Cosigner) (*result.Invoke, error) {
var resp = new(result.Invoke)
if cosigners != nil { if cosigners != nil {
p = request.NewRawParams(script, operation, params, cosigners) p.Values = append(p.Values, cosigners)
} else {
p = request.NewRawParams(script, operation, params)
} }
if err := c.performRequest("invokefunction", p, resp); err != nil { if err := c.performRequest(method, p, resp); err != nil {
// Retry with old-fashioned hashes (see neo/neo-modules#260).
if cosigners != nil {
var hashes = make([]util.Uint160, len(cosigners))
for i := range cosigners {
hashes[i] = cosigners[i].Account
}
p.Values[len(p.Values)-1] = hashes
err = c.performRequest(method, p, resp)
if err == nil {
return resp, nil
}
}
return nil, err return nil, err
} }
return resp, nil return resp, nil

View file

@ -616,7 +616,11 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
if err != nil { if err != nil {
panic(err) panic(err)
} }
return c.InvokeFunction("af7c7328eee5a275a3bcaee2bf0cf662b5e739be", "balanceOf", []smartcontract.Parameter{ contr, err := util.Uint160DecodeStringLE("af7c7328eee5a275a3bcaee2bf0cf662b5e739be")
if err != nil {
panic(err)
}
return c.InvokeFunction(contr, "balanceOf", []smartcontract.Parameter{
{ {
Type: smartcontract.Hash160Type, Type: smartcontract.Hash160Type,
Value: hash, Value: hash,
@ -649,7 +653,11 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
{ {
name: "positive", name: "positive",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.InvokeScript("00046e616d656724058e5e1b6008847cd662728549088a9ee82191", []transaction.Cosigner{{ script, err := hex.DecodeString("00046e616d656724058e5e1b6008847cd662728549088a9ee82191")
if err != nil {
panic(err)
}
return c.InvokeScript(script, []transaction.Cosigner{{
Account: util.Uint160{1, 2, 3}, Account: util.Uint160{1, 2, 3},
}}) }})
}, },
@ -952,13 +960,13 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
{ {
name: "invokefunction_invalid_params_error", name: "invokefunction_invalid_params_error",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.InvokeFunction("", "", []smartcontract.Parameter{}, nil) return c.InvokeFunction(util.Uint160{}, "", []smartcontract.Parameter{}, nil)
}, },
}, },
{ {
name: "invokescript_invalid_params_error", name: "invokescript_invalid_params_error",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.InvokeScript("", nil) return c.InvokeScript([]byte{}, nil)
}, },
}, },
{ {
@ -1134,13 +1142,13 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
{ {
name: "invokefunction_unmarshalling_error", name: "invokefunction_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.InvokeFunction("", "", []smartcontract.Parameter{}, nil) return c.InvokeFunction(util.Uint160{}, "", []smartcontract.Parameter{}, nil)
}, },
}, },
{ {
name: "invokescript_unmarshalling_error", name: "invokescript_unmarshalling_error",
invoke: func(c *Client) (interface{}, error) { invoke: func(c *Client) (interface{}, error) {
return c.InvokeScript("", nil) return c.InvokeScript([]byte{}, nil)
}, },
}, },
{ {

View file

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
@ -16,18 +15,17 @@ import (
) )
// CreateDeploymentScript returns a script that deploys given smart contract // CreateDeploymentScript returns a script that deploys given smart contract
// with its metadata and system fee require for this. // with its metadata.
func CreateDeploymentScript(avm []byte, manif *manifest.Manifest) ([]byte, int64, error) { func CreateDeploymentScript(avm []byte, manif *manifest.Manifest) ([]byte, error) {
script := io.NewBufBinWriter() script := io.NewBufBinWriter()
rawManifest, err := manif.MarshalJSON() rawManifest, err := manif.MarshalJSON()
if err != nil { if err != nil {
return nil, 0, err return nil, err
} }
emit.Bytes(script.BinWriter, rawManifest) emit.Bytes(script.BinWriter, rawManifest)
emit.Bytes(script.BinWriter, avm) emit.Bytes(script.BinWriter, avm)
emit.Syscall(script.BinWriter, "System.Contract.Create") emit.Syscall(script.BinWriter, "System.Contract.Create")
sysfee := int64(core.StoragePrice * (len(avm) + len(rawManifest))) return script.Bytes(), nil
return script.Bytes(), sysfee, nil
} }
// expandArrayIntoScript pushes all FuncParam parameters from the given array // expandArrayIntoScript pushes all FuncParam parameters from the given array